class EnumStateMachine::TransitionCollection
Represents a collection of transitions in a state machine
Attributes
Whether to skip running the action for each transition's machine
Whether to skip running the after callbacks
Whether transitions should wrapped around a transaction block
Public Class Methods
Creates a new collection of transitions that can be run in parallel. Each transition must be for a different attribute.
Configuration options:
-
:actions
- Whether to run the action configured for each transition -
:after
- Whether to run after callbacks -
:transaction
- Whether to wrap transitions within a transaction
# File lib/enum_state_machine/transition_collection.rb 22 def initialize(transitions = [], options = {}) 23 super(transitions) 24 25 # Determine the validity of the transitions as a whole 26 @valid = all? 27 reject! {|transition| !transition} 28 29 attributes = map {|transition| transition.attribute}.uniq 30 raise ArgumentError, 'Cannot perform multiple transitions in parallel for the same state machine attribute' if attributes.length != length 31 32 assert_valid_keys(options, :actions, :after, :transaction) 33 options = {:actions => true, :after => true, :transaction => true}.merge(options) 34 @skip_actions = !options[:actions] 35 @skip_after = !options[:after] 36 @use_transaction = options[:transaction] 37 end
Public Instance Methods
Runs each of the collection's transitions in parallel.
All transitions will run through the following steps:
-
Before callbacks
-
Persist state
-
Invoke action
-
After callbacks (if configured)
-
Rollback (if action is unsuccessful)
If a block is passed to this method, that block will be called instead of invoking each transition's action.
# File lib/enum_state_machine/transition_collection.rb 50 def perform(&block) 51 reset 52 53 if valid? 54 if use_event_attributes? && !block_given? 55 each do |transition| 56 transition.transient = true 57 transition.machine.write(object, :event_transition, transition) 58 end 59 60 run_actions 61 else 62 within_transaction do 63 catch(:halt) { run_callbacks(&block) } 64 rollback unless success? 65 end 66 end 67 end 68 69 if actions.length == 1 && results.include?(actions.first) 70 results[actions.first] 71 else 72 success? 73 end 74 end
Private Instance Methods
Gets the list of actions to run. If configured to skip actions, then this will return an empty collection.
# File lib/enum_state_machine/transition_collection.rb 102 def actions 103 empty? ? [nil] : map {|transition| transition.action}.uniq 104 end
Wraps the given block with a rescue handler so that any exceptions that occur will automatically result in the transition rolling back any changes that were made to the object involved.
# File lib/enum_state_machine/transition_collection.rb 168 def catch_exceptions 169 begin 170 yield 171 rescue Exception 172 rollback 173 raise 174 end 175 end
Gets the object being transitioned
# File lib/enum_state_machine/transition_collection.rb 96 def object 97 first.object 98 end
Transitions the current value of the object's states to those specified by each transition
# File lib/enum_state_machine/transition_collection.rb 139 def persist 140 each {|transition| transition.persist} 141 end
Resets any information tracked from previous attempts to perform the collection
# File lib/enum_state_machine/transition_collection.rb 115 def reset 116 @results = {} 117 @success = false 118 end
Rolls back changes made to the object's states via each transition
# File lib/enum_state_machine/transition_collection.rb 161 def rollback 162 each {|transition| transition.rollback} 163 end
Runs the actions for each transition. If a block is given method, then it will be called instead of invoking each transition's action.
The results of the actions will be used to determine success?
.
# File lib/enum_state_machine/transition_collection.rb 147 def run_actions 148 catch_exceptions do 149 @success = if block_given? 150 result = yield 151 actions.each {|action| results[action] = result} 152 !!result 153 else 154 actions.compact.each {|action| !skip_actions && results[action] = object.send(action)} 155 results.values.all? 156 end 157 end 158 end
Runs each transition's callbacks recursively. Once all before callbacks have been executed, the transitions will then be persisted and the configured actions will be run.
If any transition fails to run its callbacks, :halt will be thrown.
# File lib/enum_state_machine/transition_collection.rb 125 def run_callbacks(index = 0, &block) 126 if transition = self[index] 127 throw :halt unless transition.run_callbacks(:after => !skip_after) do 128 run_callbacks(index + 1, &block) 129 {:result => results[transition.action], :success => success?} 130 end 131 else 132 persist 133 run_actions(&block) 134 end 135 end
Did each transition perform successfully? This will only be true if the following requirements are met:
-
No
before
callbacks halt -
All actions run successfully (always true if skipping actions)
# File lib/enum_state_machine/transition_collection.rb 91 def success? 92 @success 93 end
Determines whether an event attribute be used to trigger the transitions in this collection or whether the transitions be run directly outside of the action.
# File lib/enum_state_machine/transition_collection.rb 109 def use_event_attributes? 110 !skip_actions && !skip_after && actions.all? && actions.length == 1 && first.machine.action_hook? 111 end
Is this a valid set of transitions? If the collection was creating with any false
values for transitions, then the the collection will be marked as invalid.
# File lib/enum_state_machine/transition_collection.rb 83 def valid? 84 @valid 85 end
Runs a block within a transaction for the object being transitioned. If transactions are disabled, then this is a no-op.
# File lib/enum_state_machine/transition_collection.rb 179 def within_transaction 180 if use_transaction && !empty? 181 first.within_transaction do 182 yield 183 success? 184 end 185 else 186 yield 187 end 188 end