2010-07-30 30 views
51

我正在運行一些Ruby代碼,它會在每次更改日期時發送一個Ruby文件。在該文件中,我有常量定義,像如何在沒有警告的情況下重新定義Ruby常量?

Tau = 2 * Pi 

,當然,他們做出解釋顯示無用「已初始化常量」每一次警告,所以,我想有以下功能:

def_if_not_defined(:Tau, 2 * Pi) 
redef_without_warning(:Tau, 2 * Pi) 

我能寫這樣我所有的常量定義避免了警告:

Tau = 2 * Pi unless defined?(Tau) 

,但是這是不好的,有點溼(不DRY)。

有沒有更好的方法來def_if_not_defined?而如何redef_without_warning

-

解決方案感謝史蒂夫:

class Object 
    def def_if_not_defined(const, value) 
    mod = self.is_a?(Module) ? self : self.class 
    mod.const_set(const, value) unless mod.const_defined?(const) 
    end 

    def redef_without_warning(const, value) 
    mod = self.is_a?(Module) ? self : self.class 
    mod.send(:remove_const, const) if mod.const_defined?(const) 
    mod.const_set(const, value) 
    end 
end 

A = 1 
redef_without_warning :A, 2 
fail 'unit test' unless A == 2 
module M 
    B = 10 
    redef_without_warning :B, 20 
end 
fail 'unit test' unless M::B == 20 

-

這個問題是舊的。上述代碼僅對Ruby 1.8是必需的。在Ruby 1.9中,P3t3rU5的答案不會產生任何警告,而是更好。

+5

爲什麼你想重新定義一個常數?更好地將常量保存在你自己的類或模塊中,這樣它們永遠不會與其他常量發生衝突。 – 2010-07-30 21:11:44

+1

我想重新定義一個常量,因爲我想自然地使用常量,就像我沒有使用自動源代碼重載器一樣,所以我不會接受任何「只是不使用常量」的答案。 – 2010-07-30 21:19:16

+2

什麼是不雅而不幹的關於'Tau = 2 * Pi除非定義?(Tau)'? – jrdioko 2010-12-08 17:42:36

回答

58

以下模塊可以做你想做的。如果沒有它可以提供一些指引,以您的解決方案

module RemovableConstants 

    def def_if_not_defined(const, value) 
    self.class.const_set(const, value) unless self.class.const_defined?(const) 
    end 

    def redef_without_warning(const, value) 
    self.class.send(:remove_const, const) if self.class.const_defined?(const) 
    self.class.const_set(const, value) 
    end 
end 

,並且應用它

class A 
    include RemovableConstants 

    def initialize 
    def_if_not_defined("Foo", "ABC") 
    def_if_not_defined("Bar", "DEF") 
    end 

    def show_constants 
    puts "Foo is #{Foo}" 
    puts "Bar is #{Bar}" 
    end 

    def reload 
    redef_without_warning("Foo", "GHI") 
    redef_without_warning("Bar", "JKL") 
    end 

end 

a = A.new 
a.show_constants 
a.reload 
a.show_constants 

的例子給出下面的輸出

Foo is ABC 
Bar is DEF 
Foo is GHI 
Bar is JKL 

原諒我,如果我打破任何紅寶石禁忌在這裏,因爲我仍然在我的頭部周圍的一些模塊:類:紅寶石內的本徵類結構

+0

當然,這個答案的關鍵是首先調用Object.send(:remove_const,'Tau')如果Object.const_defined?('Tau')',它定義了常量,從而搶佔警告。偉大的方法。 – ghayes 2013-08-11 22:38:44

+0

是的,或者只是'發送(:remove_const,:CONST)如果const_defined?(:CONST)'如果你在類(不是實例)範圍。 – thewoolleyman 2014-06-18 23:32:38

4

如果你想重新定義一個值,那麼不要使用常量,而應該使用全局變量($ tau = 2 * Pi),但這也不是一個好習慣。你應該把它作爲合適類的實例變量。

對於另一種情況,Tau = 2 * Pi unless defined?(Tau)是完全正確的,最具可讀性,因此是最優雅的解決方案。

2

除非常量的值是非常奇怪的(即你必須設置爲nilfalse常數),最好的選擇是使用條件賦值運算符:Tau ||= 2*Pi

這將設置頭到2π,如果它是nil,false或未定義,否則保持不變。

+1

不錯的想法...不幸的是,它不是很便攜:取決於ruby的版本和實現(ruby/jruby),對|| =常數的作用給了我三種不同的結果。要麼它按照預期安靜地工作(jruby1.5),要麼我得到一個「未初始化的常量」失敗(ruby1.8),要麼即使沒有發生任何動作(jruby1.2)也會發出警告。 – 2010-07-30 22:05:21

3

使用$ VERBOSE來抑制警告的另一種方法在此處討論:http://mentalized.net/journal/2010/04/02/suppress_warnings_from_ruby/

+2

是的。正如您的鏈接中提到的,在Rails中存在一個更好的silence_warnings實現:http://api.rubyonrails.org/classes/Kernel.html#M002564但是這種方法不如公認的答案,因爲它可能對其他方面有副作用線程。 – 2012-08-30 23:23:09

1

以下情況如何?

TAU ||= 2 * Pi 

它適用於我正在研究的寶石。

+5

這永遠不會重新定義一個常數,所以不是問題的答案。它怎麼得到8票? – jrochkind 2016-05-02 22:57:40

+1

好吧,它回答了def_if_not_defined(:Tau,2 * Pi),我認爲這是原始問題,不確定,很久以前 – P3t3rU5 2017-02-28 23:31:04

+1

也重新定義常量是對語言的濫用,即使您可以做到這一點,這並不意味着你應該這樣做 – P3t3rU5 2017-02-28 23:32:15

相關問題