Как мне рано вернуться с грабли?

226

У меня есть задача rake, в которой я делаю некоторые проверки в начале, если одна из проверок не удалась, я хотел бы вернуться рано из задачи rake, я не хочу выполнять какой-либо оставшийся код.

Я думал, что решение было бы разместить возврат, где я хотел бы вернуться из кода, но я получаю следующую ошибку

unexpected return
Janak
источник

Ответы:

285

Задача Rake - это в основном блок. Блок, кроме лямбда-выражений, не поддерживает return, но вы можете перейти к следующему оператору, используя nextкоторый в задаче rake, тот же эффект, что и при использовании return в методе.

task :foo do
  puts "printed"
  next
  puts "never printed"
end

Или вы можете переместить код в метод и использовать return в методе.

task :foo do
  do_something
end

def do_something
  puts "startd"
  return
  puts "end"
end

Я предпочитаю второй выбор.

Симона Карлетти
источник
18
Мне тоже больше нравится второй. Чем больше я использую rake, тем больше мне нравится хранить нетривиальный код вне определения задачи. Не на 100% твердое правило, но кажется хорошим руководством для работы.
Майк Вудхаус
6
Я пытался с, breakи у меня есть эта ошибка: грабли прерваны! перерыв от PROC-закрытия (Полный след, выполнив задачу с --trace)
pupeno
4
Я предпочитаю использовать следующий. Почему мы должны объявлять новый метод только для поддержки раннего возврата?
Дерек Грир
5
Что вы делаете, если вы глубоко вложены в несколько блоков? ( nextработает, только если на «уровне» блока вырваться наружу.
mjs
3
Предупреждение: объявление методов в задачах Rake - плохая идея, потому что они глобальны для всех загруженных задач Rake и не имеют отношения к пространству имен. Далее используется вместо break, потому что код в блоке может вызываться несколько раз, независимо от того, что выполняет блок (вспомним метод .each).
Лесли Вильджоен
181

Вы можете использовать abort(message)внутри задачи, чтобы отменить эту задачу с сообщением.

Sergikon
источник
5
@TylerRick Нет, это Kernel # abort .
Джо Лисс
10
Этот способ лучше подходит для выхода в неуспешных ситуациях, поскольку он автоматически устанавливает состояние выхода.
Самуил
Это победитель. Также простой способ обеспечить обратную связь использования для ошибок аргумента.
Дэвид Хэмпи
Встроенный и гораздо более понятный, чем next. Любить это.
SomeSchmo
22

Я склонен использовать, abortкоторая является лучшей альтернативой в таких ситуациях, например:

task :foo do
  something = false
  abort 'Failed to proceed' unless something
end
khelll
источник
1
Но как вы abortбез выхода с 1кодом выхода? Rake-задачи часто используются в командной строке для определения успеха или неудачи. Есть ли «успешный» abort?
Джошуа Пинтер
2
Ответил на мои собственные вопросы: похоже, exitэто хороший способ успешно выйти.
Джошуа Пинтер
19

Вернуться с ошибкой ❌

Если вы возвращаетесь с ошибкой (то есть с кодом выхода 1), которую вы захотите использовать abort, она также принимает необязательный строковый параметр, который будет выведен при выходе:

task :check do

  # If any of your checks fail, you can exit early like this.
  abort( "One of the checks has failed!" ) if check_failed?

end

В командной строке:

$ rake check && echo "All good"
#=> One of the checks has failed!

Возвращайся с успехом ✅

Если вы возвращаетесь без ошибки (то есть кода выхода 0), вы захотите использовать его exit, который не принимает строковый параметр.

task :check do

  # If any of your checks fail, you can exit early like this.
  exit if check_failed?

end

В командной строке:

$ rake check && echo "All good"
#=> All good

Это важно, если вы используете это в задании cron или в чем-то, что впоследствии должно быть выполнено в зависимости от того, была ли успешна задача rake или нет.

Джошуа Пинтер
источник
11

Если вам нужно выйти из нескольких уровней блоков, вы можете использовать fail .

Например

task :something do
  [1,2,3].each do |i|
    ...
    fail "some error" if ...
  end
end

(См. Https://stackoverflow.com/a/3753955/11543 .)

MJS
источник
8

Если вы имели в виду выход из задачи по рейку, не вызывая "рейк отменен!" сообщение, которое будет напечатано, тогда вы можете использовать «abort» или «exit». Но «abort», когда используется в блоке восстановления, завершает задачу, а также печатает всю ошибку (даже без использования --trace). Так что «выход» - это то, что я использую.

ZX12R
источник
3
В общем, я думаю, что использовать «выход» вместо return / break - плохая идея, поскольку он не просто выпрыгивает из текущего proc / method / etc. - он завершает весь процесс и пропускает любой код, который, возможно, метод вызывающей стороны должен был запустить впоследствии (включая, возможно, некоторую очистку). Но для граблей, я думаю, это, вероятно, не проблема ...
Тайлер Рик
0

Я использовал nextподход, предложенный Симон Карлетти, так как при тестировании рейка задача, abortкоторая на самом деле является просто оберткой exit, не соответствует желаемому поведению.

Пример:

task auto_invoice: :environment do
  if Application.feature_disabled?(:auto_invoice)
    $stderr.puts 'Feature is disabled, aborting.'
  next
end
Артур Беляев
источник