The object model

Ruby · Advanced · 16 min

Every piece of Ruby metaprogramming, and much Rails magic, follows directly from the object model.

In Ruby, classes are objects too: User is an instance of Class, which inherits from Module, which inherits from Object. Everything else follows from a few rules.

Method lookup: when you call obj.foo, Ruby looks in obj's singleton class, then its class, then each entry of obj.class.ancestors in order: prepended modules, the class, included modules (most recent first), the superclass, and so on up to Object, Kernel and BasicObject. The first match wins; super continues from there. If nothing is found, Ruby calls method_missing, which raises NoMethodError by default.

Singleton classes: every object can have its own hidden class holding methods for that object alone. def obj.shout or obj.extend(Mod) puts methods there. Class methods are simply singleton methods of the class object: def self.create inside class User defines create on User's singleton class. class << self opens that singleton class directly. Singleton classes of classes inherit from each other, which is why subclasses inherit class methods.

self changes with context: inside a class body it is the class, inside an instance method it is the instance. Calling a method without an explicit receiver sends it to self, and private methods can only be called that way.

Open classes let you reopen any class, even String, and add methods. This monkey patching is powerful and dangerous; prefer refinements or plain functions.

Example

module Greet
  def hi = "hi from Greet"
end

class Base
  def hi = "hi from Base"
end

class Child < Base
  include Greet
  def hi = "Child -> " + super
  def self.build = new        # singleton method of the Child object
end

p Child.ancestors.take(4)     # [Child, Greet, Base, Object]
puts Child.new.hi             # Child -> hi from Greet

obj = Child.build
def obj.hi = "only me"        # singleton method on one instance
puts obj.hi                   # only me
puts Child.new.hi             # Child -> hi from Greet
p obj.singleton_methods       # [:hi]

p Child.singleton_class.superclass   # #<Class:Base>
p Child.class, Class.superclass      # Class, Module

Remember

  • Lookup goes singleton class, then ancestors in order; first match wins
  • Class methods are singleton methods on the class object
  • Calls without a receiver go to self; private methods require that

Watch out for

  • Monkey patching core classes globally, causing conflicts between gems.

Check yourself

  1. Where does Ruby store a method defined with def self.find inside class User?

Sign in to answer, see the explanations, and get this lesson back as a quick review later.

Official docs: docs.ruby-lang.org/en/3.4/Class.html