In this section, we will learn how to use modules and class inheritance together in Ruby.
Note: we’re assuming you’re already familiar with Ruby Modules.
Order of Execution in Ruby Classes with Modules and Parent Class
When including a module into the body of a class (mixin) and that class has inherited from another class as well, one question that might pop up is that what’s the order of execution in such scenario then?
Well, the answer is, your modules comes between the parent class and the child class!
For example, let’s say we have a class name `A` and it’s the parent class of the class `B`. Now the class B here included a module named `MyModule` into its body.
Here, if we create an object from the class B and call a method on top of it, this will be the order of execution:
- Your program will first check the body of the class B to see if it has the specified method or not.
- If the method was in the body of the class B then it is invoked. Otherwise, your program will move on to the body of the `MyModule` to search that module for the specified method.
Note that the super class A is not searched yet! This means modules have higher precedence compared to parent classes! And so they will be searched first.
Now, if the modules also didn’t have the specified method, then in that case your program will start to search the body of the parent classes.
Note: if you have multiple modules in the body of a class, they all will be searched for the specified method.
Example: using modules and inheritance in a Ruby class
class Human def print_name puts "Hello from Human class" end end module PrintFullName def print_name puts first_name, last_name, age, id end end class Person < Human include PrintFullName attr_accessor :first_name, :last_name, :age, :id def initialize (first_name, last_name, age, id) self.first_name = first_name self.last_name = last_name self.age = age self.id = id end end prs = Person.new("John","Doe",100, 43221) prs.print_name
Output:
John Doe 100 43221
You can see that the `Person` class is inheriting from `Human` class as well as mixed in the `PrintFullName` module.
The Human class and PrintFullName` module both have a method named `print_name`.
So now when we call the method using the `prs` object, first the body of the Person class is searched, after that comes to the `PrintFullName` module (because the Person class didn’t have the mentioned method) and now because the module has the method then it is invoked and no call to the parent class (Human) will be made in this example.
Ruby ancestors Method
If you’re interested to see the order of search for a method on a class, there’s a method named `ancestors` which will return the list of classes and modules and their priorities on which your program will search them first for the target method.
Simply call this method on top of the target class and you’ll get the list back.
Example: using ancestors method in Ruby
class Human def print_name puts "Hello from Human class" end end module PrintFullName def print_name puts first_name, last_name, age, id end end class Person < Human include PrintFullName attr_accessor :first_name, :last_name, :age, :id def initialize (first_name, last_name, age, id) self.first_name = first_name self.last_name = last_name self.age = age self.id = id end end prs = Person.new("John","Doe",100, 43221) puts Person.ancestors
Output:
Person PrintFullName Human Object Kernel BasicObject