Ruby LanguageMonkey Patching in Ruby

Introduction

Monkey Patching is a way of modifying and extending classes in Ruby. Basically, you can modify already defined classes in Ruby, adding new methods and even modifying previously defined methods.

Remarks

Monkey patching is often used to change the behavior of existing ruby code, from gems for instance.

For instance, see this gist.

It can also be used to extend existing ruby classes like Rails does with ActiveSupport, here is an example of that.

Changing any method

def hello
  puts "Hello readers"
end

hello # => "Hello readers"

def hello
  puts "Hell riders"
end

hello # => "Hell riders"

Changing an existing ruby method

puts "Hello readers".reverse # => "sredaer olleH"

class String
  def reverse
    "Hell riders"
  end
end

puts "Hello readers".reverse # => "Hell riders"

Changing a method with parameters

You can access the exact same context as the method you override.

class Boat
  def initialize(name)
    @name = name
  end

  def name
    @name
  end
end

puts Boat.new("Doat").name # => "Doat"

class Boat
  def name
    "⛵ #{@name} ⛵"
  end
end

puts Boat.new("Moat").name # => "⛵ Moat ⛵"

Extending an existing class

class String
  def fancy
    "~~~{#{self}}~~~"
  end
end

puts "Dorian".fancy # => "~~~{Dorian}~~~"

Safe Monkey patching with Refinements

Since Ruby 2.0, Ruby allows to have safer Monkey Patching with refinements. Basically it allows to limit the Monkey Patched code to only apply when it is requested.

First we create a refinement in a module:

module RefiningString
  refine String do
    def reverse
      "Hell riders"
    end
  end
end

Then we can decide where to use it:

class AClassWithoutMP   
  def initialize(str)
    @str = str
  end
   
  def reverse
    @str.reverse
  end
end

class AClassWithMP
  using RefiningString

  def initialize(str)
    @str = str
  end
   
  def reverse
    str.reverse
  end
end

AClassWithoutMP.new("hello".reverse # => "olle"
AClassWithMP.new("hello").reverse # "Hell riders"