RAII in Ruby (Or, How to Manage Resources in Ruby) RAII in Ruby (Or, How to Manage Resources in Ruby) ruby ruby

RAII in Ruby (Or, How to Manage Resources in Ruby)


So that users don't "have to remember to do the whole begin-rescue-ensure chacha" combine rescue/ensure with yield.

class SomeResource  ...  def SomeResource.use(*resource_args)    # create resource    resource = SomeResource.new(*resource_args) # pass args direct to constructor    # export it    yield resource  rescue    # known error processing    ...  ensure    # close up when done even if unhandled exception thrown from block    resource.close  end  ...end

Client code can use it as follows:

SomeResource.use(connection_string) do | resource |  resource.do_something  ... # whatever elseend# after this point resource has been .close()d

In fact this is how File.open operates - making the first answer confusing at best (well it was to my work colleagues).

File.open("testfile") do |f|  # .. process - may include throwing exceptionsend# f is guaranteed closed after this point even if exceptions are # thrown during processing


How about yielding a resource to a block? Example:

File.open("testfile") do |f|  begin    # .. process  rescue    # .. handle error  endend


Or is the problem more of I'm still doing this too C++-like?

Yes it is since in C++ resource deallocation happens implicitly for everything on the stack. Stack unwound = resource destroyed = destructors called and from there things can be released. Since Ruby has no destructors there is no "do that when everything else is done with" place since grabage collection can be delayed several cycles from where you are. You do have finalizers but they are called "in limbo" (not everything is available to them) and they get called on GC.

Therefore if you are holding a handle to some resource that better be released you need to release it explicitly. Indeed the correct idiom to handle this kind of situation is

def with_shmoo  handle = allocate_shmoo  yield(handle)ensure  handle.closeend