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-talk/181735

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