Ruby on rails 在ruby类中重写module_函数并访问原始

Ruby on rails 在ruby类中重写module_函数并访问原始,ruby-on-rails,ruby,ruby-on-rails-5,overriding,monkeypatching,Ruby On Rails,Ruby,Ruby On Rails 5,Overriding,Monkeypatching,我正在尝试重写Rails助手方法,该方法定义如下: class Foo module Bar def orig # orig code end alias o orig module_function :o module_function :orig end end def orig # new code # super (run orig code) end alias o orig 这样我就可以覆盖并向orig和

我正在尝试重写Rails助手方法,该方法定义如下:

class Foo
  module Bar

    def orig
      # orig code
    end

    alias o orig

    module_function :o
    module_function :orig

  end
end
def orig
  # new code
  # super (run orig code)
end
alias o orig
这样我就可以覆盖并向
orig
o
添加类似的功能:

class Foo
  module Bar

    def orig
      # orig code
    end

    alias o orig

    module_function :o
    module_function :orig

  end
end
def orig
  # new code
  # super (run orig code)
end
alias o orig
我已经看过了,但它们似乎不起作用。我相信
module_函数
就是它的缺点


有人知道我如何做到这一点吗?

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

第一,最初的定义:

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"
class-MyClass
包括Foo
结束
MyClass.new.send(:bar,1)#=>“self=#,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"
模块Foo
def条(arg)
self={self},arg={arg}
结束
模块功能:条形图
结束
模块扩展
def条(arg)
超级(arg+1)
结束
结束
[Foo,Foo.singleton_class]。每个do|mod|
mod.prepend扩展
结束
Foo.bar(1)#=>“self=Foo,arg=2”
类MyClass
包括Foo
结束
MyClass.new.bar(1)#=>“self=#,arg=2”

我曾经是这个技巧的大力支持者,因为与
alias\u方法不同
它不会污染名称空间,但不再需要了。使用
alias_方法
可以完成的一切,现在也可以通过简单的继承(
prepend
)来完成。@JörgWMittag好的,我必须承认我还没有养成使用prepend的习惯。但是,我知道这里是多么简单。感谢
prepend
是一种功能强大的继承机制。它可以包含monkey补丁、面向方面编程(在建议之前、之后和周围)、CLOS风格的方法组合器(同样,在建议之前、之后和周围)。如果你向下滚动到OP链接的末尾,我会给出几个在引入
prepend
之前浮动的增强Ruby继承性的想法示例,以及如何用
prepend
替换所有这些想法,通常甚至具有额外的特性和灵活性。我看不到Rails标记的合理性,并且也会删除“override”和“monkeypatching”,只留下“ruby”。很好的一个,Jörg,与其修改
Foo
(可能在其他地方使用),不如在类定义中做所有的包含和预处理:
[self,singleton_class]。每个{k | k.include Foo;k.prepend footextension}
。托马斯:请注意,这并不取决于语句
模块\函数:bar
。如果您不需要将
bar
作为
Foo
中的模块方法,则可以删除该语句。我同意约格的观点,这是你应该采取的方法。