Posts tagged ‘ruby metaclasses’

November 25, 2008

A Complete Ruby Class Diagram

Although there are a few Ruby class-diagrams floating around the net I have yet to come across one that is complete. The following diagram was created while researching the behaviour of the Singleton Class and is complete in the sense that it shows the relationship between all classes and their super classes for a user-defined class in Ruby 1.8.6.

Legend: Hollow arrow-heads denote the ‘super class’ pointer and opaque arrow-heads denote the ‘class’ pointer. Blue ovals indicate regular classes and the grey their singleton classes.

The user-defined class depicted in the above diagram is created by the following code:

class A
end

class B < A
end

# create an instance of B
obj = B.new

# create a Singleton class for obj
class << obj; end

# create a meta-Singleton for B
class << B
    class << self
    end
end

Things to Note

  • obj’s class pointer is in fact set to its singleton class  (a fact concealed from us by the Object#class method).
  • A higher-level singleton class of B was created to showcase its strange properties. The singleton class of the singleton of B or ((B)) (to use a common notation) sets its class pointer to itself! (Go here to find out why).
  • I actually have the class diagram on the wall near my computer, it comes in very handy when doing tricky meta-programming ;)

Have a go

The above diagram cannot be navigated effectively using pure Ruby Object#class and Class#superclass methods (due to the special-case treatment of singleton classes by these methods).  To test the results given above you will need to use the following code: (you will also need RubyInline)

require 'rubygems'
require 'inline'

class Object
    inline do |builder|

        builder.c %{
            VALUE get_klass() {
                return CLASS_OF(self);
            }
        }

        builder.c %{
            VALUE set_klass(VALUE klass) {
                RBASIC(self)->klass = klass;
                return klass;
            }
        }

    end
end

class Class
    inline do |builder|

        builder.c %{            
            VALUE set_super(VALUE sup) {
                RCLASS(self)->super = sup;
                return sup;
            }
        }

        builder.c %{
            VALUE get_super() {
                return RCLASS(self)->super;
            }
        }

    end
end
Follow

Get every new post delivered to your Inbox.