Reputation: 43
I'm trying to override a Rails helper method that's defined like this:
class Foo
module Bar
def orig
# orig code
end
alias o orig
module_function :o
module_function :orig
end
end
So that I can override and add functionality to orig
and o
something like this:
def orig
# new code
# super (run orig code)
end
alias o orig
I've looked through several different monkey patching methods but they don't seem to work. I believe the module_function
is what's throwing it off.
Anyone know how I can achieve this?
Upvotes: 3
Views: 934
Reputation: 369556
Pretty much any circumstance where you would in the past have used monkey-patching can nowadays be solved with inheritance and Module#prepend
:
module Foo
def bar(arg)
"self=#{self}, arg=#{arg}"
end
module_function :bar
end
module FooExtension
def bar(arg)
super(arg + 1)
end
end
[Foo, Foo.singleton_class].each do |mod|
mod.prepend FooExtension
end
Foo.bar(1) #=> "self=Foo, arg=2"
class MyClass
include Foo
end
MyClass.new.bar(1) #=> "self=#<MyClass:0x00007fb66a86cbf8>, arg=2"
Upvotes: 4
Reputation: 26778
Here's a workaround. You can re-open the module, make an unbound reference to the original instance method, then redefine it to call the original method (with some altered behavior).
First, the original definition:
module Foo
def bar(arg)
"self=#{self}, arg=#{arg}"
end
module_function :bar
end
Next, reopening and redefining the method:
module Foo
OrigBarMethod = instance_method(:bar)
def bar(arg)
Foo::OrigBarMethod.bind(self).call(arg + 1)
end
module_function :bar
end
puts Foo.bar(1) # => "self=Foo, arg=2"
I use bind(self)
so that the original method can still make use of self
, for example:
class MyClass
include Foo
end
MyClass.new.send(:bar, 1) # => "self=#<MyClass:0x00007fb66a86cbf8>, arg=2"
Upvotes: 4