Jun 17, 2015
Table of contents:
One of the most powerful aspects of Ruby is the ability to re-open any class and change it’s methods.
Yes that’s right, you can actually reopen any class and change how it works. This includes the standard Ruby classes like String
, Array
or Hash
!
Now this is obviously as dangerous as it sounds. Being able to change the expected outcome of a method can cause all sorts of weird behaviour and difficult to track down bugs.
But nonetheless, the ability to “Monkey Patch” any class is extremely powerful. Ruby is like a sharp knife, it can be extremely effective, but it’s usually your own fault if you cut yourself.
In today’s tutorial we’ll be looking at Monkey Patching in Ruby.
To illustrate Monkey Patching we’ll make some changes to the good old String
core class.
First up, we’ll add a handy method to generate some Lorem Ipsum text:
class String
def self.lipsum
'Lorem ipsum dolor sit amet, consectetur adipiscing elit.'
end
end
In this example I’ve reopened the String
core class and added a lipsum
Class Method (Understanding Class Methods verses Instance Methods in Ruby).
You can now use this method on the String
class like this:
String.lipsum
# => "Lorem ipsum dolor sit amet, consectetur adipiscing elit."
However, not only can we added methods to the core String
class, we can also modify the behaviour of existing methods!
class String
def upcase
self.reverse
end
end
In this example we’re hijacking the upcase
method and calling the reverse
method instead!
'hello'.upcase
# => "olleh"
So as you can see, it’s incredibly easy to add or modify methods on an existing class, even when you don’t own that class or it is part of the core of Ruby.
Rarely.
Ruby provides us with a wealth of powerful tools to work with. However, just because a tool is powerful, does not make it the right tool for the job.
Monkey Patching in particular is an extremely powerful tool. However, a powerful tool in the wrong hands will cause endless amounts of pain and suffering.
Whenever you Monkey Patch a class you are potentially creating a headache at some point in the future when things go wrong.
Classes that have been Monkey Patched are more difficult to understand and debug. If you’re not careful, the error message you will receive will likely give you very little clue as to what the problem actually is.
When you Monkey Patch a method you will potentially be breaking code downstream that is relying on that behaviour.
When you add a new method to an existing class using Monkey Patching you are potentially opening weird edge cases that you can’t possible foresee.
Now with that being said, there’s no point in having powerful tools like Monkey Patching if you don’t actually make use of them.
There are cases where reopening a class does make sense.
For example, you often see Monkey Patches that simply add a convenience method that has no side effect. Ruby has a very beautiful syntax and so it can be tempting to Monkey Patch a class to turn some ugly method call into something that is more readable.
Or perhaps you need to Monkey Patch a class you own.
There are many cases where it’s fine to Monkey Patch, but it should definitely not be your first weapon of choice.
It will often be the case that Monkey Patching is just the lazy developer’s preference over actually refactoring or implementing a known design pattern for a particular problem.
Just because Monkey Patching offers you an easy solution, does not mean that you should always take that path.