Monkey 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"