为什么 Ruby 改进只修改 类,而不修改模块?
Why do Ruby refinements only modify classes, not modules?
Ruby docs on refinements state:
Refinements only modify classes, not modules so the argument must be a class.
这是为什么?
可以对模块进行猴子修补:
module MyModule
def my_method
"hello"
end
end
include MyModule
puts my_method # => hello
module MyModule
def my_method
"goodbye"
end
end
puts my_method # => goodbye
我敢肯定这不是个好主意,但如果您能限制这种猴子补丁的范围,它可能不会那么糟糕。那你为什么不能?
Ruby 中的 refine
旨在处理猴子修补和继承问题,其目的是将猴子修补限制在 classes 实例中特定命名空间。
这些相同的继承问题不会以相同的方式应用于模块,因为模块可以使用 mixin 扩展或包含在其他模块中(与 classes 相反)。
这将允许通过创建一个新模块来限制猴子补丁的命名空间,该新模块在其自己的命名空间内扩展并覆盖原始模块。
如果使用你的例子:
module MyModule
def my_method
"hello"
end
end
include MyModule
puts my_method
# => hello
module MyOtherModule
extend MyModule
puts my_method # will print: hello
def my_method
"goodbye"
end
extend self
puts my_method # will print: goodbye
end
# => hello
# => goodbye
puts my_method
# => hello
如您所见,我们设法将 'monkey-patch' 限制在 MyOtherModule
命名空间而不使用 refine
。
因为我们没有使用 MyModule
的实例(MyModule
不是 class),这种方法非常有效。
classes 不可能做到这一点,因为除其他原因外,class 实例可能不限于使用它们的模块的命名空间...因此,对于Class 个实例,应使用 refine
个。
模块的改进与 类 的改进一样有用。考虑如何
module Foobar
refine Enumerable
def all_zero?; all? &:zero? end
end
end
比直接猴子修补更有礼貌:
module Enumerable
def all_zero?; all? &:zero? end
end
有一个implementation issue with refining modules, which seems to be solved by now。
Ruby docs on refinements state:
Refinements only modify classes, not modules so the argument must be a class.
这是为什么?
可以对模块进行猴子修补:
module MyModule
def my_method
"hello"
end
end
include MyModule
puts my_method # => hello
module MyModule
def my_method
"goodbye"
end
end
puts my_method # => goodbye
我敢肯定这不是个好主意,但如果您能限制这种猴子补丁的范围,它可能不会那么糟糕。那你为什么不能?
Ruby 中的 refine
旨在处理猴子修补和继承问题,其目的是将猴子修补限制在 classes 实例中特定命名空间。
这些相同的继承问题不会以相同的方式应用于模块,因为模块可以使用 mixin 扩展或包含在其他模块中(与 classes 相反)。
这将允许通过创建一个新模块来限制猴子补丁的命名空间,该新模块在其自己的命名空间内扩展并覆盖原始模块。
如果使用你的例子:
module MyModule
def my_method
"hello"
end
end
include MyModule
puts my_method
# => hello
module MyOtherModule
extend MyModule
puts my_method # will print: hello
def my_method
"goodbye"
end
extend self
puts my_method # will print: goodbye
end
# => hello
# => goodbye
puts my_method
# => hello
如您所见,我们设法将 'monkey-patch' 限制在 MyOtherModule
命名空间而不使用 refine
。
因为我们没有使用 MyModule
的实例(MyModule
不是 class),这种方法非常有效。
classes 不可能做到这一点,因为除其他原因外,class 实例可能不限于使用它们的模块的命名空间...因此,对于Class 个实例,应使用 refine
个。
模块的改进与 类 的改进一样有用。考虑如何
module Foobar
refine Enumerable
def all_zero?; all? &:zero? end
end
end
比直接猴子修补更有礼貌:
module Enumerable
def all_zero?; all? &:zero? end
end
有一个implementation issue with refining modules, which seems to be solved by now。