def perform(op, obj, opts=nil, &block)
      op_s = op.to_s.capitalize_first
      pa = Options.get(:attribute, opts)
      attr_s = " #{pa}" if pa
      ag_s = " autogenerated" if Options.get(:autogenerated, opts)
      ctxt_s = " in context #{print_operations}" unless @operations.empty?
      logger.info(">> #{op_s}#{ag_s} #{obj.pp_s(:single_line)}#{attr_s}#{ctxt_s}...")
      # Clear the error flag.
      @error = nil
      # Push the operation on the nested operation stack.
      @operations.push(Operation.new(op, obj, opts))
      begin
        # perform the operation
        result = perform_operation(&block)
      rescue Exception => e
        # If the current operation is the immediate cause, then print the
        # error to the log.
        if @error.nil? then
          msg = "Error performing #{op} on #{obj}:\n#{e.message}\n#{obj.dump}\n#{e.backtrace.qp}"
          logger.error(msg)
          @error = e
        end
        raise e
      ensure
        # the operation is done
        @operations.pop
        # If this is a top-level operation, then clear the transient set.
        if @operations.empty? then @transients.clear end
      end
      logger.info("<< Completed #{obj.qp}#{attr_s} #{op}.")
      result
    end
def perform(op, obj, opts=nil, &block)
      op_s = op.to_s.capitalize_first
      pa = Options.get(:attribute, opts)
      attr_s = " #{pa}" if pa
      ag_s = " autogenerated" if Options.get(:autogenerated, opts)
      ctxt_s = " in context #{print_operations}" unless @operations.empty?
      logger.info(">> #{op_s}#{ag_s} #{obj.pp_s(:single_line)}#{attr_s}#{ctxt_s}...")
      # Clear the error flag.
      @error = nil
      # Push the operation on the nested operation stack.
      @operations.push(Operation.new(op, obj, opts))
      begin
        # perform the operation
        result = perform_operation(&block)
      rescue Exception => e
        # If the current operation is the immediate cause, then print the
        # error to the log.
        if @error.nil? then
          msg = "Error performing #{op} on #{obj}:\n#{e.message}\n#{obj.dump}\n#{e.backtrace.qp}"
          logger.error(msg)
          @error = e
        end
        raise e
      ensure
        # the operation is done
        @operations.pop
        # If this is a top-level operation, then clear the transient set.
        if @operations.empty? then @transients.clear end
      end
      logger.info("<< Completed #{obj.qp}#{attr_s} #{op}.")
      result
    end
Performs the operation given by the given op symbol on obj by calling the block given to this method.
 Lazy loading is suspended during the operation.

 @param [:find, :query, :create, :update, :delete] op the database operation type
 @param [Resource] obj the domain object on which the operation is performed
 @param opts (#see Operation#initialize)
 @yield the database operation block
 @return the result of calling the operation block