class StateMachine::Transition
@abstract Subclass and override {#event_description}, {#arm} and {#unarm} to implement a custom Transition
class.
Attributes
@return [Symbol] Metaclass attribute, contains the key that
is used for generating the specific transition via {#make}.
@return [State] the state that the transition leads to.
@return [Object] a more specific object that triggers
the transition.
@return [Hash] configuration options of the transition.
@return [State] the state from which the transition starts.
@return [Base] the state machine that this transition belongs to.
Public Class Methods
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
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
@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
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
@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
@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
# 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
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
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
@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
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
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