Выход, Стадия слева.
Каждый раз, когда вы входите в сеанс irb, загружаете скрипт ruby или запускаете тестовый прогон, вы запускаете процесс. Это касается всего в вашей системе, а не только кода Ruby. Например, то же самое верно для команд оболочки, таких как grep
cat
tail
Мы тратим много времени и усилий на обсуждение правильного способа написания кода и обеспечения его эффективного выполнения, но как насчет того, как он оставит свой след в мире? Есть драгоценная возможность эффективно передавать информацию при выходе из процесса.
Эта статья проливает свет на то, почему важен правильный выход и как вы можете это сделать из своих программ на Ruby.
Код, вид выхода
Когда процесс завершается, он всегда делает это с кодом выхода. Код выхода — это числовое значение от 0 до 255. В мире Unix существует соглашение, что код выхода, равный 0, означает, что программа была успешной. Любой другой код выхода обозначает какой-то сбой.
Почему выходные коды имеют значение?
Коды выхода являются связью.
Базовый вариант для кодов выхода — это успех, вы надеетесь, что ваш процесс завершается успешно каждый раз. В случае, если что-то пошло не так, вы можете указать до 255 различных причин сбоя. Коды выхода имеют решающее значение для предоставления общего способа понимания и сообщения о случаях отказа пользователям, чтобы они могли исправить действие.
Кроме того, если вы не уверены, что коды выхода являются чем-то, о чем стоит заботиться, задумайтесь над кодами состояния HTTP; в случае ответа об ошибке существует множество кодов состояния, обозначающих причину сбоя запроса, которые сообщают пользователю, что ему следует делать дальше. Как вы думаете, вдохновили HTTP коды состояния?
Пример без Ruby
Мы начнем с рассмотрения команды grep
Обратите внимание, что я использую zsh с setopt printexitvalue
$ echo foo | grep bar
zsh: done echo foo |
zsh: exit 1 grep bar
В этом примере мы напечатали строку «foo» и добавили «bar». Очевидно, это не будет соответствовать. zsh сообщает нам, что команда echo
Команда grep
Для команды grep
Сравните это с:
$ echo foo | grep foo
foo
В этом примере он мог соответствовать строке ‘foo’ и успешно завершился. Кроме того, zsh не говорит нам, что все прошло успешно.
Теперь посмотрим, что происходит, когда мы отправляем неверную опцию в grep
$ echo foo | grep --whodunnit foo
grep: unrecognized option `--whodunnit'
Usage: grep [OPTION]... PATTERN [FILE]...
Try `grep --help' for more information.
zsh: done echo foo |
zsh: exit 2 grep --whodunnit foo
На этот раз мы передали неизвестную опцию grep
Итак, мы знаем, что для grep
если код выхода был 2, то команда не используется должным образом.
Развертывания на основе кода выхода
Еще один пример, показывающий важность кодов выхода, прежде чем мы углубимся в то, как их указывать в Ruby.
Вы когда-нибудь использовали свой код?
rake test && cap deploy
Возможно, вы знакомы с &&
Он объединяет две команды вместе, указывая, что вторая команда должна выполняться только в случае успешного завершения первой команды. Успешный выход означает выход с кодом 0.
Любой тестировщик Ruby достаточно умен, чтобы выйти с ненулевым кодом завершения в случае сбоя теста. Это пример того, что ошибок печати на консоли недостаточно. Правильное использование кодов выхода позволяет командам работать вместе в сценариях и позволяет автоматизировать задачи.
Базовый случай
Если вы никогда не писали тестовый прогон или программу командной строки, то есть хороший шанс, что вам никогда не понадобилось использовать один из явных методов для выхода из вашей программы Ruby. Итак, что произойдет, если вы не используете один?
Базовый случай, когда Ruby завершает работу после выполнения всего вашего кода, — это успешный выход! Там нет ничего удивительного. Если вы не укажете иначе, ваш процесс завершится с кодом 0.
Рано освобождать
Первая ситуация, когда вы хотите явно использовать одно из операторов выхода, это, вероятно, когда вы хотите выйти из процесса перед выполнением всего кода.
Допустим, у вас был скрипт на Ruby под названием hasit
Сценарий принимает шаблон в качестве первого аргумента и некоторые данные из STDIN. Если какая-либо строка во входных данных совпадает с шаблоном, сценарий успешно завершается. Если он доходит до конца и не находит совпадений, он завершается с кодом 1.
Вот сценарий целиком.
#!/usr/bin/env ruby
pattern = ARGV.shift
data = ARGF.read
data.each_line do |line|
exit if line.match(pattern)
end
exit 1
Он выходит рано, используя Kernel.exit
Вызов этого метода без аргумента завершится с кодом выхода 0.
Провал
В последней строке скрипта видно, что вы можете передать целочисленный аргумент в Kernel.exit
Kernel.abort
Что если в этом случае мы оцениваем сообщение об ошибке, а не просто код выхода? abort
Вызов ...
data.each_line do |line|
exit if line.match(pattern)
end
abort "No matches found" Давайте обновим скрипт для выхода с сообщением:
hasit
С любым из этих методов наш скрипт $ hasit debugger lib/* && echo "Don't commit debuggers..."
$ hasit debugger lib/* || cap deploy
Kernel.at_exit
Уборка после себя
Идти рука об руку с правильными кодами выхода — малоизвестная, но полезная особенность обработчиков Ruby: at_exit.
...
at_exit {
# cleanup temp files
# close open connections
}
data.each_line do |line|
exit if line.match(pattern)
end
abort "No matches found"Kernel.exit!
Kernel.exit
Теперь, независимо от того, какой метод использует ваш процесс для выхода, вы можете рассчитывать на этот блок кода, вызываемый перед выходом. За исключением одного случая! Есть метод Kernel.exit
(обратите внимание на взрыв), который ведет себя точно так же, как Kernel.abort
Этот метод может быть использован для немедленного выхода из процесса, пропуская любые обработчики выхода в пути.
Падение сквозь трещины
Последний способ выхода из процесса — необработанное исключение. Это то, чего вы никогда не захотите сделать в производственном приложении, но это происходит постоянно, например, при выполнении тестов.
Необработанное исключение установит для вашего кода выхода значение 1 и напечатает сведения об исключении в STDERR.
Мой стильный выход
Как правило, если вы пишете приложение для командной строки, вы захотите использовать Kernel.exit!
hasit
end
В крайних случаях вы будете использовать do … end
, Полный исходный {}
bundle install
здесь .
Хорошо иметь в виду, что любой человек, который будет смотреть на ваши коды выхода, наверняка оценит небольшое различие между различными ошибками, чтобы они могли понять, где они ошиблись. Предоставление вашей команде тех же соглашений, что и других общих команд, сделает вашу команду намного проще в использовании.
выход 0