2013-12-19 29 views
4

我工作的this pretty thorny problem和決定,我也許能夠動態地創建,通過這樣做,從StandardError的繼承的類:Constantize提出了未初始化的常量錯誤

something = "JustForBelow" 
error_class = "#{something}Error".constantize 
error_class = StandardError.new 

但我發現了一個很奇怪的錯誤(在我看來),這是:

Uninitialized constant JustForBelowError 

我不是在那裏初始化它嗎?

(基本上)同樣的錯誤出現,當我試試這個:

StandardError.const_get "#{something}Error" 
# => NameError: uninitialized constant StandardError::JustForBelowClass 

這感覺真是奇怪,因爲一),這些都是超級隨機的名字;沒有任何衝突,並且b)我很確定我已經像之前的第一個例子那樣使用了constantize。任何想法出了什麼問題?

回答

4

ActiveSupport的constantize方法只是查找一個常量。它是const_get的一個更好的版本,它可以遍歷嵌套的模塊結構。

要創建一個新的錯誤,你會想要做這樣的事情:

2.0.0-p247 :013 > Object.const_set("MyNewError", Class.new(StandardError)) 
=> MyNewError 
2.0.0-p247 :014 > MyNewError.ancestors 
=> [MyNewError, StandardError, Exception, Object, Kernel, BasicObject] 

在這一點,你可以做"MyNewError".constantize並取回新的類對象。

編輯 還要注意的是const_get在第二個例子中的錯誤期待的命名空間,它被稱爲裏面。在這種情況下,在StandardError的範圍內。

舉例來說,如果你有一個像階級結構:

module A 
    class B 
    CONSTANT = "hello world" 
    end 
end 

然後,你可以在此獲得與"A::B::CONSTANT".constantize,或做Object.const_get("A").const_get("B").const_get("CONSTANT")。同樣的事情,只是ActiveSupport做得更順利。

1

你就必須初始化它,如果你做了這一點:

class JustForBelowError < StandardError ; end 
something = "JustForBelow" 
error_class = "#{somestring}Error".constantize 
error_class = StandardError.new 

你需要的,如果你希望能夠定義一個恆定的「訪問」,它使用constantize

+0

那麼,有沒有辦法動態地定義常量?如在中,不知道準確的字符串將取代JustForBelowError,從插入的字符串初始化該類? – Sasha

+0

等一下。剛纔看到了上述情況,似乎回答了後續情況 – Sasha

3

對於任何正在嘗試查找「如何在類不存在時如何進行常量化」的問題,有safe_constantize,如果該類不存在,將返回nil。它本質上只是一個rescueconstantize

'blargle'.safe_constantize # => nil 
'UnknownModule'.safe_constantize # => nil 
'UnknownModule::Foo::Bar'.safe_constantize # => nil 

safe_constantize