#
# 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