Singleton Class

This idiom is used when you want to modify a given instance of a class (as opposed to all of the instances).

Core Idiom

It is best understood in two steps:

first, this part (i.e. minus the "self" in the middle:)

(class << some_object; ... ; end)

means: create a secret class for the object pointed to by "some_object". This is known as a "singleton class" or a "metaclass". It's a class without a name and "some_object" becomes an instance of that class.

But, because the new class has no name, we've got a problem… how do we reference it (we might want to do this to, say, add a new method to this new class)? We get the reference by including the `self` inside the class definition. When the whole expression executes, the "self" is the return value:

new_class = (class << some_object; self; end)  # value of this expression is the new class
new_class.to_s                                  # => something like "#<Class:#<Array:0x71c50>>"

Yehuda Katz' excellent explanation
Dave Thomas' "The Ruby Object Model and Metaprogramming"

A common use of this idiom is to inject some behavior before or after an existing implementation. This is achieved by aliasing the existing method and then providing the addtiional behavior:

  def Array.make_observable(array=[])
    return array if array.class.include?(Observable)  # assumes THIS is the only source of observation behavior.
 
    # see also: https://github.com/jtigger/kanban-simulator/wiki/idiom%3A-Singleton-Class
    arrays_metaclass = (class << array; self; end)
 
    arrays_metaclass.class_eval do
      include Observable
 
      alias_method :original_push, :push
      def push(item)    
        push_result = original_push(item)
 
        changed
        notify_observers({ :action => :push, :object => item })
 
        return push_result
      end
 
      alias_method "original_<<".to_sym, "<<".to_sym
      def <<(item)
        result = self.send("original_<<".to_sym, item)
 
        changed
        notify_observers({ :action => :push, :object => item })
 
        return result
      end
    end
 
    return array
  end
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License