module Celluloid::FSM
Simple finite state machines with integrated Celluloid timeout support Inspired by Erlang's gen_fsm (www.erlang.org/doc/man/gen_fsm.html)
Basic usage:
class MyMachine include Celluloid::FSM # NOTE: this does NOT pull in the Celluloid module end
Inside an actor:
# machine = MyMachine.new(current_actor)
Constants
- DEFAULT_STATE
Attributes
actor[R]
state[R]
Obtain the current state of the FSM
Public Class Methods
included(klass)
click to toggle source
Included hook to extend class methods
# File lib/celluloid/fsm.rb, line 23 def self.included(klass) klass.send :extend, ClassMethods end
new(actor = nil)
click to toggle source
Be kind and call super if you must redefine initialize
# File lib/celluloid/fsm.rb, line 65 def initialize(actor = nil) @state = self.class.default_state @delayed_transition = nil @actor = actor @actor ||= Celluloid.current_actor if Celluloid.actor? end
Public Instance Methods
attach(actor)
click to toggle source
Attach this FSM to an actor. This allows FSMs to wait for and initiate events in the context of a particular actor
# File lib/celluloid/fsm.rb, line 77 def attach(actor) @actor = actor end
Also aliased as: actor=
transition(state_name, options = {})
click to toggle source
Transition to another state Options:
-
delay: don't transition immediately, wait the given number of seconds.
This will return a Celluloid::Timer object you can use to cancel the pending state transition.
Note: making additional state transitions will cancel delayed transitions
# File lib/celluloid/fsm.rb, line 89 def transition(state_name, options = {}) new_state = validate_and_sanitize_new_state(state_name) return unless new_state if handle_delayed_transitions(new_state, options[:delay]) return @delayed_transition end transition_with_callbacks!(new_state) end
transition!(state_name)
click to toggle source
Immediate state transition with no sanity checks, or callbacks. “Dangerous!”
# File lib/celluloid/fsm.rb, line 101 def transition!(state_name) @state = state_name end
Protected Instance Methods
current_state()
click to toggle source
# File lib/celluloid/fsm.rb, line 140 def current_state states[@state] end
current_state_name()
click to toggle source
# File lib/celluloid/fsm.rb, line 144 def current_state_name current_state && current_state.name || "" end
default_state()
click to toggle source
# File lib/celluloid/fsm.rb, line 136 def default_state self.class.default_state end
handle_delayed_transitions(new_state, delay)
click to toggle source
# File lib/celluloid/fsm.rb, line 148 def handle_delayed_transitions(new_state, delay) if delay fail UnattachedError, "can't delay unless attached" unless @actor @delayed_transition.cancel if @delayed_transition @delayed_transition = @actor.after(delay) do transition_with_callbacks!(new_state) end return @delayed_transition end return unless defined?(@delayed_transition) && @delayed_transition @delayed_transition.cancel @delayed_transition = nil end
states()
click to toggle source
# File lib/celluloid/fsm.rb, line 132 def states self.class.states end
transition_with_callbacks!(state_name)
click to toggle source
# File lib/celluloid/fsm.rb, line 127 def transition_with_callbacks!(state_name) transition! state_name.name state_name.call(self) end
validate_and_sanitize_new_state(state_name)
click to toggle source
# File lib/celluloid/fsm.rb, line 107 def validate_and_sanitize_new_state(state_name) state_name = state_name.to_sym return if current_state_name == state_name if current_state and !current_state.valid_transition? state_name valid = current_state.transitions.map(&:to_s).join(", ") fail ArgumentError, "#{self.class} can't change state from '#{@state}' to '#{state_name}', only to: #{valid}" end new_state = states[state_name] unless new_state return if state_name == default_state fail ArgumentError, "invalid state for #{self.class}: #{state_name}" end new_state end