2014-12-01 81 views
0

在Spree框架中,Product模型定义了一个名为build_variants_from_option_values_hash的私有方法。改变方法的可见性而无需重新定义方法

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

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

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

+2

为什么不用'send:private_method,* args'向它发送参数? – 2014-12-01 16:54:07

+0

@МалъСкрылевъ哦,我明白了。由于某种原因,我没有考虑过这个问题。谢谢,这似乎工作。 – 2014-12-01 16:58:52

回答

1

虽然@МалъСкрылевъ的做法是比较明智​​的,海事组织,你可以在交替产生方法的公共别名:

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 
+0

啊我看到了,非常好,我也没有考虑别名。至于'public:public_build_variants'部分,是否有什么理由避免直接更改方法可见性,而不是其别名(换句话说:'public:build_variants_from_option_values_hash')? – 2014-12-01 17:33:50

+1

为什么宝石开发者将该方法标记为私有通常有很好的理由。我对这件宝石一无所知,所以我不能说出这件事的确切动机。通常,私有方法不适合开发人员使用,允许宝石维护人员在没有BC间歇的情况下修改/重命名/删除此类功能。 – deefour 2014-12-01 20:19:31

1

引桥的重新定义知名度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公共方法如下:

object.send :private_method, *args 
+0

感谢您发布此信息,非常有帮助。 – 2014-12-02 21:25:56

+0

@PaulRichter你解决了接受其他答案? =) – 2014-12-03 07:03:44

+0

是的,两个答案都非常好,我很难决定接受哪一个。然而,我决定和其他人一起去,因为Deefour在他的评论中提出了这个观点。由于该方法的名称可能会改变(因为它被声明为私有,开发人员可以根据需要随意重命名),如果使用Deefour的方法,则只需更改一次该名称即可更新我的代码,因为我已经像他描述的那样在模型中声明了它。现在,我可以用你的方法做类似的事情,但我觉得别名版本更简洁一些。 – 2014-12-03 16:32:14