ASCII class inheritance tree generator

I thought I might share this little piece of code that generates a
‘lstree’-like output for class-hierarchy:

lstree(Numeric)

  • Numeric
    • Float
      `- Integer
    • Bignum
      `- Fixnum

Of course it is meant to be run for you own class hierarchies. It’s
basic stuff but I couldn’t find anything like it anywhere …

Cheers,
Simon

CODE:

#!/usr/bin/ruby -w

···

A class inheritance tree generator

def lstree(root)

get children of root

children = Hash.new()
ObjectSpace.each_object(Class) do |aClass|
if (root != aClass && aClass.ancestors.include?(root))
children[aClass.superclass] = Array.new() if children[aClass.superclass] == nil
children[aClass.superclass].push(aClass)
end
end

print nice ascii class inheritance tree

recursePrint = proc {|current_root,prefixString|
puts(prefixString+“- “+current_root.to_s)
if children[current_root] != nil
children[current_root].each do |child|
recursePrint.call(child,prefixString.tr('',' ') + " "+(child == children[current_root].last ? "”:”|"))
end
end
}

recursePrint.call(root,“”)
end


There are 10 types of people in the world…
those who understand binary and those who don’t.

I’d like to see this function included in irb ?
Somebody has an opinion about that ?

In fact i like when i coding making some test in an irb windows and this
function should help me.

Regards.

Simon Vandemoortele wrote:

I thought I might share this little piece of code that generates a
‘lstree’-like output for class-hierarchy:

I love it!

I know it’s a bit anally retentive :slight_smile: … but I prefer references like this in alphabetical order,
so I added a line:

def lstree(root)

get children of root

children = Hash.new()
ObjectSpace.each_object(Class) do |aClass|
if (root != aClass && aClass.ancestors.include?(root))
children[aClass.superclass] = Array.new() if children[aClass.superclass] == nil
children[aClass.superclass].push(aClass)
end
end

print nice ascii class inheritance tree

recursePrint = proc {|current_root,prefixString|
puts(prefixString+"- "+current_root.to_s)
if children[current_root] != nil
children[current_root].sort! {|a, b| a.to_s <=> b.to_s} # <---- THIS ONE

···
  children[current_root].each do |child|
      recursePrint.call(child,prefixString.tr('`',' ') + "    "+(child == children[current_root].last ? "`":"|"))
  end
end

}

recursePrint.call(root,“”)
end


I have always imagined that Paradise will be
a kind of library. - Jorge Luis Borges.

I'd like to see this function included in irb ?

Well, when you run irb, it read the file $HOME/.irbrc. Just put this
method in this file and it will be available the next time that you call
irb

Guy Decoux

No, it’s not; I meant to do that too but I forgot.

I’d like to evolve this little piece of code as a community; is there
anywhere I can post the code so that everyone can add his contribution ?
(I am thinking Wiki here)

Greetz,
Simon

PS: I’ve added printing of class methods.

···

On Wed, 23 Apr 2003 17:42:51 +0900, Harry Ohlsen harryo@qiqsolutions.com wrote:

I know it’s a bit anally retentive :slight_smile: … but I prefer references like this in alphabetical order,


There are 10 types of people in the world…
those who understand binary and those who don’t.

ts wrote:

“C” == Cedric Foll cedric.foll@ac-rouen.fr writes:

I’d like to see this function included in irb ?

Well, when you run irb, it read the file $HOME/.irbrc. Just put this
method in this file and it will be available the next time that you call
irb

Guy Decoux

Good idea.
Thanks.

Simon Vandemoortele wrote:

I’d like to evolve this little piece of code as a community; is there
anywhere I can post the code so that everyone can add his contribution ?

There was another post where someone has put it on the Wiki, so that’s sorted now.

However, not knowing anything about how to use a Wiki properly yet … I promise to read all about it on the weekend :slight_smile: … I’ll post a small patch here, that hopefully someone else can apply.

There’s a minor issue if you try to get a complete class listing, by doing “classtree(Object)”, because Object.superclass is nil. Here’s the original code:

  methods = (current_root.instance_methods - current_root.superclass.instance_methods).sort

and here’s my trivial change:

  methods = current_root.instance_methods

  if current_root.superclass
    methods -= current_root.superclass.instance_methods
  end

  methods.sort!

PS: I’ve added printing of class methods.

Yes, very nice! I’ve just printed out a complete class tree, with methods, to read on the train home.

Cheers,

Harry O.

···

On Wed, 23 Apr 2003 17:42:51 +0900, Harry Ohlsen harryo@qiqsolutions.com wrote:

The reaction to this trivial piece of code has been stronger than I
would have anticipated.
If you people really want class hierarchy overviews (to read on the train
home for example :slight_smile: ) wouldn’t you prefer a graphical printout ?
I know I would. I’m very excited about the possibility of automatic UML
generation from code (not interested in the reverse). With
www.graphviz.org and graphr (see RAA) this certainly seems within
reach. I even saw a one year old thread about possible inclusion in
rdoc (see RAA) but nothing seems to have come of it …

Are people still working on this ?

Simon

···

On Thu, 24 Apr 2003 08:21:03 +0900, Harry Ohlsen harryo@qiqsolutions.com wrote:

Yes, very nice! I’ve just printed out a complete class tree, with methods, to read on the train home.


There are 10 types of people in the world…
those who understand binary and those who don’t.

Simon Vandemoortele wrote:
aphviz.org and graphr (see RAA) this certainly seems within

reach. I even saw a one year old thread about possible inclusion in
rdoc (see RAA) but nothing seems to have come of it …

RDoc has done this for a while now.

The attached is something I knocked this morning during the first round
of discussions: it uses dot as you describe. Run with no parameter to
get the basic classes, and with -errors to get the error hierarchy:

ruby classes.rb [-errors] >classes.dot
dot -Tpng classes.dot >classes.png

Cheers

Dave


cl =
ObjectSpace.each_object(Module) do |c|
cl << c unless c.to_s =~ /^Errno::confused:
end

puts “digraph Ruby {”
puts " rankdir=LR;"

if ARGV[0] == “-errors”
cl.each do |c|
if c.kind_of?(Class) && (c <= Exception)# && c.superclass != Object
puts %{ “#{c.name}” → “#{c.superclass.name}”;} if c.superclass
c.included_modules.each do |m|
puts %{ “#{m.name}” [ fontcolor=blue, color=blue ];}
puts %{ “#{c.name}” → “#{m.name}” [ color=blue ] ;} unless m
== Kernel
end
end
end
else

cl.each do |c|
if c.kind_of?(Class) && !(c <= Exception) && c.superclass != Object
puts %{ “#{c.name}” → “#{c.superclass.name}”;} if c.superclass
end
c.included_modules.each do |m|
puts %{ “#{m.name}” [ fontcolor=blue, color=blue ];}
puts %{ “#{c.name}” → “#{m.name}” [ color=blue ] ;} unless m ==
Kernel
end
end
end

puts “}”

My mistake Dave … though you could be less modest and boast a little
more about this wonderful feature in the documentation because this is
really cool stuff if you ask me :slight_smile:

Happy Simon documenting away …

···

On Fri, 25 Apr 2003 09:13:34 +0900, Dave Thomas dave@pragprog.com wrote:

RDoc has done this for a while now.


There are 10 types of people in the world…
those who understand binary and those who don’t.