Search code examples
ruby

Getting exit status in ensure block


I'm writing a script that might exit normally in many different points in the program. The script currently always outputs a message to STDOUT in an ensure block, sorta like this:

begin
    exit
ensure
    puts "my message"
end

The problem is that if the script crashes, the message is output anyway, followed by the error messages. What I want to do is only output the message on an exit 0, something like this:

begin
  exit 1
ensure
  if is_this_a_normal_exit?()
    puts 'my messsage'
  end
end

Is there a way to do that?


Solution

  • When calling exit, this is generally Kernel#exit. This method basically throws a SystemExit exception which may eventually result in the program being exited.

    You can either rescue this exception or check it in the ensure block:

    begin
      exit
    rescue SystemExit => e
      puts "my message" if e.success?
    
      # re-raise the error to actually cause the program to exit
      raise 
    ensure
      # Here you can still add code which is executed after handling
      # (or not handling) any exceptions. If there was an exception,
      # you can access it here with the $! global variable.
    end
    

    Note that there are other possible causes of a program being exited, some of which you can't catch at all (e.g. when calling Kernel#exit! or when you or some other process sends a signal like SIGKILL to kill your program). Also, when using threads, the SystemExit exception may not be propagated to the main thread.