Don’t you just hate it when someone reopens your perfect class? Well let’s do something about that.
So let’s say we have a class:
And then we try to reopen it:
And now our class behaves differently.
But what if we could do something like this:
And when we look at the same scenario again:
Cool, our class resisted being reopened. But how? The module we extend our class with looks like this:
We utilize the
method_added hook Ruby gives us.
For each method you define on a class, it’s
method_added method is called with the name of the method that was defined.
We store the first implementation for a name. If it already exists then it means someone is trying to redefine the method. And we don’t want that, so we unpatch it back to what it was.
The method we got through
instance_method is unbound. In order to call it, it must first be bound to an object.
So that’s what we do, we redefine the method again after it was patched, and inside we bind the original method object to self and call it.
Since we are defining a method the
method_added hook will be invoked again, and to avoid dropping into an infinite loop we
guard ourselves with the
We probably need to add a mutex on this whole process of redefinition to be threadsafe, but I omitted it.
In fact, this even works as expected for subclasses.
And there you have it, no more monkey patches are going to mess up your precious code. :)