在ruby类中重写module_function,可以访问原始文件

时间:2018-11-10 02:04:25

标签: ruby-on-rails ruby ruby-on-rails-5 override monkeypatching

我正在尝试覆盖这样定义的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可以解决这个问题。

有人知道我怎么能做到吗?

2 个答案:

答案 0 :(得分:2)

这是一种解决方法。您可以重新打开模块,对原始实例方法进行未绑定的引用,然后重新定义它以调用原始方法(行为有所改变)。

首先是原始定义:

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"

答案 1 :(得分: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"