> On Mon, 26 Jul 2004, Daniel Cremer wrote: > >> Hi, >> >> Is there a solution to do code introspection rather than introspection >> at the level of the Module/Object ? I can't figure out if I'm looking >> for something that isn't there in Ruby since I've been reading C# code >> or if I'm missing something. Let me explain my problem. >> I would like to load ruby source files and dynamically create objects >> from classes located inside these sources. It's one class/object per >> source file and I can make it so that a string from a configuration >> file holds the name of the class. However I can't figure out a good >> way to use that string to get to the class in the source file. >> >> I could use eval but am really uncomfortable with that for obvious >> reasons (people keep saying it's evil so I don't play with him). The >> other solution I came up with was to add a method in the same source >> but outside the class to return the desired object: >> >> --------------source file--------- >> class MyNewClass >> ... >> end >> >> def create_loaded_class() >> return MyNewClass.new() >> end >> --------------------------------- >> >> Then as I require the source files I can successively invoke the >> create_loaded_class method. This works but can get quite messy as >> there are a lot of things to consider if you need to reload sources >> and create new objects etc. >> Please tell me I'm missing something obvious :). Using module_eval in the context of a wrapper module is one way to go. (I know you said no eval, but load/require end up eval-ing, anyway. I guess you could do something with $SAFE if you are worried about mischief.) This has gotten so common for me that I put it in a small lib: http://redshift.sourceforge.net/script. Here's a way of using it for what you want to do: --- program.rb --- require 'script' files = [ "dog.rb", "cat.rb" ] files.each do |file| animal_wrapper = Script.load(file) # animal_wrapper is a Module in whose context the top-level # constants and methods are defined. p animal_wrapper.main_file # should be same as the file local var p animal_wrapper::CLASS # top-level constant in the script p animal_wrapper.make_animal # top-level meth in the script end --- dog.rb --- class Dog def initialize name @name = name end end CLASS = Dog def make_animal Dog.new "Rover" end --- cat.rb --- class Dog def initialize name @name = name end end CLASS = Dog def make_animal Dog.new "Rover" end --- output of program.rb --- "/home/vjoel/tmp/script-example/dog.rb" #<Script:0x401c4e3c>::Dog #<#<Script:0x401c4e3c>::Dog:0x401c4964 @name="Rover"> "/home/vjoel/tmp/script-example/cat.rb" #<Script:0x401c4928>::Cat #<#<Script:0x401c4928>::Cat:0x401c4450 @name="Fuzzy"> -------- (You might want Dog and Cat to inherit from some base class that has a self.to_s method to avoid the hex junk.) You could simplify the picture by defining the _same_ class in each script file: class Animal def initialize;...;end end and then you can reference it by animal_wrapper::Animal.new in your main program. The fact that dog.rb and cat.rb are loaded into different wrapper contexts keeps these classes distinct, even though their names appear the same.