transition
Determines what to change the current state to when an event fires.
Definition
The options for a new transition uses the Hash syntax to map beginning to ending states:
transition :parked => :idling, :idling => :first_gear, :on => :ignite
# state will be `idling` if its current state is `parked`
# state will be `first_gear` if its current state is `idling`
Examples
transition all => nil, :on => :ignite # Transitions to nil regardless of the current state
transition all => :idling, :on => :ignite # Transitions to :idling regardless of the current state
transition all - [:idling, :first_gear] => :idling, :on => :ignite # Transitions every state but :idling and :first_gear to :idling
transition nil => :idling, :on => :ignite # Transitions to :idling from the nil state
transition :parked => :idling, :on => :ignite # Transitions to :idling if :parked
transition [:parked, :stalled] => :idling, :on => :ignite # Transitions to :idling if :parked or :stalled
transition :parked => same, :on => :park # Loops :parked back to :parked
transition [:parked, :stalled] => same, :on => [:park, :stall] # Loops either :parked or
# :stalled back to the same
# state on the park and stall
# events
transition all - :parked => same, :on => :noop # Loops every state but
# :parked back to the same state
# Transitions to :idling if :parked, :first_gear if :idling, or :second_gear if :first_gear
transition :parked => :idling, :idling => :first_gear, :first_gear => :second_gear, :on => :shift_up
To help define these implicit transitions see StateMachines::MatcherHelpers
Options
Verbose Transitions
Transitions can also be defined use an explicit set of configuration options:
:from
A state or array of states that can be transitioned from. If not specified, then the transition can occur for any state.
:to
The state that's being transitioned to. If not specified, then the transition will simply loop back (i.e. the state will not change).
:except_from
A state or array of states that cannot be transitioned from.
These options must be used when defining transitions within the context of a state.
Examples
transition :to => nil, :on => :park
transition :to => :idling, :on => :ignite
transition :except_from => [:idling, :first_gear], :to => :idling, :on => :ignite
transition :from => nil, :to => :idling, :on => :ignite
transition :from => [:parked, :stalled], :to => :idling, :on => :ignite
Conditions
In addition to the state requirements for each transition, a condition can also be defined to help determine whether that transition is available. These options will work on both the normal and verbose syntax.
:if
A method, proc or string to call to determine if the transition should occur.e.g.
:if => :moving?, or :if => lambda {|vehicle| vehicle.speed > 60}
The condition should return or evaluate to true or false.
:unless
A method, proc or string to call to determine if the transition should not occur. e.g.
:unless => :stopped?, or :unless => lambda {|vehicle| vehicle.speed <= 60}
The condition should return or evaluate to true or false.
Examples
transition :parked => :idling, :on => :ignite, :if => :moving?
transition :parked => :idling, :on => :ignite, :unless => :stopped?
transition :idling => :first_gear, :first_gear => :second_gear, :on => :shift_up, :if => :seatbelt_on?
transition :from => :parked, :to => :idling, :on => ignite, :if => :moving?
transition :from => :parked, :to => :idling, :on => ignite, :unless => :stopped?
Context
event
Context
Transitions are usually defined within the context of an event. All previous examples do so.
state
Context
The following is a state machines defined in the context of a state:
class Vehicle
state_machine :initial => :parked do
...
state :parked do
transition :to => :idling, :on => [:ignite, :shift_up], :if => :seatbelt_on?
def speed
0
end
end
state :first_gear do
transition :to => :second_gear, :on => :shift_up
def speed
10
end
end
state :idling, :first_gear do
transition :to => :parked, :on => :park
end
end
end
Transitions in this context don't need to specify the
from
state.
External Context
Transitions can be defined outside a state or an event:
class Vehicle
state_machine :initial => :parked do
...
transition :parked => :idling, :on => [:ignite, :shift_up]
transition :first_gear => :second_gear, :second_gear => :third_gear, :on => :shift_up
transition [:idling, :first_gear] => :parked, :on => :park
transition [:idling, :first_gear] => :parked, :on => :park
transition all - [:parked, :stalled] => :stalled, :unless => :auto_shop_busy?
end
end
You can:
- Use
:if
and:unless
conditions - Define
from
states (when in the machine context) usingall
,any
, andsame
helpers methods
Order of Operations
- Transitions are evaluated in the order in which they're defined.
If more than one transition applies to a given object, then the first transition that matches is performed
def transition(options) raise ArgumentError, 'Must specify :on event' unless options[:on] branches = [] options = options.dup event(*Array(options.delete(:on))) { branches << transition(options) } branches.length ### 1 ? branches.first : branches end