Я использую ERB для генерации набора инструкций с данными о местоположении и хочу принять смещение во входных данных. Однако когда я пытаюсь проверить, присутствует ли это смещение, оно устанавливает его значение равным нулю. Если кто-нибудь может помочь объяснить, что происходит, мы будем очень признательны!
Вот код, который я запустил, чтобы проверить это, как только сузил проблему:
<%
# apply a default value of 0 to the offset hash
p offset.nil?
p offset
p offset.nil?
p offset
if offset.nil?
p "I ran the code inside the if statement"
offset = {}
p "offset has been initialized, since it was nil"
end
p offset.nil?
p offset
%>
и вывод:
false
{"z"=>-10}
false
{"z"=>-10}
true
nil
Если я удалю оператор if, я получу ожидаемый результат:
false
{"z"=>-10}
false
{"z"=>-10}
false
{"z"=>-10}
но наличие этого оператора if (или подобного ему) очень важно. Я нашел обходной путь с помощью блока начала восстановления, который по сути делает то, что должен был делать If, но мне очень любопытно, почему это происходит.
Тройная проверка того, какой код вы на самом деле выполняете.
if offset == nil дает тот же результат; и после тройной проверки это код, который я выполняю
извини @Алекс, я неправильно понял твой вопрос, я использую if offset.nil?
точно, без опечатки
этот же код отлично ведет себя в обычном Ruby, но эта проблема возникает только внутри ERB
Я скопировал ваш код, добавил offset = :foo
в начале и запустил его с erb file.erb
, но не могу это воспроизвести.
Какая версия эрба и рубина?
Ruby 2.7.0, я не знаю, как проверить мою версию erb
@Dogbert Я тоже попробовал, и кажется, что если я определяю смещение в ERB, оно работает нормально, проблемы возникают только тогда, когда смещение передается в шаблон.
Похоже, проблема с вашим отступом. Попробуйте вместо этого: написать каждую строку между <% %> вместо использования нескольких строк и перейти оттуда, чтобы выяснить, почему ваша не сработала.
@DanielCusumano, можете ли вы создать минимальный пример, воспроизводящий проблему? stackoverflow.com/help/minimal-reproducible-example
Ruby 2.7.0 сильно устарел, возможно, вы просто столкнулись с ошибкой Ruby. Попробуйте хотя бы последнюю версию 2.7, 2.7.8, в которой будут исправлены ошибки.
gem list
покажет вам все ваши драгоценные камни и их версии.
Пожалуйста, покажите нам, как вы управляете Эрбом.
Я предполагаю, что вначале при вызове offset
вы вызываете метод, который возвращает значение {"z"=>-10}
, например. метод во включенном вспомогательном модуле.
Теперь в Ruby локальные переменные имеют приоритет перед одноименными методами. Таким образом, если существует локальная переменная с именем offset
, при ссылке на это имя вы получаете значение этой переменной, а не результат вызова метода с тем же именем.
Теперь в Ruby, когда вы определяете любой код, который может устанавливать переменную, эта переменная инициализируется с помощью nil
, даже если код, который устанавливает начальное значение, фактически никогда не запускается. Это похоже на подъем переменных в JavaScript (но не полностью):
defined?(some_variable)
# => nil
if false
some_variable = 'value'
end
defined?(some_variable)
# => "local-variable"
Таким образом, поскольку вы устанавливаете offset = {}
в теле вашего блока if, впоследствии у вас существует локальная переменная offset
, которая затеняет метод offset
.
Если вы хотите всегда вызывать метод offset
, вы можете указать Ruby вызывать этот метод, добавив круглые скобки (которые в противном случае не являются обязательными).
p offset
# => {"z"=>-10}
if offset.nil?
offset = {}
end
p offset
# => nil
p defined?(offset)
# => "local-variable"
p offset()
# => {"z"=>-10}
p defined?(offset())
# => "method"
Чтобы реализовать ваш реальный вариант использования, вы также можете использовать что-то вроде этого вместо оператора if
, чтобы установить переменную offset
либо как результат метода offset
, либо как пустой хеш, если метод возвращает nil
или false
:
offset = offset() || {}
Это имеет смысл, и ваша реализация работает отлично. Спасибо за ответ!
@DanielCusumano Если ответ оказался для вас полезным, вы можете рассмотреть возможность принять его.
сделанный! Извините, я новичок в переполнении стека
ты уверен, что у тебя есть
if offset.nil?
, а не что-то вродеif offset = nil