2014-12-01 47 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