2013-12-19 4 views
4

Я работаю над this pretty thorny problem и решил, что я мог бы быть в состоянии динамически создать класс, который наследует от StandardError, делая это:Constantize поднимает Uninitialized Constant Ошибка

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

Но я получаю очень странные ошибки (по-моему):

Uninitialized constant JustForBelowError 

Я не инициализирую его прямо там?

(по существу) такая же ошибка появляется, когда я пытаюсь это:

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

Это чувствует себя очень странно, потому что а) это супер случайные имена; конфликтов нет, и б) я уверен, что использовал константизацию, как в первом примере раньше. Любые идеи, что происходит не так?

ответ

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, если класс не существует. Это по существу только rescue около constantize.

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

safe_constantize

Смежные вопросы