[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

nifty one-liner to search ObjectSpace?

Giles Bowkett

3/6/2007 12:21:00 AM

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_rai...
http://gilesbowkett.bl.../search?q=...

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.gilesg...
http://gilesbowkett.bl...
http://giles.t...

38 Answers

Ben Bleything

3/6/2007 12:29:00 AM

0

On Tue, Mar 06, 2007, 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.

Yup :)

> 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

Pat Maddox

3/6/2007 12:44:00 AM

0

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_rai...
> http://gilesbowkett.bl.../search?q=...
>
> 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.gilesg...
> http://gilesbowkett.bl...
> http://giles.t...
>
>

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

Ben Bleything

3/6/2007 12:54:00 AM

0

On Tue, Mar 06, 2007, Pat Maddox wrote:
> How about
> ObjectSpace.each_object {|o| puts o.name if o.is_a?(Class) && o < BaseClass}

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

Giles Bowkett

3/6/2007 1:35:00 AM

0

On 3/5/07, Ben Bleything <ben@bleything.net> wrote:
> On Tue, Mar 06, 2007, 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.
>
> Yup :)
>
> > 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.

--
Giles Bowkett
http://www.gilesg...
http://gilesbowkett.bl...
http://giles.t...

Giles Bowkett

3/6/2007 1:41:00 AM

0

>> muppet = []
=> []
>> ObjectSpace.each_object {|o| muppet.push(o.name) if o.is_a?(Class)
&& o < Event}
=> 57244
>> muppet
=> []


--
Giles Bowkett
http://www.gilesg...
http://gilesbowkett.bl...
http://giles.t...

Ben Bleything

3/6/2007 2:19:00 AM

0

On Tue, Mar 06, 2007, Giles Bowkett wrote:
> #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 :)

Ben

Giles Bowkett

3/6/2007 2:23:00 AM

0

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.gilesg...
http://gilesbowkett.bl...
http://giles.t...

Giles Bowkett

3/6/2007 2:26:00 AM

0

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.gilesg...
http://gilesbowkett.bl...
http://giles.t...

Ben Bleything

3/6/2007 2:30:00 AM

0

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

3/6/2007 2:32:00 AM

0

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.gilesg...
http://gilesbowkett.bl...
http://giles.t...