Ruby is a wonderful language. Despite the type wars between static and dynamic (typing/checking) or that some say it might be dying (which I don’t agree with), I just find Ruby a great language to learn. Its readable and has features that hooked me from the start. I never used it on a big project or anything professionally. But I learned enough of it to send some pull requests to Ruby projects on GitHub and also develop solutions for the advent of code.
A famous Ruby book called metaprogramming with ruby  walks through some concepts of metaprogramming (in Ruby, of couses) and presents some examples.
The first concept presented by this book is called Open Classes.
Open Classes definition
The concept of Open Classes is used as a metaprogramming attribute to change an object’s behavior in runtime. In Ruby there is no real distinction between code that defines a class and code of any other kind , therefore, any code that is put within a class block is processed like any other piece of code.
So how is a class defined?
Whenever I use the keyword
class, this class is opened for modifications, however if this class was not yet modified, Ruby will take care of that for you.
Open class can be convenient most times, but given the dynamic nature of Ruby language and such feature, you might run into some problems.
Duplicate method definition
Imagine you use this feature on standard
Array class. You have a method that replaces a handful of values in a list according to your program’s logic.
class Array def replace (x, y, z) # ... end end
Unfortunately, this breaks a lot of other functionalities, because
Array#replace is already defined in the standard ruby library. And, lucky for you, Ruby will not tell you, the way Open Class works, it will simply re-open
Array class and overwrite current
We can see array has a replace method running:
.methods.grep /replace/ # => #[:replace]
This is only an example, there are several drawbacks and advantages to Monkey-Patching. The bottom line is that you must use it safely and rarely. There are a lot of resources online explaining Monkey-Patching and its quirks .
Moving on, the book  brings an example from the money gem where the Open Class principle was used. The example is as follows:
class Numeric def to_money Money.new(self * 100) end end # 100.to_money => #<Money @cents=10000>
I wanted to follow along or at least have some sort of a deep dive on this, so I joined in and cloned the source code for the money gem and went on looking for the
Numeric class Monkey-Patch. However, this snippet of code was no longer present. All the Open Class shenanigans, along with a handful of new String methods vanished.
I started hunting for this feature on their changelog and past releases.
What I figured out during this process:
- After v4.0.0 they changed the heavy logic on
Stringpatch to static calls to a
- Until version 5.0.0 the Monkey-Patch was still in place
- On v6.0.0 they added a deprecated flag and only after v6.1.0 they removed it completely
What really happend was: they moved the code to another place. Where? Here. Another repository, they isolated the logic as an addon of the Money gem.
Now, how do I feel about this? I mostly like this approach because of the following points:
Your application’s public API
When you change the behavior of a standard Ruby class (e.g. String or Numeric), you are defining part of the public API of your application. Since it is not the key feature of this gem, it’s just a handy helper method to create a
Money type object, it makes sense to provide this as an addon to your users to use at their own risk.
Ease the conflicts
If another library patches the same methods/classes you can simply don’t plug the
Monetize gem and live happily without its Monkey-Patching.
Well, Open Class is a nice concept from Ruby. You can use it to Monkey-Patch classes and twist and turn standard Ruby library all you want. And it’s fun to do so, it is one of the things that gives Ruby that special look. I also enjoy going hunting commits and understanding design decisions on Open Source projects based on their development history. I recommend you to do it from time to time
it’s super relaxing and not frustrating at all.
: Perrotta, P. (2010). Metaprogramming Ruby. Pragmatic Bookshelf.
: Monkey-Patch is a term used when you change methods of a class during runtime, specially (in Ruby) from a standard Ruby class (e.g. String, List, Numeric…)