If I have 4 classes with the following hierarchy:
class MainClass < ActiveRecord::Base
...
end
class SubClassA < MainClass
...
end
class SubClassB < MainClass
...
end
class SubClassC < MainClass
...
end
How can I get a list of the subclasses of MainClass without going through and creating instances of each of the other classes?
In a fresh IRB session I can go in and say
irb(main)> MainClass.descendants
=> []
However if I go through and create instances of each subclass I'll see the following
irb(main)> SubClassA.new
=> #<SubClassA ...>
irb(main)> SubClassB.new
=> #<SubClassB ...>
irb(main)> SubClassC.new
=> #<SubClassC ...>
irb(main)> MainClass.descendants
=> [SubClassA(...), SubClassB(...), SubClassC(...)]
I'm basically looking for a way to programmaticly supply all subclasses so in the future when I want to add SubClassD, SubClassE, etc., I won't have to worry that each one is instantiated in the code before the user can see them.
This is an artefact of development mode only loading classes when first referenced: those files haven't been read by the interpreter yet - as far as ruby is concerned the classes genuinely do not exist yet
A workaround is to put
require_dependency "subclass_a"
require_dependency "subclass_b"
....
At the bottom the file for main class (outside the class definition)
There are several ways you can achieve this. Either by using a gem such as the descendants_tracker:
class MainClass < ActiveRecord::Base
extend DescendantsTracker
end
class SubClassA < MainClass
end
...
MainClass.descendants # => [SubClassA]
Or you could create a custom one in your parent class like this:
class MainClass < ActiveRecord::Base
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
class SubClassA < MainClass
end
class SubClassB < MainClass
end
puts MainClass.descendants
#=> SubClassA
SubClassB
You can also check for levels of dependencies. If you want an array of the direct child of MainClass for example you could use the .subclasses
class method
MainClass.subclasses # => [SubClassA, SubClassB,...]
Now if you want more than one level depth of child classes use .descendants
. You can find an example here
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With