My Ruby newsletter is available here. Feel free to subscribe :-)
Ruby Object Model - Part 1
Ruby is a fully object-oriented programming language. But what does that really mean ?
In this series of articles, we’ll try to demystify the Ruby Object Model.
The Ancestor Chain
ancestors method returns an
Array that represents the ancestor chain.
The ancestor chain is the representation of the class hierarchy in Ruby.
In order, it contains:
- The calling class
- its included modules
- its parent class
- the included modules of its parents class
- the parent class of its parent class
Here is an example of the ancestor chain of the
irb> Array.ancestors # Array's ancestor chain
=> [Array, Enumerable, Object, Kernel, BasicObject]
irb> Array.included_modules # Array included modules
=> [Enumerable, Kernel]
irb> Array.superclass # the parent class
irb> Array.superclass.included_modules # parent's included modules
irb> Array.superclass.superclass # the grandparent class
Array::included_modules returns an array that contains all the modules included in the ancestor chain. This is why the
Kernel module is included in the array for
Ancestor Chain and Method Call
When you call a method inside of your object, what Ruby does is to first check if this method exists inside the
self context. If it doesn't find it there, it continues up the ancestor chain until it finds the method.
=> "roar" # calls the #to_s method defined in the Tiger class
=> "#<Tiger:0x007f>" # calls the #inspect method defined in Object
Object class hierarchy
Object is the default root class in Ruby. This means that any new class inherit from object by default
So, what’s the purpose of this class ?
If we call the
ancestors method on
Object it’ll return the following ancestor chain
=> [Object, Kernel, BasicObject]
BasicObject class is the top parent of all class. It contains a bare minimum of methods for object creation and object comparison.
The Kernel module is included in the Object class. It contains all the “object manipulation” logic.
Kernel module contains the majority of the methods,
Object is more used as an interface (for its name) by all its children.
The main object
When a new program starts, Ruby automatically creates the
main object which is an instance of the
main is the top-level context of any program. This is probably a nod to the C language (as the
main() function is the entry point of any C program and that Matz loves C)
main is the top-level scope of any ruby program. This means that any instruction out of a class/module scope is executed in the
irb> puts "main context"
=> main context
puts method refers to the private
Kernel#puts method. We have access to this method because
main is an instance of
Object which includes
Now, let’s explicitly try to access the
puts method via
self (which refers to the
main object instance).
irb> self.puts "main context"
NoMethodError: private method `puts' called for main:Object
This error is due to the fact that a private method cannot be called with a receiver (
self in this case).
self.puts is like calling
main.puts . So, We try to call
puts outside of its class context.
In other words, we try to call a private method as a public one.
Ruby is a fully oriented-object language because from the entry point (the
main context) to the end of your program you’ll be scoped at least in the
Next article: If you don’t know that
Module is an instance of the
Class class, stored in a constant and whose instances cannot be instantiated then you’ll probably learn something :)
Thank you for taking the time to read this post :-)
Feel free to 👏 and share this Medium post if it has been useful for you.
Here is a link to my last medium post:
2 quick tips for IRB.