Module: Celluloid::FSM

Defined in:
lib/vendor/celluloid/lib/celluloid/fsm.rb

Overview

Turn concurrent objects into finite state machines Inspired by Erlang’s gen_fsm. See www.erlang.org/doc/man/gen_fsm.html

Defined Under Namespace

Modules: ClassMethods Classes: State

Constant Summary collapse

DEFAULT_STATE =

Default state name unless one is explicitly set

:default

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(klass) ⇒ Object

Included hook to extend class methods



8
9
10
11
# File 'lib/vendor/celluloid/lib/celluloid/fsm.rb', line 8

def self.included(klass)
  klass.send :include, Celluloid
  klass.send :extend,  ClassMethods
end

Instance Method Details

#current_stateObject Also known as: state

Obtain the current state of the FSM



61
62
63
# File 'lib/vendor/celluloid/lib/celluloid/fsm.rb', line 61

def current_state
  defined?(@state) ? @state : @state = self.class.default_state
end

#transition(state_name, options = {}) ⇒ Object

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



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
# File 'lib/vendor/celluloid/lib/celluloid/fsm.rb', line 73

def transition(state_name, options = {})
  state_name = state_name.to_sym
  current_state = self.class.states[@state]

  return if current_state && 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 = self.class.states[state_name]

  if !new_state and state_name == self.class.default_state
    # FIXME This probably isn't thread safe... or wise
    new_state = self.class.states[state_name] = State.new(state_name)
  end

  if new_state
    if options[:delay]
      @delayed_transition.cancel if @delayed_transition

      @delayed_transition = after(options[:delay]) do
        transition! new_state.name
        new_state.call(self)
      end

      return @delayed_transition
    end

    if defined?(@delayed_transition) and @delayed_transition
      @delayed_transition.cancel
      @delayed_transition = nil
    end

    transition! new_state.name
    new_state.call(self)
  else
    raise ArgumentError, "invalid state for #{self.class}: #{state_name}"
  end
end

#transition!(state_name) ⇒ Object

Immediate state transition with no sanity checks. “Dangerous!”



116
117
118
# File 'lib/vendor/celluloid/lib/celluloid/fsm.rb', line 116

def transition!(state_name)
  @state = state_name
end