I've recently started programming in Ruby, and I am looking at exception handling.
I was wondering if ensure
was the Ruby equivalent of finally
in C#? Should I have:
file = File.open("myFile.txt", "w")
begin
file << "#{content} \n"
rescue
#handle the error here
ensure
file.close unless file.nil?
end
or should I do this?
#store the file
file = File.open("myFile.txt", "w")
begin
file << "#{content} \n"
file.close
rescue
#handle the error here
ensure
file.close unless file.nil?
end
Does ensure
get called no matter what, even if an exception isn't raised?
This is why we need
ensure
:Yes,
ensure
ensures that the code is always evaluated. That's why it's calledensure
. So, it is equivalent to Java's and C#'sfinally
.The general flow of
begin
/rescue
/else
/ensure
/end
looks like this:You can leave out
rescue
,ensure
orelse
. You can also leave out the variables in which case you won't be able to inspect the exception in your exception handling code. (Well, you can always use the global exception variable to access the last exception that was raised, but that's a little bit hacky.) And you can leave out the exception class, in which case all exceptions that inherit fromStandardError
will be caught. (Please note that this does not mean that all exceptions are caught, because there are exceptions which are instances ofException
but notStandardError
. Mostly very severe exceptions that compromise the integrity of the program such asSystemStackError
,NoMemoryError
,SecurityError
,NotImplementedError
,LoadError
,SyntaxError
,ScriptError
,Interrupt
,SignalException
orSystemExit
.)Some blocks form implicit exception blocks. For example, method definitions are implicitly also exception blocks, so instead of writing
you write just
or
The same applies to
class
definitions andmodule
definitions.However, in the specific case you are asking about, there is actually a much better idiom. In general, when you work with some resource which you need to clean up at the end, you do that by passing a block to a method which does all the cleanup for you. It's similar to a
using
block in C#, except that Ruby is actually powerful enough that you don't have to wait for the high priests of Microsoft to come down from the mountain and graciously change their compiler for you. In Ruby, you can just implement it yourself:And what do you know: this is already available in the core library as
File.open
. But it is a general pattern that you can use in your own code as well, for implementing any kind of resource cleanup (à lausing
in C#) or transactions or whatever else you might think of.The only case where this doesn't work, if acquiring and releasing the resource are distributed over different parts of the program. But if it is localized, as in your example, then you can easily use these resource blocks.
BTW: in modern C#,
using
is actually superfluous, because you can implement Ruby-style resource blocks yourself:If you want to ensure a file is closed you should use the block form of
File.open
:Yes,
ensure
ENSURES it is run every time, so you don't need thefile.close
in thebegin
block.By the way, a good way to test is to do:
You can test to see if "=========inside ensure block" will be printed out when there is an exception. Then you can comment out the statement that raises the error and see if the
ensure
statement is executed by seeing if anything gets printed out.FYI, even if an exception is re-raised in the
rescue
section, theensure
block will be executed before the code execution continues to the next exception handler. For instance:Yes,
ensure
likefinally
guarantees that the block will be executed. This is very useful for making sure that critical resources are protected e.g. closing a file handle on error, or releasing a mutex.