Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Look up all descendants of a class in Ruby

Tags:

ruby

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.