Question
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"
Answer
EDIT : It has been 9 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:
class Foo
def bar
'Hello'
end
end
class ExtendedFoo < Foo
def bar
super + ' World'
end
end
ExtendedFoo.new.bar # => 'Hello World'
This works, if you control creation of the Foo
objects. Just change every
place which creates a Foo
to instead create an ExtendedFoo
. 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:
require 'delegate'
class Foo
def bar
'Hello'
end
end
class WrappedFoo < DelegateClass(Foo)
def initialize(wrapped_foo)
super
end
def bar
super + ' World'
end
end
foo = Foo.new # this is not actually in your code, it comes from somewhere else
wrapped_foo = WrappedFoo.new(foo) # this is under your control
wrapped_foo.bar # => 'Hello World'
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
](http://Ruby-
Doc.Org/stdlib/libdoc/delegate/rdoc/Object.html#method-i-DelegateClass) helper
method from the delegate
library in the stdlib.
“Clean” Monkey Patching
Module#prepend
:
Mixin Prepending
The 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 as Module#include
, except it mixes in the mixin directly below
the class:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
prepend FooExtensions
end
Foo.new.bar # => 'Hello World'
Note: I also wrote a little bit about Module#prepend
in this question: Ruby
module prepend vs
derivation
Mixin 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 of
prepend
ing it:
class Foo
def bar
'Hello'
end
end
module FooExtensions
def bar
super + ' World'
end
end
class Foo
include FooExtensions
end
Unfortunately, that won’t work. It’s a good idea, because it uses inheritance,
which means that you can use super
. However, [Module#include
](http://Ruby-
Doc.Org/core/Module.html#method-i-include) inserts the mixin above the class
in the inheritance hierarchy, which means that FooExtensions#bar
will never
be called (and if it were called, the super
would not actually refer to
Foo#bar
but rather to Object#bar
which doesn’t exist), since Foo#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:
class Foo
def bar
'Hello'
end
end
class Foo
old_bar = instance_method(:bar)
define_method(:bar) do
old_bar.bind(self).() + ' World'
end
end
Foo.new.bar # => 'Hello World'
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 since
[Module#define_method
](http://Ruby-Doc.Org/core/Module.html#method-i-
define_method) takes a block, and blocks close over their surrounding lexical
environment (which is why we are using define_method
instead of def
here), it (and only it) will still have access to old_bar
, even after it
has gone out of scope.
Short explanation:
old_bar = instance_method(:bar)
Here we are wrapping the bar
method into an [UnboundMethod
](http://Ruby-
Doc.Org/core/UnboundMethod.html) method object and assigning it to the local
variable old_bar
. This means, we now have a way to hold on to bar
even
after it has been overwritten.
old_bar.bind(self)
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 its self
is. But, we grabbed the method
directly from a class, how does it know what its self
is?
Well, it doesn’t, which is why we need to [bind
](http://Ruby-
Doc.Org/core/UnboundMethod.html#method-i-bind) our UnboundMethod
to an
object first, which will return a [Method
](http://Ruby-
Doc.Org/core/Method.html) object that we can then call. (UnboundMethod
s
cannot be called, because they don’t know what to do without knowing their
self
.)
And what do we bind
it to? We simply bind
it to ourselves, that way it
will behave exactly like the original bar
would have!
Lastly, we need to call the Method
that is returned from bind
. In Ruby
1.9, there is some nifty new syntax for that (.()
), but if you are on 1.8,
you can simply use the [call
](http://Ruby-Doc.Org/core/Method.html#method-i-
call) 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
](http://Ruby-Doc.Org/core/Module.html#method-i-
alias_method) chain
The 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!
class Foo
def bar
'Hello'
end
end
class Foo
alias_method :old_bar, :bar
def bar
old_bar + ' World'
end
end
Foo.new.bar # => 'Hello World'
Foo.new.old_bar # => 'Hello'
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
](http://API.RubyOnRails.Org/classes/Module.html#method-
i-alias_method_chain).
An aside: [Refinements](http://Ruby-
Doc.Org/core/doc/syntax/refinements_rdoc.html)
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:
class Foo
def bar
'Hello'
end
end
module ExtendedFoo
module FooExtensions
def bar
super + ' World'
end
end
refine Foo do
prepend FooExtensions
end
end
Foo.new.bar # => 'Hello'
# We haven’t activated our Refinement yet!
using ExtendedFoo
# Activate our Refinement
Foo.new.bar # => 'Hello World'
# There it is!
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 by Module#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
class Foo
def bar:before
# will always run before bar, when bar is called
end
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
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 within bar:after
. Maybe we could (ab)use the super
keyword?
class Foo
def bar
'Hello'
end
end
class Foo
def bar:after
super + ' World'
end
end
Replacement
The before combinator is equivalent to prepend
ing a mixin with an overriding
method that calls super
at the very end of the method. Likewise, the after
combinator is equivalent to prepend
ing a mixin with an overriding method
that calls super
at the very beginning of the method.
You can also do stuff before and after calling super
, you can call super
multiple times, and both retrieve and manipulate super
’s return value,
making prepend
more powerful than method combinators.
class Foo
def bar:before
# will always run before bar, when bar is called
end
end
# is the same as
module BarBefore
def bar
# will always run before bar, when bar is called
super
end
end
class Foo
prepend BarBefore
end
and
class Foo
def bar:after
# will always run after bar, when bar is called
# may or may not be able to access and/or change bar’s return value
end
end
# is the same as
class BarAfter
def bar
original_return_value = super
# will always run after bar, when bar is called
# has access to and can change bar’s return value
end
end
class Foo
prepend BarAfter
end
old
keyword
This idea adds a new keyword similar to super
, which allows you to call the
overwritten method the same way super
lets you call the overridden
method:
class Foo
def bar
'Hello'
end
end
class Foo
def bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
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 a prepend
ed mixin is essentially the same
as old
in this proposal.
redef
keyword
Similar 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:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
old + ' World'
end
end
Foo.new.bar # => 'Hello World'
Instead of adding two new keywords, we could also redefine the meaning of
super
inside redef
:
class Foo
def bar
'Hello'
end
end
class Foo
redef bar
super + ' World'
end
end
Foo.new.bar # => 'Hello World'
Replacement
redef
ining a method is equivalent to overriding the method in a prepend
ed
mixin. super
in the overriding method behaves like super
or old
in this
proposal.