问题
The Ruby docs on refinements state:
Refinements only modify classes, not modules so the argument must be a class.
Why is this?
It's possible to monkey-patch a module:
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
I'm sure this isn't a good idea, but it might not be as bad if you could limit the scope of such a monkey patch. So why can't you?
回答1:
The refine
in Ruby is intended to deal with issues of monkey-patching and inheritance, where the intention is to limit the monkey patching to instances of classes within a specific namespace.
These same inheritance issues don't apply to modules in the same way, since modules can be extended or included within other modules (as opposed to classes) using mixins.
This would allow namespace limitation of the monkey-patching by creating a new module which extends and overrides the original within it's own namespace.
If to use your example:
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
As you can see, We managed to limit the 'monkey-patch' to the MyOtherModule
namespace without using refine
.
Since we aren't using instances of MyModule
(MyModule
is NOT a class), this approach works perfectly.
The same is not possible with classes since, among other reasons, class instances might not be limited to the namespace of the module within which they are used... Hence, for Class instances, refine
should be used.
回答2:
Refinements of modules are just as useful as refinements of classes. Consider how
module Foobar
refine Enumerable
def all_zero?; all? &:zero? end
end
end
is more polite than direct monkey patching:
module Enumerable
def all_zero?; all? &:zero? end
end
There was an implementation issue with refining modules, which seems to be solved by now.
来源:https://stackoverflow.com/questions/33071443/why-do-ruby-refinements-only-modify-classes-not-modules