Advanced Ruby - Singleton classes and methods

Question Click to View Answer

Which class defines the Dog.about method? Demonstrate that this class includes the about method.

class Dog
  def self.about
    'we bark'
  end
end
Dog.about # a singleton method that's defined in Dog's singleton class:
Dog.singleton_class.instance_methods.include? :about # => true

Every Ruby object has a singleton class to store methods for a particular object.

Add a method called my_singleton_class to the Object class that returns the singleton class of an object. Don't use the built in singleton_class method.

class Object
  def my_singleton_class
    class << self
      self
    end
  end
end

# Check the code works
Hash.my_singleton_class == Hash.singleton_class # => true

The 'class << obj' syntax changes the scope to the obj's singleton class. In this case self equals Object, so class << self changes the scope to Object's singleton class.

What does the following code print? Explain.

class NewYork
  class << self
    def greeting
      "how you doin'?"
    end
  end
end

p NewYork.greeting
"how you doin'?"

The class << self syntax is used to access the scope of the NewYork singleton_class. Once inside the scope of the singleton_class, instance methods are the same as singleton_methods:

NewYork.singleton_methods # => [:greeting]

What does the following code print? Explain.

class Human
  def Human.about; end
  def self.generation; end
  def hi; end
  instance_eval do
    def bye; end
  end
end

p Human.singleton_methods
[:about, :generation, :bye]

There are several ways to define singleton methods. Notice that the Human#hi method is a regular instance method and is not a singleton method.

Use the following code to demonstrate that singleton methods are the same as instance methods of the singleton class.

class India
  class << self
    def info
      "awesome country!"
    end
  end
end
India.singleton_methods == India.singleton_class.instance_methods(false) # => true

When false is passed as an argument to the instance_methods() method, it does not return any inherited methods.

Describe the method lookup process for the following code.

class Ghost; end
casper = Ghost.new
casper.boo

casper is an instance of the Ghost class and is the receiver of the message :boo in this example. The receiver first looks in its singleton_class for a method named :boo (the singleton class for the receiver is casper.singleton_class). If it does not find a method, it will continue up the ancestor chain to look for the method.

Here is the ancestor chain for this example:

ghost.class.ancestors # => [Casper, Object, Kernel, BasicObject].  If there are no classes that respond to the message, then method_missing is called.

Describe the method lookup process for the following code.

class Alpha; end
Alpha.profit

In this example, the :profit message is sent to the receiver, Alpha. Alpha looks for methods corresponding to the :profit message in the following order: Alpha's singleton class, Object's singleton class, BasicObject's singleton class, Class, Module, Object, Kernel and finally BasicObject. method_missing is called if no methods correspond with the :profit message.

The ancestors method can be used to view the method lookup path when the receiver is a class object:

Alpha.singleton_class.ancestors
# => [#<Class:Alpha>, #<Class:Object>, #<Class:BasicObject>, Class, Module, Object, Kernel, BasicObject]

What is the superclass of BasicObject's singleton class?

Class

BasicObject.singleton_class.superclass # => Class

The superclass of BasicObject is nil and it's important to notice that the superclass of BasicObject's singleton class is not nil.

Explain the following statement: "Ruby does not have static class methods like some other programming languages."

Ruby has singleton methods that function similarly to 'class' or 'static' methods in languages like Java, but the implementation is different. Ruby's 'class methods' are really just instance methods defined in the singleton class. Ruby doesn't have static methods like Java.