Include, extend and prepend in Ruby

There are three ways to add methods from a module to a class in Ruby.

Include

It adds methods as instance methods

module Swimmable
  def swim
    "I can swim!"
  end
end
 
class Fish
  include Swimmable
end
 
fish = Fish.new
puts fish.swim # => "I can swim!"
puts Fish.ancestors # => [Fish, Swimmable, Object, Kernel, BasicObject]

Extend

It adds methods as class methods

module Flyable
  def fly
    "I can fly!"
  end
end
 
class Bird
  extend Flyable
end
 
puts Bird.fly # => "I can fly!"
puts Bird.ancestors # => [Bird, Object, Kernel, BasicObject]

Prepend

It adds methods as instance methods but with higher precedence.

module Logger
  def log_action
    "Logged: #{super}"
  end
end
 
class Action
  prepend Logger
 
  def log_action
    "Some action"
  end
end
 
action = Action.new
puts action.log_action # => "Logged: Some action"
puts Action.ancestors # => [Logger, Action, Object, Kernel, BasicObject]

Normally, prepend is defined at the end of the class definition.

You can also prepend a module outside the class definition

Action.prepend(Logger)

Consecutive prepends

module Formatter
  def display
    "Formatted: #{super}"
  end
end
 
module Validator
  def display
    "Validated: #{super}"
  end
end
 
class Report
  prepend Formatter
  prepend Validator
 
  def display
    "Report content"
  end
end
 
report = Report.new
puts report.display # => "Validated: Formatted: Report content"
puts Report.ancestors # => [Validator, Formatter, Report, Object, Kernel, BasicObject]

When there are multiple prepends, the first lookup is from the last prepend.

Hence the lookup flow would be as follows. prepend(n) -> prepend(n-1) -> class -> include(n) -> include(n-1)

Prepend is used to insert a module's methods at the beginning of a class's method lookup chain, before the class's own methods. This means that when a method is called, Ruby will first look for it in the prepended module before looking in the class itself.