Singleton Class

Posted . Visible to the public.

We’ll start with a cow named cletus. Cows are ruminant animals. And ruminants are all part of the broader family of ungulates . Today’s topic isn’t actually about mammal taxonomy, though. Our real focus is on how objects find their methods. So we’re going to write a special method to help us with this task. We call it where, and it will take an object and a method name as arguments. Inside, it looks through the object’s class ancestors until it finds the nearest ancestor to defined the given method. With our tools defined, let’s put Cletus through his paces. Cletus can speak, and when he does, he moos. Cletus get this behavior from the fact that he is a Cow. When Cletus rests, he chews his cud. That’s because cows are Ruminant mammals. And when he eats, he grazes. This is fairly typical of ungulates, a group that also includes horses, deer, and giraffes.

class Ungulate
  def eat
    "graze graze graze"
  end
end

class Ruminant < Ungulate
  def rest
    "chew chew chew"
  end
end

class Cow < Ruminant
  def speak
    "moo"
  end
end

require "./classes"

def where(obj, method)
  obj.singleton_class.ancestors.detect do |klass|
    klass.instance_methods(false).include?(method)
  end
end

cletus = Cow.new
cletus.speak                    # => "moo"
where(cletus, :speak)           # => Cow
cletus.rest                     # => "chew chew chew"
where(cletus, :rest)            # => Ruminant
cletus.eat                      # => "graze graze graze"
where(cletus, :eat)             # => Ungulate
 
def cletus.dance
  "tappety tappety tap"
end
 
cletus.dance
# => "tappety tappety tap"

where(cletus, :dance)           # => #<Class:#<Cow:0x0055c1fb9c05c8>>

Cow.new.singleton_class.ancestors
# => [#<Class:#<Cow:0x0055978f993a78>>,
#     Cow,
#     Ruminant,
#     Ungulate,
#     Object,
#     PP::ObjectMixin,
#     Kernel,
#     BasicObject]

In Ruby, method lookup follows a simple and consistent rule. An object’s method definitions are found via its class inheritance chain. Always. In order for objects to be able to have individual method definitions, they have a singleton class that’s unique to them, and that singleton class is the first place Ruby looks for a method definition.

Alexander M
Last edit
Alexander M
Posted by Alexander M to Ruby and RoR knowledge base (2016-11-03 14:50)