OT: Ruby question: alternative to begin/ensure block

Sorry for asking a purely Ruby question, but somebody on the list
knows the answer to this.

Are there any alternatives to begin/ensure blocks that can be used to
ensure that specific cleanup code gets executed?

In my particular case, I am interacting with an Excel spreadsheet
using OLE with something like:

require 'win32ole'
xl = WIN32OLE.new('Excel.Application')
begin
   do_all_of_my_spreadsheet_processing_here
ensure
   xl.Workbooks.each { |w| w.Close(false) }
   xl.Quit()
end

I want to make sure that I close all of the workbooks w/o saving, and
that the Excel application terminates if any exceptions are raised.

Using begin/ensure solves this at the expense of an added level of
indentation. What I would like to do is something along the lines of

xl = WIN32OLE.new('Excel.Application')
xl.before_going_out_of_scope do |x|
  # Cleanup connection to the Excel application so that it exits
  x.Workbooks.each { |w| w.Close(false) }
  x.Quit()
end

This has the advantage (in my mind) of keeping the cleanup code right
next to the allocation code and allows me to forget all about it as I
continue on with my application.

--wpd

Sorry for asking a purely Ruby question, but somebody on the list
knows the answer to this.

Are there any alternatives to begin/ensure blocks that can be used to
ensure that specific cleanup code gets executed?

AFAIK has to been begin/ensure (finalizers wouldn't do the trick here)

That's not to say you can't make things a little nicer (similar to
File.open):

class Excel
   def self.do_stuff
     xl = WIN32OLE.new('Excel.Application')
     yield xl
   ensure
     xl.Workbooks.each { |w| w.Close(false) }
     xl.Quit()
   end
end

Then you can do

Excel.do_stuff do |xl|
   ...
end

Fred

Sorry for asking a purely Ruby question, but somebody on the list
knows the answer to this.

Are there any alternatives to begin/ensure blocks that can be used to
ensure that specific cleanup code gets executed?

AFAIK has to been begin/ensure (finalizers wouldn't do the trick here)

Ahhh... "finalizers" look like what I wanted to use, although, as you
point out, they wouldn't do the trick here, since they don't have
access to the underlying object.

That's not to say you can't make things a little nicer (similar to
File.open):

class Excel
  def self.do_stuff
    xl = WIN32OLE.new('Excel.Application')
    yield xl
  ensure
    xl.Workbooks.each { |w| w.Close(false) }
    xl.Quit()
  end
end

Then you can do

Excel.do_stuff do |xl|
  ...
end

Thank you. I thought of doing something like that, but wrapped myself
around a pole mistakenly trying to figure out how extend the WIN32OLE
class to do something like this. You're solution is much more elegant
and solves the problem of placing the "cleanup" code next to the
"open" code, but doesn't solve the indentation problem. I think I'll
give it a shot.

Onto a slightly different topic...
I've noticed your name next to a lot of responses to newbie questions
from myself and others. I want to say thank you very much for taking
the time and effort to help us all along.

--wpd

Sorry for asking a purely Ruby question, but somebody on the list
knows the answer to this.

Are there any alternatives to begin/ensure blocks that can be used
to
ensure that specific cleanup code gets executed?

AFAIK has to been begin/ensure (finalizers wouldn't do the trick
here)

Ahhh... "finalizers" look like what I wanted to use, although, as you
point out, they wouldn't do the trick here, since they don't have
access to the underlying object.

They can do, but it still doesn't help, because you have no control
over when they run. If ruby never needs to garbage collect (and it
will only do so if memory usage hits a certain threshold) your
finalizers will never run

That's not to say you can't make things a little nicer (similar to
File.open):

class Excel
def self.do_stuff
   xl = WIN32OLE.new('Excel.Application')
   yield xl
ensure
   xl.Workbooks.each { |w| w.Close(false) }
   xl.Quit()
end
end

Then you can do

Excel.do_stuff do |xl|
...
end

Thank you. I thought of doing something like that, but wrapped myself
around a pole mistakenly trying to figure out how extend the WIN32OLE
class to do something like this. You're solution is much more elegant
and solves the problem of placing the "cleanup" code next to the
"open" code, but doesn't solve the indentation problem. I think I'll
give it a shot.

I'm not sure I get the 'indentation problem'. To me it almost sounds
like you're saying 'Well an if statement sure would do the trick, but
then i'd have to indent stuff'. If you hate the indentation that much
then just don't indent (although personally I think that will make
your code look a mess.

Fred

Onto a slightly different topic...
I've noticed your name next to a lot of responses to newbie questions
from myself and others. I want to say thank you very much for taking
the time and effort to help us all along.

don't mention it.

I'm not sure I get the 'indentation problem'. To me it almost sounds
like you're saying 'Well an if statement sure would do the trick, but
then i'd have to indent stuff'. If you hate the indentation that much
then just don't indent (although personally I think that will make
your code look a mess.

The "indentation problem" is one of excessive indentation, which can
always be solved by factoring the code. It just seems that the use of
a begin/ensure block, a File.open-like block, and even an if block,
all result in the rest of my code being indented a level uselessly.
Imagine if I had an Excel worksheet, and a Word document, and an
ActiveRecord database, etc... all competing for cleanup clauses (well,
perhaps it's a stretch with the ActiveRecord one...). I was just
hoping that magical Ruby would have some sort of:

object.before_going_out_of_scope do |x|
  x.blah
end

incantation, that would add a callback to the object. But perhaps
that adds too much overhead, and not enough feature to be of use
outside my little project.

(I know you said not to mention it, but I'm going to mention it anyway)
Thanks again.

--wpd