这里有一个很好的关于当前在 ruby 中实现改进的文档: http ://ruby-doc.org//core-2.2.0/doc/syntax/refinements_rdoc.html ,但是有一些奇怪的极端情况。
首先,include module
正交于using module
(一个包括模块的实例方法,而另一个激活细化)。但是包含一个细化模块本身有一个技巧,请参阅
Better way to turn a ruby class into a module而不是使用细化?.
def to_module(klass)
Module.new do
#note that we return the refinement module itself here
return refine(klass) {
yield if block_given?
}
end
end
class Base
def foo
"foo"
end
end
class Receiver
include to_module(Base) {
def foo
"refined " + super
end
}
end
Receiver.new.foo #=> "refined foo"
奇怪的是,这个细化模块不能与using
!
m=to_module(Base) {}
m.class #=> Module
using m
#=>TypeError: wrong argument type Class (expected Module)
因此,仅使用精化模块的封闭模块。其次,我想使用上面的 yield 技巧来传递一个 Proc 来优化(即使它只接受一个块),而不是像
https://www.new-bamboo.co那样将 Proc 转换回源代码.uk/blog/2014/02/05/refinements-under-the-knife/。但是yield
在包含示例中使用 as 不起作用:
def ref_module1(klass)
Module.new do
refine(klass) {
yield
}
end
end
class Receiver1
using ref_module1(Base) {
def foo
"refined " + super
end
}
def bar
Base.new.foo
end
end
Receiver1.new.bar #=> NoMethodError: super: no superclass method `foo'
我们看到 Receiver1 仍然使用 Bar#foo 而不是提炼的方法。但是我们可以module_eval
改用:
def ref_module2(klass,&b)
Module.new do
refine(klass) {
module_eval(&b)
}
end
end
class Receiver2
using ref_module2(Base) {
def foo
"refined " + super
end
}
def bar
Base.new.foo
end
end
Receiver2.new.bar #=> "refined foo"
我不太明白为什么module_eval
在这里工作而不是yield
方法。在细化块内,“default_definee”是细化模块,因此module_eval
将“default_definee”置于self
=“细化模块”不应影响它。实际上,在开头的“包含”示例中,当我使用module_eval
或直接使用yield
.
谁能解释这种行为?