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)
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 75 def attach(actor) @actor = actor end
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 87 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
# File lib/celluloid/fsm.rb, line 138 def current_state states[@state] end
# File lib/celluloid/fsm.rb, line 142 def current_state_name current_state && current_state.name || '' end
# File lib/celluloid/fsm.rb, line 134 def default_state self.class.default_state end
# File lib/celluloid/fsm.rb, line 146 def handle_delayed_transitions(new_state, delay) if delay raise 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 if defined?(@delayed_transition) and @delayed_transition @delayed_transition.cancel @delayed_transition = nil end end
# File lib/celluloid/fsm.rb, line 130 def states self.class.states end
# File lib/celluloid/fsm.rb, line 125 def transition_with_callbacks!(state_name) transition! state_name.name state_name.call(self) end
# File lib/celluloid/fsm.rb, line 105 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 not current_state.valid_transition? state_name valid = current_state.transitions.map(&:to_s).join(", ") raise 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 raise ArgumentError, "invalid state for #{self.class}: #{state_name}" end new_state end
Generated with the Darkfish Rdoc Generator 2.