Ruby Object Model
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
The ancestors
method returns a 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 parent's class
- the parent class of its parent class
- etc…
Here is an example of the ancestor chain of the Array
class
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
=> Object
irb> Array.superclass.included_modules # parent's included modules
=> [Kernel]
irb> Array.superclass.superclass # the grandparent class
=> BasicObject
Array::included_modules
returns an array that contains all the modules included in the ancestor chain.
This is why Kernel
is included in the array for Array.included_modules
.
Ancestor Chain and Method Call
When you call a method inside of your object, what Ruby does is first check if this method exists inside the context ofself
.
If it doesn't find it there, it continues up the ancestor chain until it finds the method.
class Tiger
def to_s
"roar"
end
endirb> Tiger.new.to_s
=> "roar" # calls the #to_s method defined in the Tiger class
irb> Tiger.inspect
=> "#<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 inherits Object
by default
class Child
endChild.superclass
=> Object
So, what’s the purpose of this class?
If we call the ancestors
method on Object
it’ll return the following ancestor chain
irb> Object.ancestors
=> [Object, Kernel, BasicObject]
BasicObject
The BasicObject
class is the top parent of all classes. It contains a bare minimum of methods for object creation and object comparison.
Kernel
The Kernel module is included in the Object class. It contains all the “object manipulation” logic.
Object
AsKernel
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 Object
class. 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 Matz loves C)
irb> self
=> main
irb> self.class
=> Object
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 main
context
irb> puts "main context"
=> main context
Here, the puts
method refers to the private Kernel#puts
method. We have access to this method because main
is an instance of Object
which includes Kernel
.
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).
Calling 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 if it is a public one.
Conclusion
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 main
object.
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 :)
Ruby Mastery
We’re currently finalizing our first online course: Ruby Mastery.
Join the list for an exclusive release alert! 🔔
Also, you can follow us on x.com as we’re very active on this platform. Indeed, we post elaborate code examples every day.
💚