Ruby on rails 在ruby类中重写module_函数并访问原始
我正在尝试重写Rails助手方法,该方法定义如下: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和
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
中的模块方法,则可以删除该语句。我同意约格的观点,这是你应该采取的方法。