return to list of articles

Understanding Ruby's module prepend and include

Ruby 2.0 allows you to change how methods work, in a much better way.

Overview

Any time that a Ruby class includes a module, that module is appended to that class’ hierarchy which has implications for its lookup order. Before Ruby 2.0 there was no elegant way of prepending that module without having to resort to hacks like alias_method_chain where you would have ugly method names like #original_with_addition and #original_without_addition. Now with Ruby 2.0 there is a neat solution to this.

Example

Your class can now both prepend as well as include a module into its hierarchy without you having to explicitly do class evals. To help understand how it works, we summon the all-knowing Kanye to help us out:

class Kanye
  def announcement
    puts "I totes love Jay Z and Beyoncé"
  end
end

Kanye.new.announcement

We have a simple class with an announcement method. When called, Kanye professes his love for his two idols.

I totes love Jay Z and Beyoncé

Now let’s imagine the very unlikely scenario wherein Kanye would be a bit rude. Instead of writing a whole new class from scratch, we can utilize Ruby’s amazing powers of inheritance and we’ll inherit from our original Kayne.

class RudeKanye < Kanye
  def announcement
    puts "Beyoncé had one of the best videos of all time!"
    super
  end
end

RudeKanye.new.announcement

Now when rude Kanye orates magnificently, the result will be:

Beyoncé had one of the best videos of all time!
I totes love Jay Z and Beyoncé

He can express his opinions, and thanks to super he can also express his invaluable original idea too. But what if Kayne had even more to say? I know, it’s highly unlikely, but because we can’t rule anything out, we’ll have to develop a solution for him. That solution is using Ruby’s prepend and include methods. We create two modules with some more wisdom nuggets:

module RudeAnnouncementExtra
  def announcement
    puts "One of the best videos of all time!"
    super
  end
end

module RudeAnnouncementIntro
  def announcement
    puts "Yo, Taylor, I'm really happy for you, I'ma let you finish, but..."
    super
  end
end

Then we add these modules into the RudeKanye’s class using the following. Note that both methods are now public methods so you can simply call them like:

RudeKanye.include(RudeAnnouncementExtra)
RudeKanye.prepend(RudeAnnouncementIntro)

Now when rude Kanye makes an announcement:

RudeKanye.new.announcement

The result is:

Yo, Taylor, I'm really happy for you, I'ma let you finish, but...
Beyoncé had one of the best videos of all time!
One of the best videos of all time!
I totes love Jay Z and Beyoncé

Thanks to Ruby, people can have as many opinions as they want and we don’t have to duck punch our code to make that happen.


Get notified when Pawel releases new posts, guides, or projects