Nifty one-liner to search ObjectSpace?

Say I've got a class and I know it has subclasses. I'm absolutely sure
there must be an irb ObjectSpace one-liner to give me all the
subclasses of an arbitrary class.

The best I have right now is based on a solution to something else, a
Scriptaculous inline autocompleter for Rails apps that gives you Ajaxy
autocomplete search of all class names within your Rails app.

http://gilesbowkett.com/blog_code_samples/123006_seaside_rails/pat.txt

I've been able to find the Class instance method #inherited(), which
takes another class and tells you yay or nay, but a simple one-liner
to return a class's subclasses has so far proved out of my reach.

I know it exists. I just don't know what it is. I'm also kind of
stymied because it appears ObjectSpace has #each_object but not #each.
That seems so weird to me.

···

--
Giles Bowkett
http://www.gilesgoatboy.org


Say I've got a class and I know it has subclasses. I'm absolutely sure
there must be an irb ObjectSpace one-liner to give me all the
subclasses of an arbitrary class.

Yup :slight_smile:

I've been able to find the Class instance method #inherited(), which
takes another class and tells you yay or nay, but a simple one-liner
to return a class's subclasses has so far proved out of my reach.

ObjectSpace.each_object( Class ) {|klass| puts klass if klass < IO }

...will give you any class that is a subclass of IO. Could pretty
easily be wrapped into a method you could call on a class. In fact:

class Class
  def subclasses
    out =
    ObjectSpace.each_object( Class ) {|k| out << k if k < self }
    return out
  end
end

Stick that in your .irbrc and call IO.subclasses. YEAH.

I know it exists. I just don't know what it is. I'm also kind of
stymied because it appears ObjectSpace has #each_object but not #each.
That seems so weird to me.

What would #each do that #each_object doesn't?

Ben

···

On Tue, Mar 06, 2007, Giles Bowkett wrote:

How about
ObjectSpace.each_object {|o| puts o.name if o.is_a?(Class) && o < BaseClass}

irb(main):005:0> ObjectSpace.each_object {|o| puts o.name if
o.is_a?(Class) && o < Numeric}
Bignum
Float
Fixnum
Integer

Pat

···

On 3/5/07, Giles Bowkett <gilesb@gmail.com> wrote:

Say I've got a class and I know it has subclasses. I'm absolutely sure
there must be an irb ObjectSpace one-liner to give me all the
subclasses of an arbitrary class.

The best I have right now is based on a solution to something else, a
Scriptaculous inline autocompleter for Rails apps that gives you Ajaxy
autocomplete search of all class names within your Rails app.

http://gilesbowkett.com/blog_code_samples/123006_seaside_rails/pat.txt
Giles Bowkett: Search results for cleverness

I've been able to find the Class instance method #inherited(), which
takes another class and tells you yay or nay, but a simple one-liner
to return a class's subclasses has so far proved out of my reach.

I know it exists. I just don't know what it is. I'm also kind of
stymied because it appears ObjectSpace has #each_object but not #each.
That seems so weird to me.

--
Giles Bowkett
http://www.gilesgoatboy.org
http://gilesbowkett.blogspot.com
http://giles.tumblr.com/

Giles Bowkett schrieb:

Say I've got a class and I know it has subclasses. I'm absolutely sure
there must be an irb ObjectSpace one-liner to give me all the
subclasses of an arbitrary class.
(...)
I know it exists. I just don't know what it is. I'm also kind of
stymied because it appears ObjectSpace has #each_object but not #each.
That seems so weird to me.

Giles, here's something for both of your wishes:

   require "enumerator"

   s = Exception # substitute with your superclass
   puts ObjectSpace.to_enum(:each_object, class<<s; self; end).to_a

Note that you can replace "to_a" with any method of Enumerable.

Regards,
Pit

Additional note: if you need the subclass info often you may want to look into #inherited. With that method you can record all subclasses of a class when they are created and do not need to revisit all classes.

Kind regards

  robert

···

On 06.03.2007 01:21, Giles Bowkett wrote:

Say I've got a class and I know it has subclasses. I'm absolutely sure
there must be an irb ObjectSpace one-liner to give me all the
subclasses of an arbitrary class.

The best I have right now is based on a solution to something else, a
Scriptaculous inline autocompleter for Rails apps that gives you Ajaxy
autocomplete search of all class names within your Rails app.

http://gilesbowkett.com/blog_code_samples/123006_seaside_rails/pat.txt
Giles Bowkett: Search results for cleverness

I've been able to find the Class instance method #inherited(), which
takes another class and tells you yay or nay, but a simple one-liner
to return a class's subclasses has so far proved out of my reach.

I know it exists. I just don't know what it is. I'm also kind of
stymied because it appears ObjectSpace has #each_object but not #each.
That seems so weird to me.

ObjectSpace.each_object takes an optional argument that restricts it to
a given class/module, so you can take out the #is_a? check by saying
ObjectSpace.each_object( Class ) {}

Ben

···

On Tue, Mar 06, 2007, Pat Maddox wrote:

How about
ObjectSpace.each_object {|o| puts o.name if o.is_a?(Class) && o < BaseClass}

> Say I've got a class and I know it has subclasses. I'm absolutely sure
> there must be an irb ObjectSpace one-liner to give me all the
> subclasses of an arbitrary class.

Yup :slight_smile:

> I've been able to find the Class instance method #inherited(), which
> takes another class and tells you yay or nay, but a simple one-liner
> to return a class's subclasses has so far proved out of my reach.

ObjectSpace.each_object( Class ) {|klass| puts klass if klass < IO }

...will give you any class that is a subclass of IO. Could pretty
easily be wrapped into a method you could call on a class. In fact:

class Class
  def subclasses
    out =
    ObjectSpace.each_object( Class ) {|k| out << k if k < self }
    return out
  end
end

Stick that in your .irbrc and call IO.subclasses. YEAH.

> I know it exists. I just don't know what it is. I'm also kind of
> stymied because it appears ObjectSpace has #each_object but not #each.
> That seems so weird to me.

What would #each do that #each_object doesn't?

Ben

#each enables #collect, doesn't it? It's the core iterator for all
those other iterator methods.

I wanted to throw the horns all metal-style when I first saw this, but
it doesn't work in irb:

class Class
   def subclasses
       out =
       ObjectSpace.each_object( Class ) {|k| out << k if k < self }
       return out
     end
  end

=> nil

Event.subclasses

NoMethodError: protected method `subclasses' called for Event:Class
        from /opt/local/lib/ruby/gems/1.8/gems/activerecord-1.15.2/lib/active_record/base.rb:1236:in
`method_missing'
        from (irb):9

Event.new.subclasses

NoMethodError: undefined method `subclasses' for #<Event:0x3556b50>
        from /opt/local/lib/ruby/gems/1.8/gems/activerecord-1.15.2/lib/active_record/base.rb:1861:in
`method_missing'
        from (irb):10

I thought maybe I needed to use Class.class_eval instead:

Class.class_eval do
   def subclasses
       out =
       ObjectSpace.each_object( Class ) {|k| out << k if k < self }
       return out
     end
  end

but I got identical error output when I tried that. In fact I think I
just used a synonym for "class Class" by using "Class.class_eval" and
the whole thing was very cargo cult of me.

Anyway, that < operator for inheritance is insanely cool, but I'm
missing something getting this to work.

Couldn't get Pat's solution to work either!

ObjectSpace.each_object {|o| puts o.name if o.is_a?(Class) && o < Event}

=> 55128

Maybe just molasses in the brainpan today.

···

On 3/5/07, Ben Bleything <ben@bleything.net> wrote:

On Tue, Mar 06, 2007, Giles Bowkett wrote:

--
Giles Bowkett
http://www.gilesgoatboy.org

http://giles.tumblr.com/

muppet =

=>

ObjectSpace.each_object {|o| muppet.push(o.name) if o.is_a?(Class)

&& o < Event}
=> 57244

muppet

=>

···

--
Giles Bowkett
http://www.gilesgoatboy.org

http://giles.tumblr.com/

#each enables #collect, doesn't it? It's the core iterator for all
those other iterator methods.

Good call, hadn't considered that.

I wanted to throw the horns all metal-style when I first saw this, but
it doesn't work in irb:

WORKSFORME:

class Class
  def subclasses
    out =
    ObjectSpace.each_object( Class ) {|k| out << k if k < self }
    return out
  end
end

=> nil

IO.subclasses

=> [File, Socket, UNIXServer, UNIXSocket, UDPSocket, TCPServer, TCPSocket, IPSocket, BasicSocket]

I just tried this on a Rails model, and it bombed. I think that's
what's happening to you. You can do Event.send :subclasses, but that's
sort of ghetto.

but I got identical error output when I tried that. In fact I think I
just used a synonym for "class Class" by using "Class.class_eval" and
the whole thing was very cargo cult of me.

hehehe

Couldn't get Pat's solution to work either!

>>ObjectSpace.each_object {|o| puts o.name if o.is_a?(Class) && o < Event}
=> 55128

This doesn't make sense to me, but without being in your environment
it's useless to try to help :slight_smile:

Ben

···

On Tue, Mar 06, 2007, Giles Bowkett wrote:

You know what, I'm sorry, I figured out why this didn't work.
ObjectSpace only contains the classes loaded, not the classes which
could be loaded. The subclasses of the class I was examining hadn't
been loaded yet.

ObjectSpace.each_object(Class){|k| out << k if k < ActiveRecord::Base}

=> 1355

out

=> [CGI::Session::ActiveRecordStore::Session, Event, Tag, Tagging]

The Fixnum returned by #each_object() still baffles me, but I think
for this to be useful I'd have to autoload all the classes defined in
the app; I was doing this in Rails console and apparently the console
lazily loads only the things it needs at any given time.

···

--
Giles Bowkett
http://www.gilesgoatboy.org

http://giles.tumblr.com/

The Rails problem is due to some Rails internals thing, I think. I
just got it to work using #subklasses instead of #subclasses for the
method name. Doesn't fix the lazy loading, though.

···

--
Giles Bowkett
http://www.gilesgoatboy.org


http://giles.tumblr.com/

I'm pretty sure it's the total number of objects inspected by the call
to each_object. So that'd mean it looked at 1355 classes to find the
tasty nuggets it was after.

Ben

···

On Tue, Mar 06, 2007, Giles Bowkett wrote:

The Fixnum returned by #each_object() still baffles me, but I think
for this to be useful I'd have to autoload all the classes defined in
the app; I was doing this in Rails console and apparently the console
lazily loads only the things it needs at any given time.

Sorry, that was my assumption too, I'm just puzzled that it's doing
that, rather than returning an array or something.

···

On 3/5/07, Ben Bleything <ben@bleything.net> wrote:

On Tue, Mar 06, 2007, Giles Bowkett wrote:
> The Fixnum returned by #each_object() still baffles me, but I think
> for this to be useful I'd have to autoload all the classes defined in
> the app; I was doing this in Rails console and apparently the console
> lazily loads only the things it needs at any given time.

I'm pretty sure it's the total number of objects inspected by the call
to each_object. So that'd mean it looked at 1355 classes to find the
tasty nuggets it was after.

Ben

--
Giles Bowkett
http://www.gilesgoatboy.org

http://giles.tumblr.com/