Reputation: 33
If I require a Ruby file that contains class definitions, how can I discover what classes were added by the require without having to view the contents of the file?
For example, if I have file 'foobar.rb', consisting only of the following:
class Foo
end
class Bar
end
I know that if I require this file, I now have Foo and Bar available:
>> require 'foobar' #=> true
>> Foo #=> Foo
>> Bar #=> Bar
Supposing I didn't know what the contents of foobar.rb were and I merely required it. How would I discover that Foo and Bar are now new class constants?
Upvotes: 3
Views: 527
Reputation: 230306
Using system tracer:
# one.rb
class Foo
end
class Bar
end
# two.rb
require 'tracer'
Tracer.add_filter {|event| event == 'class' }
Tracer.on {
require './one'
}
>> #0:/Users/sergio/projects/tmp/mp/one.rb:1::C: class Foo
>> #0:/Users/sergio/projects/tmp/mp/one.rb:4::C: class Bar
Documentation: Tracer.
Upvotes: 2
Reputation: 118261
You can do that by using a hacky approach. Each time when you will be defining a new custom class using class
keyword, or Class::new
, whatever, a hook method Class#inherited
method called always.
Thus, put the below code in your file :
class Object
def self.inherited(subclass)
(@classes ||= []) << subclass
end
def self.display_all_loaded_custom_class
@classes
end
end
class Foo;end
class Bar;end
self.class.display_all_loaded_custom_class # => [Foo, Bar]
Whenever you will be defining any class, without making it a subclass of any other class, Object
becomes the default superclass of these class(s). Thus it is very expected you need to define Object::inherited
method to track those.
Upvotes: 2
Reputation: 44675
You can try:
classes = ObjectSpace.each_object(Class).to_a
require 'foobar'
new_classes = ObjectSpace.each_object(Class).to_a - classes
This will only return newly defined classes instead of all the defined constants.
Upvotes: 0
Reputation: 30445
If you are only interested in classes and modules which are defined at the top level, i.e. not inside a Module, you can do it like this:
previously_defined = Object.constants
require 'foobar'
just_defined = Object.constants - previously_defined
(You'll have to filter out the names of modules if you don't want them.)
If you need to get all classes, you can do:
previously_defined = []
ObjectSpace.each_object(Class) { |cls| previously_defined << cls }
require 'foobar'
just_defined = []
ObjectSpace.each_object(Class) { |cls| just_defined << cls }
just_defined -= previously_defined
Upvotes: 1