Консоль Ruby — Многострочная команда с выходом

#ruby #console #irb

Вопрос:

У меня есть простой скрипт ruby, который я хотел бы запустить в консоли rails, используя bundle exec rails c

 ids = [1, 2]  if ids.length() gt; 5  puts "More than 5 ids, quitting"  exit end  ids.each do |id|  puts id end  

Консоль rails завершает работу программы, как только видит команду выхода. Как бы лучше всего это обойти?

Комментарии:

1. Не ставить exit ?

2. exit указывает процессу Ruby на выход. Что вы ожидали от этого?

3. Извините, я отредактировал первый цикл, чтобы было понятнее

4. Ну, этот код на самом деле не выполняется. В качестве альтернативы, вместо exit этого вы можете установить флаг ( dont_run = true или что-то в этом роде) и завернуть код, который вы хотите пропустить, в проверку этого флага.

5. @SergioTulentsev Да. Еще лучше: поместите его в метод, который возвращает или выдает ошибку при выполнении с недопустимыми параметрами. Таким образом, автор может вызвать метод из консоли Ruby. Возможно, именно этого и хотел автор.

Ответ №1:

Один из способов сделать это-использовать throw/catch :

 ids = [1, 2]  catch(:bail) do  if ids.length gt; 5  puts "More than 5 ids, quitting"  throw :bail  end   ids.each do |id|  puts id  end end  

catch :bail определяет блок, помеченный символом :bail (название на самом деле не имеет значения). Он будет выполняться нормально до тех пор, пока вы throw :bail , и в этот момент Ruby не закроет стек вызовов, пока не найдет соответствующий улов. Если соответствующий улов не найден, будет поднята ошибка «Не пойман».

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

Другой альтернативой было бы просто определить метод или вызвать (и спасти) исключение, если ввод неверен.

Ответ №2:

Поднимите аргумент, если переданные Аргументы Каким-либо образом недействительны

Существует множество способов исправить ваш код, но ваша основная проблема заключается в том, что Kernel#exit завершит как стандартный сеанс REPL, так и приложение, а не просто вернется из метода или выйдет из оператора if. Поскольку ваш код не показывает, что вы находитесь внутри метода, вы не можете его использовать return , потому что нет подходящего метода или закрытия для возврата. Возможно, вы могли бы обойти вызов #exit с вложенными сеансами irb или чем-то подобным, но это в конечном итоге решает неправильную проблему.

В большинстве случаев вы хотите создать исключение с полезным сообщением, а не просто выйти, когда что-то пойдет не так. Следующее сделает это в вашем приложении, в то время как в консоли irb или pry это вызовет исключение, но останется в вашем сеансе REPL:

 ids = [1, 2]  raise ArgumentError, "More than 5 ids: #{ids}" if ids.length gt; 5 ids.each { |id| puts id }  

Если бы вы находились внутри метода, вы могли бы использовать #warn, а затем вместо этого вернуть соответствующее возвращаемое значение. Однако, поскольку вы, предположительно, находитесь внутри объекта верхнего уровня вашего REPL, возвращаться не из чего, так что, вероятно, это ваш лучший вариант общего назначения.