[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Dynamic Object Instantiation

Troy Denkinger

3/1/2006 11:30:00 PM

I'm sure this question has been asked and answered in the past, but googling
and searching the list archives isn't getting me much. It's probably a case
of me not searching correctly. So, if someone has a pointer on that front,
let me know.

Basically, I want a class to dynamically load and instantiate objects.
Here's the code that is supposed to do that:

ComponentGatherer.rb
---------------------------------

class ComponentGatherer

def initialize()
@@components = []
Dir.foreach( File.dirname( __FILE__ ) ){|x|
next unless x =~ /component.rb$/i
x.gsub!( ".rb", "" )
require "#{x}"
@@components.push( x )
}
end

def components
@@components.each{ |x|
test = x.new()
# Blah, blah, blah
}
end
end


Locating and requring the files seems to be working fine, it's when the
component() call is made that I'm a bit lost. I have to
*Component.rbfiles, they look like this:

MyOtherComponent.rb
--------------------------------
class MyOtherTestComponent

attr :test

def initialize()
self.test = 2
end
end

The error I get from the components() method is:

undefined method `new' for "MyOtherTestComponent":String (NoMethodError)

I understand what the error is saying, but I'm not sure how to call new() on
"x" above such that it returns an object of the requested class. Any help
is appreciated.

Regards,

Troy Denkinger
2 Answers

Joel VanderWerf

3/2/2006 12:30:00 AM

0

Troy Denkinger wrote:
> I'm sure this question has been asked and answered in the past, but googling
> and searching the list archives isn't getting me much. It's probably a case
> of me not searching correctly. So, if someone has a pointer on that front,
> let me know.
>
> Basically, I want a class to dynamically load and instantiate objects.
> Here's the code that is supposed to do that:
>
> ComponentGatherer.rb
> ---------------------------------
>
> class ComponentGatherer
>
> def initialize()
> @@components = []
> Dir.foreach( File.dirname( __FILE__ ) ){|x|
> next unless x =~ /component.rb$/i
> x.gsub!( ".rb", "" )
> require "#{x}"
> @@components.push( x )
> }
> end
>
> def components
> @@components.each{ |x|
> test = x.new()
> # Blah, blah, blah
> }
> end
> end
>
>
> Locating and requring the files seems to be working fine, it's when the
> component() call is made that I'm a bit lost. I have to
> *Component.rbfiles, they look like this:
>
> MyOtherComponent.rb
> --------------------------------
> class MyOtherTestComponent
>
> attr :test
>
> def initialize()
> self.test = 2
> end
> end
>
> The error I get from the components() method is:
>
> undefined method `new' for "MyOtherTestComponent":String (NoMethodError)
>
> I understand what the error is saying, but I'm not sure how to call new() on
> "x" above such that it returns an object of the requested class. Any help
> is appreciated.
>
> Regards,
>
> Troy Denkinger
>

If there is a way to map from the file name to the class name (in this
example, it would map "MyOtherComponent.rb" to "MyOtherTestComponent"),
then you can do this first, and then use const_get to get the class:

x = "MyOtherComponent.rb"
x.gsub(/.rb$/, "")
x.gsub(/Component/, "TestComponent")
cl = Kernel.const_get x
obj = cl.new

But it's sometimes difficult to enforce this filename/classname consistency.

I prefer something like this:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-t...

It still uses const_get, but it wraps the component inside a module, so
that the global namespace doesn't get polluted, and you can query for
the class that was defined in a file without mucking around with the
file name.

HTH.

--
vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407


Troy Denkinger

3/3/2006 6:16:00 PM

0

Thanks for the followup. I also figured out how to search and found this:

http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-talk/134...

Which also helps.

Thanks.

On 3/1/06, Joel VanderWerf <vjoel@path.berkeley.edu> wrote:
>
> Troy Denkinger wrote:
> > I'm sure this question has been asked and answered in the past, but
> googling
> > and searching the list archives isn't getting me much. It's probably a
> case
> > of me not searching correctly. So, if someone has a pointer on that
> front,
> > let me know.
> >
> > Basically, I want a class to dynamically load and instantiate objects.
> > Here's the code that is supposed to do that:
> >
> > ComponentGatherer.rb
> > ---------------------------------
> >
> > class ComponentGatherer
> >
> > def initialize()
> > @@components = []
> > Dir.foreach( File.dirname( __FILE__ ) ){|x|
> > next unless x =~ /component.rb$/i
> > x.gsub!( ".rb", "" )
> > require "#{x}"
> > @@components.push( x )
> > }
> > end
> >
> > def components
> > @@components.each{ |x|
> > test = x.new()
> > # Blah, blah, blah
> > }
> > end
> > end
> >
> >
> > Locating and requring the files seems to be working fine, it's when the
> > component() call is made that I'm a bit lost. I have to
> > *Component.rbfiles, they look like this:
> >
> > MyOtherComponent.rb
> > --------------------------------
> > class MyOtherTestComponent
> >
> > attr :test
> >
> > def initialize()
> > self.test = 2
> > end
> > end
> >
> > The error I get from the components() method is:
> >
> > undefined method `new' for "MyOtherTestComponent":String
> (NoMethodError)
> >
> > I understand what the error is saying, but I'm not sure how to call
> new() on
> > "x" above such that it returns an object of the requested class. Any
> help
> > is appreciated.
> >
> > Regards,
> >
> > Troy Denkinger
> >
>
> If there is a way to map from the file name to the class name (in this
> example, it would map "MyOtherComponent.rb" to "MyOtherTestComponent"),
> then you can do this first, and then use const_get to get the class:
>
> x = "MyOtherComponent.rb"
> x.gsub(/.rb$/, "")
> x.gsub(/Component/, "TestComponent")
> cl = Kernel.const_get x
> obj = cl.new
>
> But it's sometimes difficult to enforce this filename/classname
> consistency.
>
> I prefer something like this:
>
> http://blade.nagaokaut.ac.jp/cgi-bin/scat.rb/ruby/ruby-t...
>
> It still uses const_get, but it wraps the component inside a module, so
> that the global namespace doesn't get polluted, and you can query for
> the class that was defined in a file without mucking around with the
> file name.
>
> HTH.
>
> --
> vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407
>
>