Here is an example:
class Parent
def self.descendants
ObjectSpace.each_object(Class).select { |klass| klass < self }
end
end
class Child < Parent
end
class GrandChild < Child
end
puts Parent.descendants
puts Child.descendants
puts Parent.descendants gives you:
GrandChild
Child
puts Child.descendants gives you:
GrandChild
If you use Rails >= 3, you have two options in place. Use .descendants
if you want more than one level depth of children classes, or use .subclasses
for the first level of child classes.
Example:
class Animal
end
class Mammal < Animal
end
class Dog < Mammal
end
class Fish < Animal
end
Animal.subclasses #=> [Mammal, Fish]
Animal.descendants #=> [Dog, Mammal, Fish]
Ruby 1.9 (or 1.8.7) with nifty chained iterators:
#!/usr/bin/env ruby1.9
class Class
def descendants
ObjectSpace.each_object(::Class).select {|klass| klass < self }
end
end
Ruby pre-1.8.7:
#!/usr/bin/env ruby
class Class
def descendants
result = []
ObjectSpace.each_object(::Class) {|klass| result << klass if klass < self }
result
end
end
Use it like so:
#!/usr/bin/env ruby
p Animal.descendants
Override the class method named inherited. This method would be passed the subclass when it is created which you can track.
Alternatively (updated for ruby 1.9+):
ObjectSpace.each_object(YourRootClass.singleton_class)
Ruby 1.8 compatible way:
ObjectSpace.each_object(class<<YourRootClass;self;end)
Note that this won't work for modules. Also, YourRootClass will be included in the answer. You can use Array#- or another way to remove it.
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