Home > database >  Ruby console - Multiline command with exit
Ruby console - Multiline command with exit

Time:10-29

I have a simple ruby script I would like to run in the rails console, using bundle exec rails c

ids = [1, 2]

if ids.length() > 5
    puts "More than 5 ids, quitting"
    exit
end

ids.each do |id|
    puts id
end

The rails console quits the program as soon as it sees the exit command. What would be the best way around this?

CodePudding user response:

One way to do this is to use throw/catch:

ids = [1, 2]

catch(:bail) do
  if ids.length > 5
    puts "More than 5 ids, quitting"
    throw :bail
  end

  ids.each do |id|
    puts id
  end
end

catch :bail defines a block that is labeled with the symbol :bail (the name doesn't really matter). It will execute normally until you throw :bail at which point Ruby zips up the call stack until its finds a corresponding catch. If no matching catch is found an UncaughtThrowError will be raised.

This is somewhat like break but can be used in any context and to break out of deeply nested constructs.

Another alternative would be to simply define a method or raise (and rescue) an exception if the input is invalid.

CodePudding user response:

Raise ArgumentError When Passed Arguments are Somehow Invalid

There are a lot of ways to fix your code, but your essential problem is that Kernel#exit will exit both a standard REPL session and an application, not simply return from a method or break out of an if-statement. Since your code doesn't show that you're inside a method, you can't use return because there's no appropriate method or closure to return from. You could possibly work around calling #exit with nested irb sessions or the like, but that's ultimately solving the wrong problem.

In most cases, you want to raise an exception with a useful message rather than simply exit when something goes unfixably wrong. The following would do that in your application, while in an irb or pry console it will raise the exception but remain within your REPL session:

ids = [1, 2]

raise ArgumentError, "More than 5 ids: #{ids}" if ids.length > 5
ids.each { |id| puts id }

If you were inside a method, you could use #warn and then return an appropriate return value instead. However, since you are presumably inside the top-level object of your REPL, there's nothing to return from, so this is likely your best general-purpose option.

  • Related