【问题标题】:Alter method visibility without redefining method更改方法可见性而不重新定义方法
【发布时间】:2015-01-29 17:51:46
【问题描述】:

在 Spree 框架中,Product 模型定义了一个名为 build_variants_from_option_values_hash 的私​​有方法。

此方法通常由after_create 回调在内部调用,并在类中声明为private。我想在正常的“创建”生命周期之外使用这个方法并直接调用它,但是由于它是私有声明的,不幸的是它在类之外是不可见的。

问题:有没有办法改变/修改方法的可见性而不重新定义它?

使用class_eval,我可以在private 区域之外的产品装饰器中重新定义方法,这确实可以解决问题。然而,我觉得完全复制整个方法只是为了改变它的可见性是一种不必要的“猴子修补”类型的方法。有没有更好的方法来做到这一点?

【问题讨论】:

  • 为什么不直接用 send :private_method, *args 发送 args 给它?
  • @МалъСкрылевъ 哦,我明白了。出于某种原因,我没有考虑到这一点。谢谢,这似乎确实有效。

标签: ruby-on-rails ruby ruby-on-rails-4 methods visibility


【解决方案1】:

虽然@МалъСкрылевъ 的方法更明智,但 IMO,您也可以创建该方法的公共别名:

Product.class_eval do

  alias_method :public_build_variants, :build_variants_from_option_values_hash
  public :public_build_variants

end

现在可以用作

p = Product.new
p.public_build_variants

【讨论】:

  • 啊,我明白了,非常好,我也没有考虑过别名。关于public :public_build_variants 部分,我是否有任何理由希望避免直接更改方法可见性,而不是其别名(换句话说:public :build_variants_from_option_values_hash)?
  • gem 开发人员将方法标记为私有通常是有充分理由的。我对所讨论的宝石一无所知,因此在这种情况下我无法说出确切的动机。通常私有方法不打算供开发人员使用,允许 gem 维护者修改/重命名/删除此类功能而无需 BC 中断。
【解决方案2】:

ruby 中重新定义方法的可见性的方法并不好。但是,您可以通过获取和重新定义公共空间的相同方法来做到这一点,如下所示:

class CC
   private
   def private_method
   end
end
CC.new.private_method # => NoMethodError: private method `private_method' called for #<CC:0x8166144>

method = CC.instance_method(:private_method)
CC.send(:remove_method, :private_method)
CC.send(:define_method, :private_method, method)
CC.new.private_method # => nil

但调用私有方法的正确方法是使用#send public 方法,如下所示:

object.send :private_method, *args

【讨论】:

  • 感谢发帖,非常有帮助。
  • 是的,两个答案都很好,我很难决定接受哪一个。然而,我决定选择另一个,因为 Deefour 在他的评论中提出了这一点;那,由于方法的名称可能会改变(因为它被声明为私有,开发人员可以根据需要随意重命名),如果我使用 Deefour 的方法,我只需要更改一次名称来更新我的代码,因为我已经像他描述的那样在模型中声明了它。现在,我可以用你的方法做类似的事情,但我觉得别名版本更干净一些。
  • @PaulRichter 好方法是使用#send,位别名或get/assign =)
  • 对不起,我不太明白你在说什么bit alias or get/assign。但是,如果您觉得send 方法是更好的方法,我完全 100% 开放,如果您想帮助我了解您的立场。正如我所说,除了我提到的“清洁”之外,这两种方法对我来说似乎或多或少都一样好。为什么您认为#send 可能是更好的方法?
  • @PaulRichter 更好,因为它没有被引入类结构。它只是对私有方法的间接调用,就像直接对公共方法一样。
猜你喜欢
  • 1970-01-01
  • 2012-09-07
  • 2019-01-06
  • 2018-05-19
  • 2019-07-22
  • 2014-08-17
  • 2013-09-30
  • 1970-01-01
  • 2021-04-11
相关资源
最近更新 更多