Why doesn't to_proc work inside Ruby refinements?

早过忘川 提交于 2019-12-12 10:52:22

问题


It seems that to_proc doesn't work on methods defined in refinements:

module ArrayExtensions
  refine Array do
    def sum
      reduce(0, :+)
    end
  end
end

using ArrayExtensions

puts [[1, 2, 3]].map { |array| array.sum } # => 6
puts [[1, 2, 3]].map(&:sum) # => array.rb:13:in `map': undefined method `sum' for [1, 2, 3]:Array (NoMethodError)
puts [1, 2, 3].method(:sum).to_proc.call # => array.rb:14:in `method': undefined method `sum' for class `Array' (NameError)

Is this the intended behavior? Is there a workaround?


回答1:


NB The answer below is correct for legacy rubies. In Ruby 2.5+ map(&:sum) works as expected.


Scoping of refinements is restricted to current context. Since refinements are intended to be not global, as an opposite to monkey patches, any try to call the refined method from outside is prevented. In the code below:

puts [[1, 2, 3]].map { |array| array.sum } # => 6

the scope is fine, we are inside the same scope where this refinement was defined. But here:

puts [[1, 2, 3]].map(&:sum)

the scope is transferred to the context of Symbol class (!). As stated in the documentation:

When control is transferred outside the scope the refinement is deactivated.

The analogy here would be a private method. Though, while it is exactly as stated in docs, I am unsure whether this behaviour is intended. I believe, an interpreter should take care about such cases. But this question is better to address Matz :)

P.S. Good question!




回答2:


Of course it is intended. The scope for a refinement is either the module block or the file where using was called. In your (&:sum), you are not (explicitly) calling the method sum; you only have a symbol :sum there. Calling is done somewhere in the Ruby C-implementation when Symbol#to_proc is used. That environment is where your refinement is not effective.

A workaround is to explicitly call the method within that file.



来源:https://stackoverflow.com/questions/35333222/why-doesnt-to-proc-work-inside-ruby-refinements

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