On 4/15/07, Dorren <dorrenchen / gmail.com> wrote:
> for a given class, find all subclasses
>
> i found the solution (by pit capitain) at
> http://groups.google.com/group/comp.lang.ruby/browse_thread/thread/e812c7cef446a96
> , it works, but i don't understand it.
> --------------------------------------------------------
>    require "enumerator"
>
>    def get_subclasses(klass)
>      ObjectSpace.enum_for(:each_object, class << klass; self;
> end).to_a
>    end
>
> -------------------------------------------------------
>
> i don't understand what "class << klass; self; end" does. can someone
> rewrite and make it longer?
>
>

There are two potentially confusing bits about that very elegant piece of code.

One is the use of enumerator and enum_for, which can be pretty easily
unrolled. However, it may not be clear from that code that the hard
work is actually being done by ObjectSpace.each_object which accepts a
parameter to use as a 'filter'

The other confusing bit could be the use of the "class << object"
form, which is described as such (in the pickaxe):

... the class <<obj notation, which basically says "build me a new
class just for object obj." ...

Thats one way of putting it. Another way is presented in this article
(which is the explanation that makes the most sense to me):
http://whytheluckystiff.net/articles/seeingMetaclassesClearly.html

Here is a 'longer' version of the above like you asked for, though,
I'm not sure it's any more clear:
#################################
class Object
  # The hidden singleton lurks behind everyone
  def metaclass
    class << self
      return self
    end
  end
end

def get_subclasses(klass)
  the_subclasses = []

  ObjectSpace.each_object( klass.metaclass ) do |object|
    the_subclasses.push object
  end

  return the_subclasses
end

class A
end

class B < A
end

p get_subclasses( A )
#################################

Hope that helps,
-Harold