user3482116
user3482116

Reputation: 33

How to discover which classes were loaded when requiring a Ruby file

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

Answers (4)

Sergio Tulentsev
Sergio Tulentsev

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

Arup Rakshit
Arup Rakshit

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

BroiSatse
BroiSatse

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

Alex D
Alex D

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

Related Questions