class StateMachine::Path
A path represents a sequence of transitions that can be run for a particular object. Paths can walk to new transitions, revealing all of the possible branches that can be encountered in the object's state machine.
Attributes
The state machine this path is walking
The object whose state machine is being walked
Public Class Methods
Creates a new transition path for the given object. Initially this is an empty path. In order to start walking the path, it must be populated with an initial transition.
Configuration options:
-
:target
- The target state to end the path on -
:guard
- Whether to guard transitions with the if/unless conditionals defined for each one
# File lib/state_machine/path.rb 22 def initialize(object, machine, options = {}) 23 assert_valid_keys(options, :target, :guard) 24 25 @object = object 26 @machine = machine 27 @target = options[:target] 28 @guard = options[:guard] 29 end
Public Instance Methods
Determines whether or not this path has completed. A path is considered complete when one of the following conditions is met:
-
The last transition in the path ends on the target state
-
There are no more transitions remaining to walk and there is no target state
# File lib/state_machine/path.rb 85 def complete? 86 !empty? && (@target ? to_name == @target : transitions.empty?) 87 end
Lists all of the events that can be fired through this path.
For example,
path.events # => [:park, :ignite, :shift_up, ...]
# File lib/state_machine/path.rb 70 def events 71 map {|transition| transition.event}.uniq 72 end
The initial state name for this path
# File lib/state_machine/path.rb 37 def from_name 38 first && first.from_name 39 end
Lists all of the from states that can be reached through this path.
For example,
path.to_states # => [:parked, :idling, :first_gear, ...]
# File lib/state_machine/path.rb 46 def from_states 47 map {|transition| transition.from_name}.uniq 48 end
The end state name for this path. If a target state was specified for the path, then that will be returned if the path is complete.
# File lib/state_machine/path.rb 52 def to_name 53 last && last.to_name 54 end
Lists all of the to states that can be reached through this path.
For example,
path.to_states # => [:parked, :idling, :first_gear, ...]
# File lib/state_machine/path.rb 61 def to_states 62 map {|transition| transition.to_name}.uniq 63 end
Walks down the next transitions at the end of this path. This will only walk down paths that are considered valid.
# File lib/state_machine/path.rb 76 def walk 77 transitions.each {|transition| yield dup.push(transition)} 78 end
Private Instance Methods
Determines whether it's possible to walk to the given transition from the current path. A transition can be walked to if:
-
It has not been recently walked and
-
If a target is specified, it has not been walked to twice yet
# File lib/state_machine/path.rb 110 def can_walk_to?(transition) 111 !recently_walked?(transition) && (!@target || times_walked_to(@target) < 2) 112 end
Determines whether the given transition has been recently walked down in this path. If a target is configured for this path, then this will only look at transitions walked down since the target was last reached.
# File lib/state_machine/path.rb 98 def recently_walked?(transition) 99 transitions = self 100 if @target && @target != to_name && target_transition = detect {|t| t.to_name == @target} 101 transitions = transitions[index(target_transition) + 1..-1] 102 end 103 transitions.include?(transition) 104 end
Calculates the number of times the given state has been walked to
# File lib/state_machine/path.rb 91 def times_walked_to(state) 92 select {|transition| transition.to_name == state}.length 93 end
Get the next set of transitions that can be walked to starting from the end of this path
# File lib/state_machine/path.rb 116 def transitions 117 @transitions ||= empty? ? [] : machine.events.transitions_for(object, :from => to_name, :guard => @guard).select {|transition| can_walk_to?(transition)} 118 end