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.
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.
$ 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.
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.
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" )