Ruby Object Model

Yask Srivastava
3 min readFeb 19, 2018

--

I was super new to Ruby and the Rails magic scared the shit out of me. Understanding how objects work in Ruby
was crucial to writing good software.

Weird thing about ruby is that the object can adopt behaviors that are not defined by their classes, which is the central defining principal
in Ruby programming language. It’ll make a lot of sense once we understand how objects work here.

Let’s get started.

Every object in ruby needs to know how to respond to the message sent to it.

class Person
def initialize(name)
@name = name
end
def speak
p “#{@name} says hello”
end
end

The instructions on how to respond to the message is defined in the object’s class.

For example, when we run



yask = Person.new(“Yask”)
yask.speak
>> “Yask says hello”

How method look up works ?

1. Set `self` to the receiver.
2. Find out the `self`’s class.
3. Search for the method defination in that class.
* If it’s not found there, move to the parent of this class.
Keep repeating this step untill the method is found.
* Execute the method once found.
4. If the method was not found, start looking for `missing_method`.

Beautiful thing about this 4 step process is that this method is universal for *any* object.

Since class is an Object in Ruby too, it follows the same process.

How class method works ?

They work exactly the same way.

Eg:

Person.object_id

The method `object_id` is looked up in the following classes :

`self` = Person


Person.class.ancestors
#> [Class, Module, Object, Kernel, BasicObject]

Don’t believe me ?


class Module
def object_id
p ‘how about now ?’
end
end
Person.object_id#> ‘how about now ?’

Singleton / Eigen / Metaclasses

This is a nameless class which we can attach in between any object’s class chain.

Eg: If the object chain looks like this:


String.class.ancestors
#> [Class, Module, Object, Kernel, BasicObject]

After adding the Eigen class it would be :

#> [NamelessEigenClass, Class, Module, Object, Kernel, BasicObject]

So if we wanted to add a function to the class `String`, we can add it to the EigenClass.

To do that:

class String
class << self
def my_custom_method
#do_something
end
end
end

Now we can execute:

String.my_custom_method

If we follow the steps for how method look up works, it makes sense.

`self` = String

`self.class` = `Class`

After we created the Eigen class the object chain looked like :
`[NamelessEigenClass, Class, Module, Object, Kernel, BasicObject]`

And it found the `my_custom_method` at `NamelessEigenClass`.

Inheritence

What happens when we inherit from a parent class which opens up an Eigen class
and defines some methods there ?

Like, inheriting class methods from the parent class. How does that work ?


class Parent
class << self
def speak
p ‘hello world’
end
end
end
class Child < Parent
end

As you can guess `Child.speak` works, but how ?

We never defined the eigen class in Child, and in the process of method look ups
ruby would look at `Child.class` which is `Class` (and it’s parents).

Since we never defined singleton class for it, it shouldn’t be able to search
for it.

But intrestingly, when we inherit from a parent class, the child class’s Eigen
class also inherits from it’s Parent’s eigen class.

We can prove this:


Child.singleton_class.superclass
#> #<Class:Parent>
Child.singleton_class.instance_methods.detect &:hello.method(:==)
#> :speak

Isn’t that cool ?

Method looks ups are super simple and there is one and only one rule of them.
No exceptions.

--

--