Согласно различным твитам об этом, включение констант является , как правило, плохой идеей, потому что это затрудняет тестирование, и для этого необходимо изменить состояние констант (что делает их чуть менее постоянными).Тем не менее, если вы пишете плагин, который должен вести себя по-разному в зависимости от среды, в которой он загружен, вам придется где-то проверить наличие Rails
, Merb
и т. Д., Даже еслиэто не в этой части кода.Где бы это ни было, вы хотите сохранить его изолированным, чтобы решение принималось только один раз.Что-то вроде MyPlugin::env
.Теперь вы можете безопасно заглушить этот метод в большинстве мест, а затем указать этот метод, заглушив константы.
Что касается того, как заглушить константы, ваш пример выглядит не совсем правильно.Код спрашивает, если defined?(Rails)
, но Kernel.const_set(:Rails, nil)
не определяет константу, а просто устанавливает ее значение на nil
.То, что вы хотите, это что-то вроде этого (отказ от ответственности - это не в моей голове, не проверено, даже не запускается, может содержать синтаксические ошибки, и не очень хорошо учтено):
def without_const(const)
if Object.const_defined?(const)
begin
@const = const
Object.send(:remove_const, const)
yield
ensure
Object.const_set(const, @const)
end
else
yield
end
end
def with_stub_const(const, value)
if Object.const_defined?(const)
begin
@const = const
Object.const_set(const, value)
yield
ensure
Object.const_set(const, @const)
end
else
begin
Object.const_set(const, value)
yield
ensure
Object.send(:remove_const, const)
end
end
end
describe "..." do
it "does x if Rails is defined" do
rails = double('Rails', :env => {:stuff_i => 'need'})
with_stub_const(:Rails, rails) do
# ...
end
end
it "does y if Rails is not defined" do
without_const(:Rails) do
# ....
end
end
end
Я дамнекоторые думали, стоит ли включать это в rspec или нет.Это одна из тех вещей, которые, если бы мы добавили людей, использовали бы ее как предлог, чтобы полагаться на константы, когда им не нужно:)