class StateMachine::Transition

@abstract Subclass and override {#event_description}, {#arm} and {#unarm} to implement a custom Transition class.

Attributes

event_type[RW]

@return [Symbol] Metaclass attribute, contains the key that

is used for generating the specific transition via {#make}.
destination_state[R]

@return [State] the state that the transition leads to.

event_trigger_value[R]

@return [Object] a more specific object that triggers

the transition.
options[R]

@return [Hash] configuration options of the transition.

source_state[R]

@return [State] the state from which the transition starts.

state_machine[R]

@return [Base] the state machine that this transition belongs to.

Public Class Methods

make(options) click to toggle source

Creates a new {Transition} object with the given options. The returned object’s subclass is determined by the :type option.

@param options [Hash] Configuration options for the transition. @option options [Symbol] :type Type identifier for the transition, ex. :on, :after, :on_notification.

See {#initialize} for all possible options.

@example

StateMachine::Transition.make type: :to, ... # => #<StateMachine::Transition:...>

@return [Transition] a new object with the class that fits the given :type option.

# File lib/motion-state-machine/transition.rb, line 56
def self.make(options)
  klass = @@types_to_subclasses[options[:type]]
  klass.new options
end
new(options) click to toggle source

Initializes a new {Transition} between two given states.

Additionally, you must also supply an event trigger value as option. Its key must be equal to the transition class’s event_type., ex. if event_type is :on, you have to supply the event value using the option key :on.

@param options [Hash] Configuration options for the transition.

@option options [StateMachine::Base] :state_machine

State machine that the transition belongs to.

@option options [Symbol] :from

State where the transition begins.

@option options [Symbol] :to

State where the transition ends.

@option options [Proc] :if (nil)

Block that should return a +Boolean+. If the block returns
+false+, the transition will be blocked and not executed
(optional).

@option options [Proc] :unless (nil)

Block that should return a +Boolean+. If the block returns
+true+, the transition will be blocked and not executed
(optional).

@option options [Boolean] :internal (false)

If set to true, the transition will not leave it's source
state: Entry and Exit actions will not be called in this case.
For internal transitions, +:from+ and +:to+ must be the same
(optional).

@note This method should not be used directly. To create Transition objects, use {#make} instead.

# File lib/motion-state-machine/transition.rb, line 98
def initialize(options)
  @options = options.dup
  @state_machine = @options.delete :state_machine
  @source_state = @state_machine.state options[:from]
  @destination_state = @state_machine.state options[:to]

  event_type = self.class.event_type
  if event_type.nil?
    raise RuntimeError, "#{self.class} has no defined event type."
  end

  [:from, :to].each do |symbol|
    unless options[symbol].is_a?(Symbol)
      raise ":#{symbol} option must be given as symbol."
    end
  end

  @event_trigger_value = options[event_type]
  if @event_trigger_value.nil?
    raise ArgumentError, "You must supply an event trigger value."
  end

  if options[:internal] && options[:from] != options[:to]
    raise ArgumentError,
      "Internal states must have same source and destination state."
  end
end
types() click to toggle source

@return [Array<Class<Transition>>] a list of all registered transition subclasses

# File lib/motion-state-machine/transition.rb, line 38
def self.types
  @@types_to_subclasses.keys
end

Protected Class Methods

type(type_symbol) click to toggle source

Defines a Hash key symbol that is unique to a {Transition} subclass. The key is used by {#make} to identify which {Transition} subclass should be created.

@param [Symbol] type_symbol

Unique symbol identifying your transition subclass.
# File lib/motion-state-machine/transition.rb, line 169
def self.type(type_symbol)
  unless type_symbol.is_a?(Symbol)
    raise ArgumentError, "Type must be given as symbol."
  end
  if @@types_to_subclasses[type_symbol].nil?
    @@types_to_subclasses[type_symbol] = self
  else
    other_class = @@types_to_subclasses[type_symbol]
    raise ArgumentError,
      "Can't register :#{type_symbol} twice, "
      "already used by #{other_class}."
  end
  @event_type = type_symbol
end

Public Instance Methods

allowed?() click to toggle source

@return [Boolean] Asks the guard blocks given for :if and

+:unless+ if the transition is allowed. Returns +true+ if the
transition is allowed to be executed.
# File lib/motion-state-machine/transition.rb, line 131
def allowed?
  if_guard = options[:if]
  unless if_guard.nil?
    return false unless if_guard.call(@state_machine)
  end
  unless_guard = options[:unless]
  unless unless_guard.nil?
    return false if unless_guard.call(@state_machine)
  end
  true
end
event_description() click to toggle source

@return [String] a short description of the event.

Used for debug output.
# File lib/motion-state-machine/transition.rb, line 147
def event_description
  # Implement this in a subclass.
  "after unclassified event"
end
inspect() click to toggle source
# File lib/motion-state-machine/transition.rb, line 153
def inspect
  "#<#{self.class.name}:0x#{object_id.to_s(16)} "\
  "#{event_description} @options=#{options.inspect}>"
end

Protected Instance Methods

handle_in_source_state() click to toggle source

Delegates handling the transition to the source state, which makes sure that there are no ambiguous transitions for the same event.

# File lib/motion-state-machine/transition.rb, line 189
def handle_in_source_state
  if @state_machine.initial_queue.nil?
    raise RuntimeError, "State machine not started yet."
  end

  if Dispatch::Queue.current.to_s != @state_machine.initial_queue.to_s
    raise RuntimeError,
      "#{self.class.event_type}:#{@event_trigger_value} must be "\
      "called from the queue where the state machine was started."
  end

  @source_state.send :guarded_execute,
    self.class.event_type,
    @event_trigger_value
end

Private Instance Methods

arm() click to toggle source

Called by source {State} when it is entered. Allows the transition to initialize a mechanism that catches its trigger event. Override this in a subclass.

# File lib/motion-state-machine/transition.rb, line 243
def arm
end
event_log_text() click to toggle source

@return [String] Debug string that can be logged after the

transition has been executed.
# File lib/motion-state-machine/transition.rb, line 228
def event_log_text
            if @options[:internal]
                    "#{@state_machine.name} still #{destination_state.name} "\
    "#{event_description} (internal transition, not exiting state)."
            else
                            "#{@state_machine.name} #{destination_state.name} "\
    "#{event_description}."
  end
end
unarm() click to toggle source

Called by source {State} when it is exited. Subclass implementations should deactivate their triggering mechanism in this method.

# File lib/motion-state-machine/transition.rb, line 251
def unarm
end
unguarded_execute() click to toggle source

Executed the transition directly, without checking the guard blocks. Calls {State#exit!} on the source state, executes the transition’s :action block and calls {State#enter!} on the destination state.

# File lib/motion-state-machine/transition.rb, line 214
def unguarded_execute
  @source_state.send :exit! unless @options[:internal] == true
  # Could use @state_machine.instance_eval(&options[:action]) here,
  # but this would be much slower
  @options[:action] && @options[:action].call(@state_machine)
  @destination_state.send :enter! unless @options[:internal] == true

  @state_machine.log "#{event_log_text}"
end