Why do Ruby refinements only modify classes, not modules?

匆匆过客 提交于 2019-12-23 12:55:37

问题


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

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!