On Sep 18, 2008, at 9:02 AM, DMisener wrote:

> Our situation is a little more complicated:
>
> In our particular case we are creating run-time at_exit{} handlers
>
> To give a concrete example:
>
> We have a generic OpenOutputFile(...) routine which opens a "tentative
> output" file
> (output which is conditional on the module successfully completing).
> We generate a temporary work file and at_exit we rename this file to
> its "permanent name".
> If the program aborts for any reason, this rename should not happen
> ( we do leave the failed working file around for later problem
> investigation)


you can do this

at_exit {
   rename_files unless $!
}

but you can also make it vastly simpler: do not use at exit handlers

setup a global list of renames to occur, for instance

   module Rename
     Map = {}

     def file hash = {}
       src, dst, *ignored = hash.to_a.first
       Map[src.to_s] = dst.to_s
     end

      def files!
        require 'fileutils'
        Map.each{|src,dst| FileUtils.mv src, dst}
        Map.clear
      end

      extend self
   end

then, in the code, add files to be renamed

   Rename.file 'foo' => 'bar'

this does not rename the file, it only notes that it needs to be done  
later

now *as the last line of your program do*

   Rename.files!

since this line is the last line of you program, it will never execute  
under exceptional or error conditions.  if you prefer you can then  
wrap this up with an at_exit handler

at_exit {
   Rename.files! unless $!
}

but be warned - calling exit or exit! itself will set $!


cfp:~ > ruby -e'  begin; exit; ensure; p $!.class; end  '
SystemExit


so, in fact, you have to be very, very, very careful about doing  
things in at exit handlers based on 'error' conditions.  this is a bug

at_exit{ cleanup! unless $! }
exit 0

that's why a solution that does not depend on at_exit or $! is much  
better - simply defer the renaming until the very end.  it's a sure  
thing that you'll introduce bugs otherwise.


in any case it seems like you are working too hard - just 'normal'  
ruby code performs *exactly* as per your requirements anyhow

   do_the_work
   rename_the_file      # does *not* execute if previous line raises

cheers.


a @ http://codeforpeople.com/
--
we can deny everything, except that we have the possibility of being  
better. simply reflect on that.
h.h. the 14th dalai lama