4

My goal is this:

class MyBeautifulRubyClass
  #some code goes here
end

puts MyBeautifulRubyClass.subclasses #returns 0

class SlightlyUglierClass < MyBeautifulRubyClass
end

puts MyBeautifulRubyClass.subclasses #returns 1

hell ideally even

puts MyBeautifulRubyClass.getSubclasses #returns [SlightlyUglierClass] in class object form

I am sure this is possible, just not sure how!

A Question Asker
  • 3,339
  • 7
  • 31
  • 39

2 Answers2

9

Here's an inefficient way:

Look up all descendants of a class in Ruby

The efficient approach would use the inherited hook:

class Foo
  def self.descendants
    @descendants ||= []
  end

  def self.inherited(descendant)
    descendants << descendant
  end
end

class Bar < Foo; end
class Zip < Foo; end

Foo.descendants #=> [Bar, Zip]

If you need to know about descendants of descendants, you can recurse to get them:

class Foo
  def self.all_descendants
    descendants.inject([]) do |all, descendant|
      (all << descendant) + descendant.all_descendants
    end
  end
end

class Blah < Bar; end

Foo.descendants     #=> [Bar, Zip]
Foo.all_descendants #=> [Bar, Blah, Zip]
Community
  • 1
  • 1
d11wtq
  • 34,788
  • 19
  • 120
  • 195
  • This is pretty similar to [how Rails does it](https://github.com/rails/rails/blob/d89a7967b5af5c87bbfc268af72287b82541d384/activesupport/lib/active_support/descendants_tracker.rb#L32-35) as well. – Michelle Tilley Oct 15 '11 at 00:28
  • Could I then call Bar.descendants? What would it take to make that work? – Volte Feb 06 '13 at 19:29
  • @Volte Create a module called something like DescendantsTracking that has the inherited method (as a regular method, not a singleton method) then "extend" Foo and Bar with it. – d11wtq Feb 06 '13 at 22:44
0

Not sure if you can do it without going to ObjectSpace a la http://snippets.dzone.com/posts/show/2992, but that may have changed--just one solution.

Dave Newton
  • 158,873
  • 26
  • 254
  • 302