覆盖 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

这样我就可以覆盖并向 origo 添加功能,如下所示:

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"