[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

Creating objects without knowing their names

paul.p.carey

2/16/2006 9:05:00 AM

Hi

I'd like to load an arbitary number of Ruby files from a directory and
create their associated objects. However, I don't know the class names
of the files that have just been loaded. Is it possible to determine a
file's class name once that file has been loaded? (Without resorting to
parsing, or enforcing a mapping between the filename and class name.)

What I want to do is something like the following:

converter_names = Array.new
Find.find("./converters") do |filename|
converter_names.push(filename) if filename =~ /rb$/
end

converters = Array.new
converter_names.each do |converter_name|
load converter_name
klassName = ...?
converters.push(Object.const_get(klassName).new)
end

Many thanks

Paul

4 Answers

Joel VanderWerf

2/16/2006 9:44:00 AM

0

paul.p.carey@gmail.com wrote:
> Hi
>
> I'd like to load an arbitary number of Ruby files from a directory and
> create their associated objects. However, I don't know the class names
> of the files that have just been loaded. Is it possible to determine a
> file's class name once that file has been loaded? (Without resorting to
> parsing, or enforcing a mapping between the filename and class name.)
>
> What I want to do is something like the following:
>
> converter_names = Array.new
> Find.find("./converters") do |filename|
> converter_names.push(filename) if filename =~ /rb$/
> end
>
> converters = Array.new
> converter_names.each do |converter_name|
> load converter_name
> klassName = ...?
> converters.push(Object.const_get(klassName).new)
> end

You probably know this already, but for the benefit of bystanders: there
isn't in general one-to-one mapping between classes and files. A class
can be defined across several files; a file can contain several class
definitions. (Maybe in the case of the files you are using there is
always a 1-1 map, though.)

I like to use module_eval to solve this problem by reading the file and
evaling its definitions in the context of a new module. It's all wrapped
up neatly in my "script" library on RAA.

For example:

$ cat cl.rb
class MyWeirdClass
def foo
end
end

SOME_CONSTANT = 3

$ cat script-ex.rb
require 'script'

script = Script.load "cl.rb"

p script
p script.constants
script_objects = script.constants.map {|k| script.const_get(k)}
script_classes = script_objects.grep(Class)
p script_classes


$ ruby script-ex.rb
#<Script:/home/vjoel/ruby/misc/cl.rb>
["SOME_CONSTANT", "MyWeirdClass"]
[#<Script:0xb7d794a4>::MyWeirdClass]


This also has the benefit of keeping every name from the external file
in a new module's namespace. The return value of Script.load is that module.

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


Robert Klemme

2/16/2006 10:47:00 AM

0

Joel VanderWerf wrote:
> paul.p.carey@gmail.com wrote:
>> Hi
>>
>> I'd like to load an arbitary number of Ruby files from a directory
>> and create their associated objects. However, I don't know the class
>> names of the files that have just been loaded. Is it possible to
>> determine a file's class name once that file has been loaded?
>> (Without resorting to parsing, or enforcing a mapping between the
>> filename and class name.)

> You probably know this already, but for the benefit of bystanders:
> there isn't in general one-to-one mapping between classes and files.
> A class
> can be defined across several files; a file can contain several class
> definitions. (Maybe in the case of the files you are using there is
> always a 1-1 map, though.)

There are other options. Some of them:

- Make sure all classes on those files inherit a base class which
overrides #inherited so it gets notified every time a sub class is
created. You can then store the set of sub classes in a member of the
base class and use that for whatever purposes.

- Make classes in those files register with some arbitrary registry you
create (that's basically the same as the first just more explicit).

- use set_trace_func to trance execution of those files and notice
whenever a new class occurs. (Not sure whether that works though).

Kind regards

robert

Markus Tarmak

2/16/2006 12:48:00 PM

0

Robert Klemme wrote:
> Joel VanderWerf wrote:
> > paul.p.carey@gmail.com wrote:
> >> Hi
> >>
> >> I'd like to load an arbitary number of Ruby files from a directory
> >> and create their associated objects. However, I don't know the class
> >> names of the files that have just been loaded. Is it possible to
> >> determine a file's class name once that file has been loaded?
> >> (Without resorting to parsing, or enforcing a mapping between the
> >> filename and class name.)
>
> > You probably know this already, but for the benefit of bystanders:
> > there isn't in general one-to-one mapping between classes and files.
> > A class
> > can be defined across several files; a file can contain several class
> > definitions. (Maybe in the case of the files you are using there is
> > always a 1-1 map, though.)
>
> There are other options. Some of them:
>
> - Make sure all classes on those files inherit a base class which
> overrides #inherited so it gets notified every time a sub class is
> created. You can then store the set of sub classes in a member of the
> base class and use that for whatever purposes.
>
> - Make classes in those files register with some arbitrary registry you
> create (that's basically the same as the first just more explicit).
>
> - use set_trace_func to trance execution of those files and notice
> whenever a new class occurs. (Not sure whether that works though).
>
> Kind regards
>
> robert

Or you can compare the classes you had before loading to classes you
had after loading. Something like this:

def defined_classes
classes = []
ObjectSpace.each_object(Class){|c| classes << c}
classes
end

initial_classes = defined_classes
require 'net/http'
p defined_classes - initial_classes

paul.p.carey

2/16/2006 3:02:00 PM

0

All very helpful answers. Many thanks indeed.
Paul