覆盖 ruby class 内的 module_function 以访问原始文件
Override module_function inside ruby class with access to original
我正在尝试覆盖这样定义的 Rails 辅助方法:
class Foo
module Bar
def orig
# orig code
end
alias o orig
module_function :o
module_function :orig
end
end
这样我就可以覆盖并向 orig
和 o
添加功能,如下所示:
def orig
# new code
# super (run orig code)
end
alias o orig
我已经查看 several different monkey patching methods 但它们似乎不起作用。我相信 module_function
是导致它失败的原因。
有人知道我怎样才能做到这一点吗?
这是一个解决方法。您可以重新打开模块,对原始实例方法进行未绑定引用,然后重新定义它以调用原始方法(具有一些改变的行为)。
一、原文定义:
module Foo
def bar(arg)
"self=#{self}, arg=#{arg}"
end
module_function :bar
end
接下来,重新打开并重新定义方法:
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"
我用的是bind(self)
,这样原来的方法还可以利用self
,例如:
class MyClass
include Foo
end
MyClass.new.send(:bar, 1) # => "self=#<MyClass:0x00007fb66a86cbf8>, arg=2"
几乎任何你过去会使用猴子补丁的情况现在都可以通过继承来解决 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"
我正在尝试覆盖这样定义的 Rails 辅助方法:
class Foo
module Bar
def orig
# orig code
end
alias o orig
module_function :o
module_function :orig
end
end
这样我就可以覆盖并向 orig
和 o
添加功能,如下所示:
def orig
# new code
# super (run orig code)
end
alias o orig
我已经查看 several different monkey patching methods 但它们似乎不起作用。我相信 module_function
是导致它失败的原因。
有人知道我怎样才能做到这一点吗?
这是一个解决方法。您可以重新打开模块,对原始实例方法进行未绑定引用,然后重新定义它以调用原始方法(具有一些改变的行为)。
一、原文定义:
module Foo
def bar(arg)
"self=#{self}, arg=#{arg}"
end
module_function :bar
end
接下来,重新打开并重新定义方法:
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"
我用的是bind(self)
,这样原来的方法还可以利用self
,例如:
class MyClass
include Foo
end
MyClass.new.send(:bar, 1) # => "self=#<MyClass:0x00007fb66a86cbf8>, arg=2"
几乎任何你过去会使用猴子补丁的情况现在都可以通过继承来解决 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"