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) using all, any, and same 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
    

results matching ""

    No results matching ""