Class#descendants

provides a Module#ancestors, but no Class#descendants.

Here’s a working implementation:

class Class
  def inherited(klass)
    subclasses << klass
  end

  def subclasses
    @subclasses ||= []
  end

  def descendants
    subclasses.inject(subclasses) do |all, subclass|
      all + subclass.descendants
    end
  end
end

Notes

  1. This does obviously only keep track of classes created after the Class class has been extended.
  2. If you don’t want to keep track of all classes, simply put the methods above in the eigenclass of the class in which descendants you’re interested of. If you wonder why the above methods are instance methods, it is because instance methods of Class become class methods of Class instances.

Demonstration

class A;     end
class B < A; end
class C < B; end

A.subclasses  # => [B]
A.descendants # => [B, C]

See Also

Ruby Facets provides a Class#descendents that uses ObjectSpace instead of Class#inherited.