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

machine[R]

The state machine this path is walking

object[R]

The object whose state machine is being walked

Public Class Methods

new(object, machine, options = {}) click to toggle source

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, line 22
def initialize(object, machine, options = {})
  assert_valid_keys(options, :target, :guard)
  
  @object = object
  @machine = machine
  @target = options[:target]
  @guard = options[:guard]
end

Public Instance Methods

complete?() click to toggle source

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, line 85
def complete?
  !empty? && (@target ? to_name == @target : transitions.empty?)
end
events() click to toggle source

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, line 70
def events
  map {|transition| transition.event}.uniq
end
from_name() click to toggle source

The initial state name for this path

# File lib/state_machine/path.rb, line 37
def from_name
  first && first.from_name
end
from_states() click to toggle source

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, line 46
def from_states
  map {|transition| transition.from_name}.uniq
end
to_name() click to toggle source

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, line 52
def to_name
  last && last.to_name
end
to_states() click to toggle source

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, line 61
def to_states
  map {|transition| transition.to_name}.uniq
end
walk() { |push| ... } click to toggle source

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, line 76
def walk
  transitions.each {|transition| yield dup.push(transition)}
end

Private Instance Methods

can_walk_to?(transition) click to toggle source

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, line 110
def can_walk_to?(transition)
  !recently_walked?(transition) && (!@target || times_walked_to(@target) < 2)
end
recently_walked?(transition) click to toggle source

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, line 98
def recently_walked?(transition)
  transitions = self
  if @target && @target != to_name && target_transition = detect {|t| t.to_name == @target}
    transitions = transitions[index(target_transition) + 1..-1]
  end
  transitions.include?(transition)
end
times_walked_to(state) click to toggle source

Calculates the number of times the given state has been walked to

# File lib/state_machine/path.rb, line 91
def times_walked_to(state)
  select {|transition| transition.to_name == state}.length
end
transitions() click to toggle source

Get the next set of transitions that can be walked to starting from the end of this path

# File lib/state_machine/path.rb, line 116
def transitions
  @transitions ||= empty? ? [] : machine.events.transitions_for(object, :from => to_name, :guard => @guard).select {|transition| can_walk_to?(transition)}
end