It's frowned upon, I know. But monkey-patching allows methods to be replaced with new ones that can still call the old ones. I needed to add some code to a constructor for a class whose source I didn't control. Subclassing was inappropriate, so the monkey-patch was the way to go.
! this is a note to self and may include errors or other misinformation.
Version 2 of Ruby introduced prepend which allows a module to be used to monkey-patch a class. It works like this:
module MonkeyPatch def initialize(*args) super end end
Of course, additional code goes inside
initialize and can go either side of the call to
super. The patch is then applied like this:
class SomeClass prepend MonkeyPatch end
Prior to the introduction of
prepend, things were more difficult.
class SomeClass class << self alias_method :__new__, :new def new(*args) __new__(*args) end end end
The original constructor is still accessible because
alias_method gave it a new name
__new__. This effect can be removed with a slightly different approach:
class SomeClass class << self __new__ = instance_method(:new) def new(*args) __new__.bind(self).(*args) end end end
Or, an alternative with
class SomeClass class << self __new__ = instance_method(:new) define_method(:new) do |*args| __new__.bind(self).(*args) end end end
__new__ returned by
instance_method is an unbound method assigned to a local variable so it's visible only within this code block. To call it, it needs to be re-bound to the object:
Note these latter examples patch
new instead of
initialise. This is because patching the latter doesn't work (actually, neither did patching
new - but
prepend works perfectly).
Read more here, here and here