Ruby Object Model
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 ?
- Set
self
to the receiver. - Find out the
self
’s class. - 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.
- 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.