From: Joel VanderWerf Date: 2006-03-02T09:29:30+09:00 Subject: Re: Dynamic Object Instantiation 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