To be able to understand this article about ruby metaclasses, you need to have in mind some basics of the Ruby language.
Discovering the existence of metaclasses
Ruby allows you to define methods on any object:
o = Object.new
def o.hello
"Hello !"
end
puts o.hello #=> "Hello !"
puts Object.new.hello #=> undefined method `hello'
Here we defined the method hello only for the instance ’o’ of Object. Any other instance of Object will not have this method.
How is that possible since only Class objects can have methods? In fact, Ruby has a internal mechanism that creates a "metaclass" to store these object specific methods.
What is a metaclass exactly?
If I were forced to define what a metaclass is, I would say that it’s a hidden class attached to a particular object:
It is a class: it contains methods
It is hidden: metaclasses are more or less part of Ruby’s black magic and it is not so simple to access/manipulate these. We’ll come back to this later.
It is specific to an object: each object has its own metaclass.
There is a very peculiar way to get to a metaclass’ context:
class Foo
class << self
# At this point we are in the context of Foo's metaclass
puts self
end
end #=> #<Class:Foo>
The special result #<Class:Foo> is specific to metaclasses. This syntax means: "I am an instance of Class attached to Foo."
From the previous example, we can define a generic method on the Object class to access the metaclass of any object:
class Object
def meta
class << self
self
end
end
end
We can then write:
class Foo
end
puts Foo.meta #=> #<Class:Foo>
puts Foo.new.meta #=> #<Class:#<Foo:0xb7cb19cc>>
Notice that the metaclass of an instance of Foo is specific to this instance #<Foo:0xb7cb19cc>.
Defining methods on metaclasses
Let’s check what has been said before: metaclasses store the methods of its attached object:
class Foo
end
f = Foo.new
def f.hello
puts "Hello !"
end
f.hello #=> Hello !
puts f.meta.instance_methods.include?("hello") #=> true
puts f.singleton_methods.include?("hello") #=> true
The method directly defined on the object is stored in its metaclass. Another way to do the exact same thing would be to define the method in the metaclass’ context:
class Foo
end
f = Foo.new
class << f
def hello
puts "Hello !"
end
end
f.hello #=> Hello !
puts f.meta.instance_methods.include?("hello") #=> true
puts f.singleton_methods.include?("hello") #=> true
Same thing here, we defined the method directly on the object metaclass. Same result: the method is available for this object only.
As you know, classes are themselves instances (of Class), so they have their own metaclass as well. It is possible to use their metaclass to define methods on them:
class Foo
def self.hello
puts "Hello !"
end
end
Foo.hello #=> Hello !
puts Foo.meta.instance_methods.include?("hello") #=> true
puts Foo.singleton_methods.include?("hello") #=> true
Do you recognize it? It is the usual way to write a class method!
You could also write:
class Foo
end
class << Foo
def hello
puts "Hello !"
end
end
Foo.hello #=> Hello !
puts Foo.meta.instance_methods.include?("hello") #=> true
puts Foo.singleton_methods.include?("hello") #=> true
It is equivalent.
Unified behavior
The management of the classes in Ruby is similar to the management of any other object. This is an attractive feature of Ruby. Classes store the methods for their instances, and if you want these classes to have methods too, you just do the same thing with their metaclass.
The Object class define the method singleton_methods. It returns a list of the methods that can be called on an object (Module, Class or regular Object).
Matz’s Ruby Interpreter (MRI)
The C implementation of Matz’s Ruby Interpreter defines 3 basic structures:
struct RBasic {
unsigned long flags;
VALUE klass;
};
struct RObject {
struct RBasic basic;
struct st_table *iv_tbl;
};
struct RClass {
struct RBasic basic;
struct st_table *iv_tbl;
struct st_table *m_tbl;
VALUE super;
};
A Ruby Object is a RObject, containing:
a reference to a RClass: value klass
state flags: unsigned long flags ( designed to store information like taint, freeze, etc. )
a map of the instance variables: struct st_table *iv_tbl
A Ruby Class is a RClass, containing:
a reference to a RClass, state flags and instance variables like an Object. This is the reason why we consider that a Ruby class can be seen as an object.
a map of the methods: struct st_table *m_tbl
a reference to a RClass "super" pointing to the superclass: VALUE super
Important note about the relationship of these C structures:
For a given RClass rc, the super RClass of the klass of rc is the klass of the super RClass of rc.
I know it sounds complicated but consider this example:
class Foo
end
class Bar < Foo
end
The RObjects and RClasses at work here can be represented like this:

the klass of the super RClass of Bar is: Foo’s metaclass
the super RClass of the klass of Bar is: Foo’s metaclass
It’s just how it has been coded. This is hidden from Ruby:
class Foo
end
class Bar < Foo
end
puts Bar.meta.superclass #=> #<Class:Class>
puts Bar.superclass.meta #=> #<Class:Foo>
Ruby considers that any metaclass’ superclass is the metaclass of Class.
Search order for a method
When you call a method on an object, where does Ruby search for this method?
Well here is how it works:
The search begins in the methods of the RClass of this RObject
From there it will search up all of its super RClasses until it finds the method
So for the previous example with Bar < Foo, a call like Bar.new.hello would follow this path to find the method ’hello’:
search in Bar
search in Foo
search in Object
This ensures the inheritance of instance methods.
The same way, a call to Bar.hello would follow this path:
search in Bar.meta
search in Foo.meta
search in Object.meta
search in Class
This ensures the inheritance of class methods.
Open classes
A class definition is never sealed in Ruby. They remain "open":
class Foo
def self.load_hello
def hello
puts "Hello !"
end
end
end
begin
Foo.new.hello #=> dynamic_methods.rb:9: undefined method `hello' for ...
rescue
Foo.load_hello
Foo.new.hello #=> Hello !
end
The method hello has been loaded dynamically.
Extending classes
There is a widely accepted way to extend an existing model in the Ruby community.
Let’s create a simple acts_as_* module. Let’s make a "acts_as_taggable" to associate a tag to an object. The tag will contain anything you want. It will be basically similar to the behavior of attr_accessor.
A way to do that is to add this capability on the super class (like ActiveRecord does), and then call the feature in a subclass.
model.rb:
require 'acts_as_taggable'
class MyBase
include Acts::Taggable
end
class Foo < MyBase
acts_as_taggable :info
end
class Bar < MyBase
acts_as_taggable :comment
end
The file ’acts_as_taggble.rb’ will contain the definition of the module Acts::Taggable:
module Acts
module Taggable
def self.included(base)
puts self #=> Displays Acts::Taggable
# adds ClassMethods instance methods to the class object 'base'
base.extend(ClassMethods)
end
module ClassMethods
def acts_as_taggable( name )
puts self #=> Displays Foo, then Bar
end
end
end
When the module will be included by MyBase, the method "included" will be invoked on the Acts::Taggable module (self) with the including class as a parameter (base).
With this parameter (base=MyBase) of type Class, we are going to add the methods of another module, usually called "ClassMethods". In our case, act_as_taggable will be added to MyBase’s singleton_methods (so they will be class methods).
This acts_as_taggable method will be used in the context of the caller. "self" will represent the class that will actually use act_as_taggable (Foo, Bar), not the module nor the superclass (MyBase).
The job of act_as_taggable when actually invoked is to dynamically define a getter and a setter method on the class:
module Acts
module Taggable
def self.included(base)
# adds ClassMethods instance methods to the class object 'base'
base.extend(ClassMethods)
end
module ClassMethods
def acts_as_taggable( name )
class_eval <<-END_CE
def #{name}=(t)
@tag=t
end
def #{name}
@tag
end
END_CE
end
end
end
end
The class_eval method will define the info et info= methods on Foo, and comment et comment= on Bar. Those are the accessor methods for the instance variable @tag.
require 'model'
f = Foo.new
f.info = "This class is beautiful !"
b = Bar.new
b.comment = "I'm just another class"
puts f.info #=> "This class is beautiful !"
puts b.comment #=> "I'm just another class"
Voila
We are done for now. I hope some of you found some answers and/or questions in this article :) See you soon!
Resources
An infoQ conference by Dave Thomas about Ruby metaprogramming basics
An article about Ruby metaclasses and why they are useful
An article by Patrick Farley explaining the different implementations of the MRI
The Ruby hacker guide chapter 4 about the MRI implementation
A screencast by Dave Thomas