# # i ran into this slippery bug below which, although it uses idiomatic ruby, # royally botches transaction semantics. read it carefully and then examine # the output in the __END__ block below. the moral: # # *never* use rescue to perform an action, like commiting a transaction, which # must always occur. if *always* is in your mind use ensure. # def (Db = Object.new).execute string puts string end def (UnSafe = Db.clone).transaction begin execute 'BEGIN' yield execute 'COMMIT' rescue Object => e execute 'ROLLBACK' end end def (Safe = Db.clone).transaction execute 'BEGIN' begin yield ensure if $! execute 'ROLLBACK' raise e else execute 'COMMIT' end end end def perform on on.transaction do on.execute 'select 42' return end end puts '---' perform UnSafe puts '---' perform Safe # # output from running the code # __END__ --- BEGIN select 42 --- BEGIN select 42 COMMIT