Forum: Ruby Identfying classes in a file dynamically

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
Navya A. (Guest)
on 2006-04-11 02:24
(Received via mailing list)
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.
Joel VanderWerf (Guest)
on 2006-04-11 05:29
(Received via mailing list)
Navya A. wrote:
>  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.
unknown (Guest)
on 2006-04-11 06:15
(Received via mailing list)
Hi --

On Tue, 11 Apr 2006, Joel VanderWerf wrote:

>> sc, ec = [], []
>
> 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 (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 5!
http://www.manning.com/black
Joel VanderWerf (Guest)
on 2006-04-11 06:21
(Received via mailing list)
removed_email_address@domain.invalid 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...
unknown (Guest)
on 2006-04-11 06:49
(Received via mailing list)
Hi --

On Tue, 11 Apr 2006, Joel VanderWerf wrote:

> $ 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 (removed_email_address@domain.invalid)
Ruby Power and Light, LLC (http://www.rubypowerandlight.com)

"Ruby for Rails" coming in PDF April 15, and in paper May 5!
http://www.manning.com/black
Joel VanderWerf (Guest)
on 2006-04-11 07:19
(Received via mailing list)
removed_email_address@domain.invalid wrote:
>>
>
> 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.
zdennis (Guest)
on 2006-04-11 17:57
(Received via mailing list)
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

Navya A. wrote:
>  ObjectSpace.each_object(Class) { |c| sc << c }
>
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
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.1 (GNU/Linux)
Comment: Using GnuPG with Thunderbird - http://enigmail.mozdev.org

iD8DBQFEO7aRMyx0fW1d8G0RAjPQAJ0YvkXA1bRmS7VCWlxw/n5CeFUD9ACcD100
MN9Ii+gFYzpg56Veh4YFd2g=
=vGHj
-----END PGP SIGNATURE-----
This topic is locked and can not be replied to.