This was the tip of the week in the August 12, 2021 Ruby Weekly Newsletter.


We’ll continue our brief Tip of the Week series around using code from a module by learning about prepend. Last week, we learned about include, and how it inserts a module into the ancestors chain directly after the class which includes it.

prepend uses the same syntax as include but works differently - it inserts a module into the ancestors chain directly before the class which includes it. Let’s take a look:

module ExampleModule
  def example_method
    "This is defined in the module we're prepending"
  end
end

class ExampleClass
  prepend ExampleModule
end

ExampleClass.new.example_method
=> "This is defined in the module we're prepending"

Now if we look at the ancestors chain, we’ll see that ExampleModule precedes ExampleClass. This is the exact opposite of what we saw last week with ExampleModule succeeding ExampleClass:

ExampleClass.ancestors
=> [ExampleModule, ExampleClass, Object, Kernel, BasicObject]

As we learned when [discussing ancestors][anc], this means that Ruby will first look for a method defined on ExampleModule, and if it’s not defined there, it will continue to traverse the list of ancestors, looking next at ExampleClass (our class itself).

This means using prepend will cause the methods defined on the module we’re prepending to trump methods defined on the class itself.

module ExampleModule
  def example_method
    "This is defined in ExampleModule, which we're prepending"
  end
end

class ExampleClass
  prepend ExampleModule

  def example_method
    "This is defined in ExampleClass itself"
  end
end

ExampleClass.new.example_method
=> "This is defined in ExampleModule, which we're prepending"

prepend is commonly used in cases where it makes sense for a module to override a method defined in a class. Examples of this might be when a module needs to set something up in the initialize method, but the initialize method of a class itself doesn’t call super. The initialize method in the module can do whatever setup it needs, and then call super to execute the class’ initialize method.

We’ll learn about extend next week!