Say I am monkey patching a method in a class, how could I call the overridden method from the overriding method? I.e. Something a bit like super
E.g.
class Foo
def bar()
"Hello"
end
end
class Foo
def bar()
super() + " World"
end
end
>> Foo.new.bar == "Hello World"
The class that will make override must to be reloaded after class that contains the original method, so
require
it in the file that will make overrride.EDIT: It has been 5 years since I originally wrote this answer, and it deserves some cosmetic surgery to keep it current.
You can see the last version before the edit here.
You can’t call the overwritten method by name or keyword. That’s one of the many reasons why monkey patching should be avoided and inheritance be preferred instead, since obviously you can call the overridden method.
Avoiding Monkey Patching
Inheritance
So, if at all possible, you should prefer something like this:
This works, if you control creation of the
Foo
objects. Just change every place which creates aFoo
to instead create anExtendedFoo
. This works even better if you use the Dependency Injection Design Pattern, the Factory Method Design Pattern, the Abstract Factory Design Pattern or something along those lines, because in that case, there is only place you need to change.Delegation
If you do not control creation of the
Foo
objects, for example because they are created by a framework that is outside of your control (like ruby-on-rails for example), then you could use the Wrapper Design Pattern:Basically, at the boundary of the system, where the
Foo
object comes into your code, you wrap it into another object, and then use that object instead of the original one everywhere else in your code.This uses the
Object#DelegateClass
helper method from thedelegate
library in the stdlib.“Clean” Monkey Patching
Module#prepend
: Mixin PrependingThe two methods above require changing the system to avoid monkey patching. This section shows the preferred and least invasive method of monkey patching, should changing the system not be an option.
Module#prepend
was added to support more or less exactly this use case.Module#prepend
does the same thing asModule#include
, except it mixes in the mixin directly below the class:Note: I also wrote a little bit about
Module#prepend
in this question: Ruby module prepend vs derivationMixin Inheritance (broken)
I have seen some people try (and ask about why it doesn’t work here on StackOverflow) something like this, i.e.
include
ing a mixin instead ofprepend
ing it:Unfortunately, that won’t work. It’s a good idea, because it uses inheritance, which means that you can use
super
. However,Module#include
inserts the mixin above the class in the inheritance hierarchy, which means thatFooExtensions#bar
will never be called (and if it were called, thesuper
would not actually refer toFoo#bar
but rather toObject#bar
which doesn’t exist), sinceFoo#bar
will always be found first.Method Wrapping
The big question is: how can we hold on to the
bar
method, without actually keeping around an actual method? The answer lies, as it does so often, in functional programming. We get a hold of the method as an actual object, and we use a closure (i.e. a block) to make sure that we and only we hold on to that object:This is very clean: since
old_bar
is just a local variable, it will go out of scope at the end of the class body, and it is impossible to access it from anywhere, even using reflection! And sinceModule#define_method
takes a block, and blocks close over their surrounding lexical environment (which is why we are usingdefine_method
instead ofdef
here), it (and only it) will still have access toold_bar
, even after it has gone out of scope.Short explanation:
Here we are wrapping the
bar
method into anUnboundMethod
method object and assigning it to the local variableold_bar
. This means, we now have a way to hold on tobar
even after it has been overwritten.This is a bit tricky. Basically, in Ruby (and in pretty much all single-dispatch based OO languages), a method is bound to a specific receiver object, called
self
in Ruby. In other words: a method always knows what object it was called on, it knows what itsself
is. But, we grabbed the method directly from a class, how does it know what itsself
is?Well, it doesn’t, which is why we need to
bind
ourUnboundMethod
to an object first, which will return aMethod
object that we can then call. (UnboundMethod
s cannot be called, because they don’t know what to do without knowing theirself
.)And what do we
bind
it to? We simplybind
it to ourselves, that way it will behave exactly like the originalbar
would have!Lastly, we need to call the
Method
that is returned frombind
. In Ruby 1.9, there is some nifty new syntax for that (.()
), but if you are on 1.8, you can simply use thecall
method; that’s what.()
gets translated to anyway.Here are a couple of other questions, where some of those concepts are explained:
“Dirty” Monkey Patching
alias_method
chainThe problem we are having with our monkey patching is that when we overwrite the method, the method is gone, so we cannot call it anymore. So, let’s just make a backup copy!
The problem with this is that we have now polluted the namespace with a superfluous
old_bar
method. This method will show up in our documentation, it will show up in code completion in our IDEs, it will show up during reflection. Also, it still can be called, but presumably we monkey patched it, because we didn’t like its behavior in the first place, so we might not want other people to call it.Despite the fact that this has some undesirable properties, it has unfortunately become popularized through AciveSupport’s
Module#alias_method_chain
.An aside: Refinements
In case you only need the different behavior in a few specific places and not throughout the whole system, you can use Refinements to restrict the monkey patch to a specific scope. I am going to demonstrate it here using the
Module#prepend
example from above:You can see a more sophisticated example of using Refinements in this question: How to enable monkey patch for specific method?
Abandoned ideas
Before the Ruby community settled on
Module#prepend
, there were multiple different ideas floating around that you may occasionally see referenced in older discussions. All of these are subsumed byModule#prepend
.Method Combinators
One idea was the idea of method combinators from CLOS. This is basically a very lightweight version of a subset of Aspect-Oriented Programming.
Using syntax like
you would be able to “hook into” the execution of the
bar
method.It is however not quite clear if and how you get access to
bar
’s return value withinbar:after
. Maybe we could (ab)use thesuper
keyword?Replacement
The before combinator is equivalent to
prepend
ing a mixin with an overriding method that callssuper
at the very end of the method. Likewise, the after combinator is equivalent toprepend
ing a mixin with an overriding method that callssuper
at the very beginning of the method.You can also do stuff before and after calling
super
, you can callsuper
multiple times, and both retrieve and manipulatesuper
’s return value, makingprepend
more powerful than method combinators.and
old
keywordThis idea adds a new keyword similar to
super
, which allows you to call the overwritten method the same waysuper
lets you call the overridden method:The main problem with this is that it is backwards incompatible: if you have method called
old
, you will no longer be able to call it!Replacement
super
in an overriding method in aprepend
ed mixin is essentially the same asold
in this proposal.redef
keywordSimilar to above, but instead of adding a new keyword for calling the overwritten method and leaving
def
alone, we add a new keyword for redefining methods. This is backwards compatible, since the syntax currently is illegal anyway:Instead of adding two new keywords, we could also redefine the meaning of
super
insideredef
:Replacement
redef
ining a method is equivalent to overriding the method in aprepend
ed mixin.super
in the overriding method behaves likesuper
orold
in this proposal.Take a look at aliasing methods, this is kind of renaming the method to a new name.
For more information and a starting point take a look at this replacing methods article (especially the first part). The Ruby API docs, also provides (a less elaborate) example.