Advanced Ruby - Object Model

Question Click to View Answer

What does the following code print? Explain.

class Pencil; end
p Pencil.class
Class

All class objects (objects that can be used to instantiate other objects) are instances of the Class class. Hash.class, Array.class, String.class, and Pencil.class all return Class.

What does the following code print? Explain.

class CompactDisc; end
cd = CompactDisc.new
p cd.class
CompactDisc

The cd object is an instance of the CompactDisc class.

What does the following code print? Explain.

Class.class
Class

Paradoxically, the Class object is an instance of itself. There are a few paradoxes in the Ruby object model that cannot be explained with the Ruby programming language. The language designer set up Ruby with certain paradoxes and it's best to simply accept these at face value.

What does the following code print? Explain.

class Blink; end
p Blink.superclass
Object

All user defined classes inherit from Object by default.

What does the following code print? Explain.

p BasicObject.superclass
nil

Every class object (i.e. instance of the Class class) has a superclass, except for BasicObject. BasicObject is at the top of the class hierarchy and does not have a superclass.

What does the following code print? Explain.

p BasicObject.singleton_class.superclass
Class

BasicObject's singleton class inherits from Class.

What does the following code print? Explain.

class Seltzer
  private
  def bubbles; end
end

a_can = Seltzer.new
p a_can.bubbles

This code raises the following exception: NoMethodError: private method `bubbles' called for #Seltzer:0x007f9783ad0cb0

Private methods cannot be called with an explicit receiver. a_can is an explicit receiver in this example, so the code raises an exception.

What does the following code print? Explain.

class Surfer
  def speak
    "My hair is #{self.hair}"
  end

  private

  def hair
    'golden'
  end
end

dude = Surfer.new
p dude.speak

This code raises the following exception: NoMethodError: private method `hair' called for #Surfer:0x007f97840f2558

Private methods cannot be called, even if the explicit receiver is self. In the Surfer#speak method, self.hair cannot be used, it must be only hair() without an explicit receiver.

What does the following code print? Explain.

class Pig
  protected
  def sound
    'oink!'
  end
end

piggy = Pig.new
p piggy.sound

This code raises the following exception: NoMethodError: protected method `sound' called for #Pig:0x007ff24ab73d58

Similar to private methods, protected methods cannot be called with an explicit receiver.

What does the following code print? Explain.

class Fido
  def angry
    self.sound * 3
  end

  protected

  def sound
    'woof'
  end
end

p Fido.new.angry
'woofwoofwoof'

Notice that this code does not raise an exception. Protected methods can be called with an explicit receiver, but only if the explicit receiver is self (in other words, only when the explicit receiver is not necessary). Matz regrets introducing the protected keyword, so it's best to just use private.

What does the following code print? Explain.

class IceCream
  @temp = 'cold'
end

p IceCream.instance_variables
[:@temp]

Instance variables are bound to objects. Unless specified otherwise, instance variables are bound to self. self is a keyword that points to different objects based on the context of the program. self points to the IceCream object when the @temp instance variable is defined, so the @temp instance variable is bound to the IceCream object.

What does the following code print? Explain.

class Soccer
  @fun = 'woo hoo'
  def initialize
    @goal = 'score'
  end
end

s = Soccer.new
p s.instance_variables
[:@goal]

The @goal instance variable is bound to instances of the Soccer class. The @fun instance variable is bound to the Soccer class object itself, not instances of the Soccer class.

What does the following code print? Explain.

h = {}
class Sublime
  @fav = 'caress me down'
  def sing(obj)
    obj.instance_variable_set(:@greeting, 'mucho gusto')
    obj.instance_variable_set(:@name, 'me llamo brad lee')
  end
end

s = Sublime.new
s.sing(h)
p s.instance_variables
p "***"
p h.instance_variables
[]
"***"
[:@greeting, :@name]

In this example, the instance variables are bound to a specific object and are not bound to self by default.