Как написать охранную оговорку с несколькими условиями в Ruby?
После запуска Rubocop против этого кода я получаю
Use a guard clause instead of wrapping the code inside a conditional expression.
Так что из того, что я прочитал, "оговорка об охране" выйдет из метода, если условие не будет выполнено, поэтому нам не нужно тратить время на прохождение дополнительных условий, пожалуйста, исправьте меня, если мое понимание неверно.
Мой вопрос, однако, как бы я использовать охранное заявление с несколькими условиями
def auth_creds
if %w(test1 qa demo ci).include? ENV['ENV']
{ key: 'key1', secret: 'secret1' }
elsif ENV['ENV'] == 'live'
{ key: 'key2', secret: 'secret2' }
else
fail 'Unable to set key/secret'
end
end
Спасибо
3 ответа
Ваш фрагмент не является допустимым примером для "охранных статей". Там нет ничего, чтобы защититься от. Это просто выбор данных. Это выглядело бы лучше как case/when
но if
цепь тоже в порядке.
def auth_creds
case ENV['ENV']
when 'test1', 'qa', 'demo', 'ci'
{ key: 'key1', secret: 'secret1' }
when 'live'
{ key: 'key2', secret: 'secret2' }
else
fail 'Unable to set key/secret'
end
end
Охранное предложение (или, как я их называю, ранние возвраты) используется, когда все тело метода заключено в условное выражение.
def process_project
if project
# do stuff
end
end
Метод ничего не сделает, если нет project
, Так что это делает код более читабельным, если мы сократим вложение здесь.
def process_project
return unless project
# do stuff with project
end
Опять не каждый if
в вашем коде можно / нужно преобразовать в эту форму. Только там, где это уместно.
Все зависит от вашего фактического кода, но с данным фрагментом вы можете использовать пункт охраны, чтобы обеспечить действительный ENV['ENV']
значение:
VALID_ENVS = %w(test1 qa demo ci live)
def auth_creds
fail 'invalid environment' unless VALID_ENVS.include? ENV['ENV']
if ENV['ENV'] == 'live'
{ key: 'key2', secret: 'secret2' }
else
{ key: 'key1', secret: 'secret1' }
end
end
Как отметил Серхио Туленцев, ваши учетные данные хранятся в ENV
(вместо имени env), вероятно, будет лучше:
def auth_creds
{ key: ENV.fetch('KEY'), secret: ENV.fetch('SECRET') }
end
fetch
поднимет KeyError
если данный ключ не найден в ENV
,
Пункты охраны обычно идут так:
def do_something
return 'x' if some_condition?
# other code
end
Таким образом, ваш код может быть переписан как
def auth_creds
return { key: 'key1', secret: 'secret1' } if %w(test1 qa demo ci).include? ENV['ENV']
return { key: 'key2', secret: 'secret2' } if ENV['ENV'] == 'live'
fail 'Unable to set key/secret'
end
Тем не менее, это довольно уродливо, и теперь rubocop будет жаловаться на слишком длинные строки. Итак, давайте перефразируем код, чтобы описать его намерение:
def auth_creds
return { key: 'key1', secret: 'secret1' } if test_env?
return { key: 'key2', secret: 'secret2' } if live_env?
fail 'Unable to set key/secret'
end
private # omit if `auth_creds` is also private
def test_env?
%w(test1 qa demo ci).include? ENV['ENV']
end
def live_env?
ENV['ENV'] == 'live'
end
Бонусные очки: извлечение %w(test1 qa demo ci)
в постоянную!
Двойные бонусные баллы: (спасибо @Sergio Tulentsev) Извлеките из своего кода свои специфические для среды (и, вероятно, чувствительные!!!) учетные данные! Если вы используете Rails, поместите его в secrets.yml
иначе используйте для этого один из множества замечательных камней:
Несколько слов о Рубокопе: примите его совет с зерном соли. Например, ваш код на самом деле не подходит для защитного предложения, он просто возвращает данные в зависимости от условий. Таким образом, вместо этого вы можете попробовать рефакторинг кода в качестве выражения регистра.
А иногда Рубокоп просто говорит о мусоре:-) (не специально, но "измерить" стиль кода сложно!)