Closed Classes in Ruby
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 @unpatching
flag.
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. :)