ruby-on-rails – 为什么在私有版本中声明一个委派方法是公开的?

前端之家收集整理的这篇文章主要介绍了ruby-on-rails – 为什么在私有版本中声明一个委派方法是公开的?前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。
我可以通过将声明放在私人部分中来使attr_reader(以及相关的attr_writer和attr_accessor)方法是私有的:
class Foo
private
  attr_reader :b
end

Foo.new.b # => NoMethodError: private method `b' called for #<Foo:>

但是,Rails的delegate和Ruby标准库的def_delegate不能这样工作.这些委托的方法总是公开的.

class Foo
  attr_reader :b
  def initialize
    @b = 'b'
  end
end

require 'forwardable'
class Bar
  attr_reader :foo
  def initialize
    @foo = Foo.new
  end
  extend Forwardable
private
  def_delegator :foo,:b
end

Bar.new.b # => "b"

将代理私有化可以通过将其更改为:

private def_delegator :foo,:b

但是我预计上面的Bar.new.b会出现一个NoMethodError错误.为什么代表团不是私人的?

def_delegator(def_instance_delegator的别名)的方法定义只是拯救(已移除块):

def def_instance_delegator(accessor,method,ali = method)
  line_no = __LINE__; str = %Q{
    def #{ali}(*args,&block)
      #{accessor}.__send__(:#{method},*args,&block)
    end
  }
  module_eval(str,__FILE__,line_no)
end

这意味着module_eval不尊重它在私有部分中被调用.为什么?

解决方法

@H_403_23@ 是的,问题是使用module_eval,因为它在评估传递的字符串之前显式设置公共可见性.
它在CRuby和JRuby中的行为方式相同.例如,CRuby的被证明的代码eval_under功能.

如你所知,当您将def_delegate传递给私有方法时,它将变为私有的. def_delegate首先将传递的方法定义为public(由底层的module_eval),然后通过private重置为私有可见性.

如果当前Module.module_eval的行为是正确的或者在Forwardable.def_instance_delegator中存在错误,那么这不是100%清楚.在文档指南中使用module_eval示例将其用于相关类/模块之外,并且不期望可见性参数,因此将方法的可见性设置为public似乎是合乎逻辑的.

解决方案将是Module.module_eval处理可选可见性参数,并在发送到隐式或显式自身时尊重当前可见性(如果可能的话怀疑)或修复Forwardable.def_instance_delegator实现来定义具有更合适的Module.define_method而不是module_eval的方法.
无论如何,这是填写http://bugs.ruby-lang.org错误报告的好候选人.

猜你在找的Ruby相关文章