Metaclass

In Ruby everything is an object, even Class (sort of, see reference).
Every object also has at least one meta-object lurks behind it. The meta-object serves as an easy way to intercept singleton-method overrides for the object.

A method is first looked up in the object’s metaclass, then the object’s parent class, then to parent class’ metaclass than to parent class’s parent class, and so on…
Note that meta-object is also an object, so itself can also contain an meta-object: the meta-meta-object.

Here is a set of useful methods when doing metaporgramming: code by _why

  class Object
    # The hidden singleton lurks behind everyone
    def metaclass; class << self; self; end; end
    def meta_eval &blk; metaclass.instance_eval &blk; end

    # Adds methods to a metaclass
    def meta_def( name, &blk )
      meta_eval { define_method name, &blk }
    end

    # Defines an instance method within a class
    def class_def( name, &blk )
      class_eval { define_method name, &blk }
    end
  end

Class Methods

Using self in Class Method

Be very careful when using private class method in public class method:

  class C
    def self.foo
      self.bar  # self.bar is same as C.bar which is illegal b/c we call private method on C
    end
  
    def self.baz
      bar
    end

    def self.bar
      'bar'
    end
    private_class_method :bar
  end

  C.foo # => NoMethodError: private method `poo' called for C:Class
  C.baz # => 'bar'

Singleton Methods

Ruby stores instance method definitions and class variables in “normal” class object, while overrides singleton class methods in Object’s metaclass (a.k.a. class’s meta-object).
Think of Ruby’s metaclass as “a class which an object uses to redefine itself.”

Assuming the above metaclass helpers have been defined:

  class A
    @class_instance_var = "a class instance variable"
    @@class_var = "a class variable"
  
    def self.instance_var
      @class_instance_var  # not accessible by subclass
    end
  
    def self.class_var 
      @@class_var   # accessible by subclasses
    end 
  
    def foo
      'an instance method'
    end
  end

  A.instance_var  # => "A class instance variable"
  A.class_var     # => "A class varaible"
  
  # note: Module#intance_methods only is only availabe in class objects since Class mixed in Module (but not Object).
  # class methods are defined in metaclass 
  A.metaclass.instance_methods.grep /class_var$|instance_var$/  # => ["instance_var", "class_var"]
  A.singleton_methods.grep /class_var$|instance_var$/           # => ["instance_var", "class_var"]
  A.instance_methods.grep /class_var$|instance_var$/            # => []
  
  a = A.new
  a.instance_methods                       # => Exceptions instance_methods undefined.
  A.instance_methods.grep /foo/            # => ["foo"]
  a.metaclass.instance_methods.grep /foo/  # => ["foo"]  # instance_methods is also kept in metaclass
  a.singleton_methods                      # => []

  # singleton_methods() is away to keep track of instance method added to the metaclass  
  def a.bar; 'bar'; end
  a.singleton_methods                      # => ['bar'], exists in singleton_methods
  a.metaclass.instance_methods.grep /bar/  # => ['bar'], as well as metaclass' instance_methods

Note:

  1. singleton_methods is can be used to keep track of methods added to the metaclass of an object.
  2. metaclass.instance_methods reads all available methods: including instance methods defined in class definitions.
  3. klass.metaclass.instance_methods == klass.public_methods (see below)

Bindings

Reference by Jim Weirich

In Ruby, bindings are explicitly made available in a Binding object. You can capture the current local variables Binding by calling Kernel#binding method.

Even though Ruby’s bindings are object, there’s no easy way to get/set variables in the a given binding. As a result, we must use the eval method in Kernel to access variables bind to the binding object:

  eval "a", vars      # evaluate the value of variable "a" in binding "vars"
  eval "a=1337", vars # assign the value 1337 to variable "a" in binding "vars" 

Bindings and Local Scope

Local variables can captured by calling binding. You can access any local variables by passing a reference of a binding context and calling eval on it:

  def foo( binding_context )
    a = "change a!"
    eval "a", binding_context  # eval will only refer to binding the one that's in binding_context
  end

  def goo
    a = 1337
    foo( binding )
  end

  goo  # 1337

You can also hold on to a binding long after its scope has gone out:

  def bind_me
    a, b = 2, 3
    binding
  end

  bind_me_vars = bind_me
  ## bind_me() is now out of scope
  eval "a", bind_me_vars       # => 2, "a" still exist in binding
  eval "b", bind_me_vars       # => 3, so is b
  eval "a=1337", bind_me_vars  # you can even give it a new value!  eval will return 1337
  eval "a", bind_me_vars       # => 1337

Blocks and Bindings

A block The block automatically captures and carries with it the bindings from the code location where it was created (created => block is also an object):

  def var_a
    a = "var_a"
    lambda { a }
  end

  def redef_var_a(block)
    a = "something other than var_a"
    block.call          # a is still "var_a" in block's binding/context
  end

  redef_var_a( var_a )  # => "var_a"

class_eval V.S. instance_eval

RDoc References:

Both class_eval and instance_eval takes either a string or a block and will evaluate it in the appropriate context. For more, see below.
It is also a good idea to include __FILE__ and __LINE__ to quick spot errors when doing metaprogramming: eval Anti-pattern

  eval("puts 'hello world'")
  # becomes
  eval("puts 'hello world'", binding, __FILE__, __LINE__)

  "str".instance_eval("puts self")
  # becomes
  "str".instance_eval("puts self", __FILE__, __LINE__)

  String.module_eval("A=1")
  # becomes
  String.module_eval("A=1", __FILE__, __LINE__)

Module#class_eval

  • Module#class_eval is an alias for Module#module_eval
  • Since they are instance methods of Module and Module is mixed into Class, class_eval is specific to Class only:
  class A; end
  A.new.class_eval   # => NoMethodError: undefined method `class_eval' for #<A:0x6e1220>
  • Ruby internally uses self and ruby_class decide where it can define method when it encounters keyword like def, alias reference
  • When class_eval is used on a class object to define a method, it will set self = obj, ruby_class = obj. This means that the method you defined is effectively defined as a instance method for the given class.
  class A; end
  A.class_eval do
    def foo; puts 'foo'; end
  end
  A.foo       # => NoMethodError
  A.new.foo   # => "foo"

Object#instance_eval

  • instance_eval is defined on Object, so it’s available on all objects, including class.
  • When instance_eval is used on a class object to define a method, it’ll set self = obj, ruby_class = metaclass. This means the method is a class method since it’s being defined on metaclass.
  class B; end
  B.instance_eval do
    def foo; puts 'foo'; end
  end
  B.foo       # => "foo"
  B.new.foo   # => NoMethodError

Metaprogramming Patterns

Dynamically Defined Methods

One useful pattern in Ruby metaprogramming is the use of dynamically generated methods.
Combined with metacass, Moduel#define_method enables us to generate customized methods for the subclasses of a given class:

  class MetaFactory
    def self.build *names
      names.each do |name|
        meta_def "build_me_a_#{name}" do # these methods will only defined in the class that calls build()
          "Here's a #{name}"   # You can do more here
        end
      end
    end 
  end

  class Factory < MetaFactory
    build :foo, :bar, :baz    # build_me_a_foo, build_me_a_bar, build_me_a_baz; only defined in Factory
  end

  Factory.build_me_a_foo      # => "You've got a foo", this only exist in Factory class

  Factory.metaclass.instance_methods.grep /foo/  # => ["build_me_a_foo"]
  Factory.public_methods.grep /foo/              # => ["build_me_a_foo"]
  Factory.public_methods.sort == Factory.metaclass.instance_methods.sort # => true

  # singleton_methods contains methods that has been injected into metaclass
  Factory.singleton_methods                      # => [..., "build", "build_me_a_foo"]

  # dynamically defined class method is not in parent class
  MetaFactory.build_me_a_foo                     # => NoMethodError

Note also meta_def is just a syntactical sugar to provide better code readability.
You can achieve the same effect by using Object#instance_eval on metaclass or Object#instance_eval on self:

  class MetaFactory
    def self.build *names
      names.each do |name|
        source_code = %Q{
          def build_me_a_#{name}
            "Here's a #{name}"
          end}
        instance_eval source_code   # implicit self => Subclass Factory (class method)
      end
    end
  end

  class Factory < MetaFactory; build :foo; end

  Factory.build_me_a_foo                         # => "You've got a foo".
  Factory.metaclass.instance_methods.grep /foo/  # => ["build_me_a_foo"]
  Factory.singleton_methods                      # => [..., "build", "build_me_a_foo"]

The above build method is not able to use Module#define_method because define_method is only used for defining instance methods, when called within the class context. So, the only way to use a define_method to define a class method is in the metaclass context.
For various ways to define a class method in Ruby see Jay Field’s “Ruby: Defining Class Methods”.