This was the tip of the week in the August 5, 2021 Ruby Weekly Newsletter.
In last week’s tip, we learned about ancestors. This set us up to learn about three ways of using code from a module in a class. This week, we’ll discuss what is likely the most common of these approaches:
We can look at an example of using
include to include a module’s methods in a class:
module ExampleModule def example_method "This is defined in the module we're including" end end class ExampleClass include ExampleModule end ExampleClass.new.example_method => "This is defined in the module we're including"
What is actually happening when we
include ExampleModule, or
include any module or class, is that this module or class will be inserted in the ancestors chain directly after the class which
ExampleClass.ancestors => [ExampleClass, ExampleModule, Object, Kernel, BasicObject]
As we learned last week, this means that Ruby will first look for a method defined on
ExampleClass, and if it’s not defined there, it will continue to traverse the list of ancestors, looking next at
This means using
include gives us the helpful property of being able to easily override methods defined in an included module:
module ExampleModule def example_method "This is defined in the module we're including" end end class ExampleClass include ExampleModule def example_method "This is defined in ExampleClass itself" end end ExampleClass.new.example_method => "This is defined in ExampleClass itself"
If we’re used to using
include, we might have an intuitive understanding of this overriding in action. Hopefully now with the context around
ancestors, we can see why it’s happening. In the coming weeks, we’ll have tips around two other ways of using code from modules or classes: