# File lib/state_machine/transition.rb, line 28
      def perform(transitions, options = {})
        # Validate that the transitions are for separate machines / attributes
        attributes = transitions.map {|transition| transition.attribute}.uniq
        raise ArgumentError, 'Cannot perform multiple transitions in parallel for the same state machine attribute' if attributes.length != transitions.length
        
        success = false
        
        # Run before callbacks.  If any callback halts, then the entire chain
        # is halted for every transition.
        if transitions.all? {|transition| transition.before}
          # Persist the new state for each attribute
          transitions.each {|transition| transition.persist}
          
          # Run the actions associated with each machine
          begin
            results = {}
            success =
              if block_given?
                # Block was given: use the result for each transition
                result = yield
                transitions.each {|transition| results[transition.action] = result}
                !!result
              elsif options[:action] == false
                # Skip the action
                true
              else
                # Run each transition's action (only once)
                object = transitions.first.object
                transitions.all? do |transition|
                  action = transition.action
                  action && !results.include?(action) ? results[action] = object.send(action) : true
                end
              end
          rescue Exception
            # Action failed: rollback 
            transitions.each {|transition| transition.rollback}
            raise
          end
          
          # Run after callbacks even when the actions failed. The :after option
          # is ignored if the transitions were unsuccessful.
          transitions.each {|transition| transition.after(results[transition.action], success)} unless options[:after] == false && success
          
          # Rollback the transitions if the transaction was unsuccessful
          transitions.each {|transition| transition.rollback} unless success
        end
        
        success
      end