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.

I had been most primarily writing python and had adopted to the python’s way of doing things. I had built apps using web2py for learning web development, writing most things from scratch. I then went on to develop web services using more advanced frameworks, like flask, django and started contributing to some open source websites like moin moin wiki engine.

Jumping to a rails code wasn’t easy for me. I didn’t understand magical things rails did under the hood. It felt like a nice frameworks for small projects, but at work we had been using for massive web services. With bigger projects you have bigger requirements, and yes, bigger complexity.

Here I just wanted to write about learning one concept in Ruby that made a huge difference. Yep, it’s about how ruby does objects.

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 definition in that class.
    • If it’s not found there, move to the parent of this class. Keep repeating this step until 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

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 should’t be able to search for it.

But interestingly, when we inherit from a parent class, the child class’s Eigen class also inherits from it’s Parent’s eignen 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.