Статьи

Выход, выход! Прервать, поднять … Выведи меня отсюда!

Выход, Стадия слева.

Каждый раз, когда вы входите в сеанс irb, загружаете скрипт ruby ​​или запускаете тестовый прогон, вы запускаете процесс. Это касается всего в вашей системе, а не только кода Ruby. Например, то же самое верно для команд оболочки, таких как grepcattail

Мы тратим много времени и усилий на обсуждение правильного способа написания кода и обеспечения его эффективного выполнения, но как насчет того, как он оставит свой след в мире? Есть драгоценная возможность эффективно передавать информацию при выходе из процесса.

Эта статья проливает свет на то, почему важен правильный выход и как вы можете это сделать из своих программ на 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.exitKernel.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!hasitend В крайних случаях вы будете использовать do … end , Полный исходный {}bundle installздесь .

Хорошо иметь в виду, что любой человек, который будет смотреть на ваши коды выхода, наверняка оценит небольшое различие между различными ошибками, чтобы они могли понять, где они ошиблись. Предоставление вашей команде тех же соглашений, что и других общих команд, сделает вашу команду намного проще в использовании.

выход 0