Identfying classes in a file dynamically

Hi,

I was trying to identify the classes in a give file at the run time. the following is the code i used.
sc, ec = [], []
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes
sc, ec = [], []
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman1.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes

Both roman.rb and roman1.rb has the same class Roman.
the first time i print the new_classes i can see the Roman class in the output but the second one does not print because the class Roman is arleady read previously.

is there a way i can over come this problem and identify the Roman class twice.

Thanks,
Navya.

···

---------------------------------
New Yahoo! Messenger with Voice. Call regular phones from your PC and save big.

Navya Amerineni wrote:

Hi,

I was trying to identify the classes in a give file at the run time. the following is the code i used.
sc, ec = ,
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes
sc, ec = ,
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman1.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes

Both roman.rb and roman1.rb has the same class Roman.
the first time i print the new_classes i can see the Roman class in the output but the second one does not print because the class Roman is arleady read previously.

is there a way i can over come this problem and identify the Roman class twice.

One way is to wrap the file in a module, so that the constants defined
in it will not collide with other constants.

file = "some/file"
m = Module.new
m.module_eval(IO.read(file), File.expand_path(file))
p m.constants

But then the Roman module won't be available except as m::Roman. To fix
this, you could include m into any class or module that needs to use Roman.

···

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

Navya Amerineni wrote:

Hi,

I was trying to identify the classes in a give file at the run time. the following is the code i used.
sc, ec = ,
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes
sc, ec = ,
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman1.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes

Both roman.rb and roman1.rb has the same class Roman.
the first time i print the new_classes i can see the Roman class in the output but the second one does not print because the class Roman is arleady read previously.

is there a way i can over come this problem and identify the Roman class twice.

Way #1, store the new classes in a hash. This way you won't be overriding any classes you've previously loaded.

Way #2, use one array to store new classes, and then each time you compute the "new_classes" after you load a file, merge those
into your one authoriatize array. This way you won't be overriding any classes you've previously loaded.

Way #3, pass a string into a new ruby process which loads the files and outputs the new classes. Read these in and then use Way #1
or Way #2 to store the classes. This is a bit hackish, but it works and it leaves your toplevel ruby process namespace alone.

Here is the idea of Way #3

  str =<<-'EOT'
    def count_classes( arg )
      arr =
      ObjectSpace.each_object( arg ){ |c| arr << c }
      arr
    end

    orig_classes = count_classes( Class )
    require "load"
    new_classes = count_classes( Class ) - orig_classes
    puts new_classes.join( "\n" )
  EOT

  child = IO.popen( "ruby -e '#{str}'", "r" )
  new_classes = child.readlines.map!{ |s| s.chomp! }
  puts new_classes

Zach

Hi --

···

On Tue, 11 Apr 2006, Joel VanderWerf wrote:

Navya Amerineni wrote:

Hi,

I was trying to identify the classes in a give file at the run time. the following is the code i used.
sc, ec = ,
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes
sc, ec = ,
ObjectSpace.each_object(Class) { |c| sc << c }
require 'Roman1.rb'
ObjectSpace.each_object(Class) { |c| ec << c }
new_classes = ec - sc
puts new_classes

Both roman.rb and roman1.rb has the same class Roman.
the first time i print the new_classes i can see the Roman class in the output but the second one does not print because the class Roman is arleady read previously.

is there a way i can over come this problem and identify the Roman class twice.

One way is to wrap the file in a module, so that the constants defined
in it will not collide with other constants.

file = "some/file"
m = Module.new
m.module_eval(IO.read(file), File.expand_path(file))
p m.constants

But then the Roman module won't be available except as m::Roman. To fix
this, you could include m into any class or module that needs to use Roman.

Also I think that if the read-in file uses the ::Const construct,
those classes won't get counted.

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 5!

dblack@wobblini.net wrote:
...

Also I think that if the read-in file uses the ::Const construct,
those classes won't get counted.

You mean like this:

$ cat t.rb
class ::Foo
end
$ ruby -e 'load "t.rb"; p Foo'
Foo
$ ruby -e 'load "t.rb"; ObjectSpace.each_object(Class) {|c| p c if
c.name == "Foo"}'
Foo

So it doesn't look like that works, unless I'm misunderstanding...

···

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

Hi --

···

On Tue, 11 Apr 2006, Joel VanderWerf wrote:

dblack@wobblini.net wrote:
...

Also I think that if the read-in file uses the ::Const construct,
those classes won't get counted.

You mean like this:

$ cat t.rb
class ::Foo
end
$ ruby -e 'load "t.rb"; p Foo'
Foo
$ ruby -e 'load "t.rb"; ObjectSpace.each_object(Class) {|c| p c if
c.name == "Foo"}'
Foo

So it doesn't look like that works, unless I'm misunderstanding...

Yes, that's what I meant; if you have ::Foo in your file, then you
won't get a Foo class in the module you wrap in, so you won't get the
right count of modules in the file.

David

--
David A. Black (dblack@wobblini.net)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 5!

dblack@wobblini.net wrote:

Hi --

...

Also I think that if the read-in file uses the ::Const construct,
those classes won't get counted.

You mean like this:

$ cat t.rb
class ::Foo
end
$ ruby -e 'load "t.rb"; p Foo'
Foo
$ ruby -e 'load "t.rb"; ObjectSpace.each_object(Class) {|c| p c if
c.name == "Foo"}'
Foo

So it doesn't look like that works, unless I'm misunderstanding...

Yes, that's what I meant; if you have ::Foo in your file, then you
won't get a Foo class in the module you wrap in, so you won't get the
right count of modules in the file.

Oh, I see--I thought you meant it was a workaround, but it's actually a
limitation of the module wrapping trick. Good point.

···

On Tue, 11 Apr 2006, Joel VanderWerf wrote:

dblack@wobblini.net wrote:

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