Home > Software engineering >  Escaping ensure in console/rake/rails
Escaping ensure in console/rake/rails

Time:09-28

Given something like this

def infinite
  puts Time.now
rescue => err
  puts err.message
ensure
  infinite
end

When you run this in console/rake and hit ctrl-c - nothing happens. How do you escape this with CTRL-C?

CodePudding user response:

I'm not sure if this is the proper solution but this worked for me:

def infinite
  puts Time.now
rescue SystemExit, Interrupt
  @skip_ensure = true
  puts 'SystemExist/Interrupt'
rescue => err
  puts err.message
ensure
  infinite unless @skip_ensure
end

CodePudding user response:

Use catch instead which is an alternative control flow.

catch executes its block. If throw is not called, the block executes normally, and catch returns the value of the last expression evaluated.

Ruby searches up its stack for a catch block whose tag has the same object_id as the throw (symbols are almost always used as the have the same object_id). When found, the block stops executing and returns val (or nil if no second argument was given to throw).

def infinate
  catch(:done) do
    begin 
      infinite
    rescue SystemExit, Interrupt => e
      puts e.message
      throw :done
    end
  end
end

Using ensure with a condition like that is semantically wrong as the whole point of ensure is to run code that always should be run.

CodePudding user response:

Using rescue to create an infinite loop via recursion seem overly complicated and could cause a SystemStackError later on.

Why not use an actual loop:

def infinite
  loop do
    begin
      puts Time.now
    rescue => err
      puts err.message
    end
  end
end

With the above, Ctrl-C works just fine, because rescue without an explicit exception class will only handle StandardErrors.

  • Related