Module: Statesman::Machine

Defined in:
lib/statesman/machine.rb

Overview

The main module, that should be ‘extend`ed in to state machine classes.

Defined Under Namespace

Modules: ClassMethods

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(base) ⇒ Object



11
12
13
14
# File 'lib/statesman/machine.rb', line 11

def self.included(base)
  base.extend(ClassMethods)
  base.send(:attr_reader, :object)
end

.retry_conflicts(max_retries = 1) ⇒ Object

Retry any transitions that fail due to a TransitionConflictError



17
18
19
20
21
22
23
24
25
26
# File 'lib/statesman/machine.rb', line 17

def self.retry_conflicts(max_retries = 1)
  retry_attempt = 0

  begin
    yield
  rescue TransitionConflictError
    retry_attempt += 1
    retry_attempt <= max_retries ? retry : raise
  end
end

Instance Method Details

#allowed_transitionsObject



185
186
187
188
189
# File 'lib/statesman/machine.rb', line 185

def allowed_transitions
  successors_for(current_state).select do |state|
    can_transition_to?(state)
  end
end

#available_eventsObject



253
254
255
256
257
258
# File 'lib/statesman/machine.rb', line 253

def available_events
  state = current_state
  self.class.events.select do |_, transitions|
    transitions.key?(state)
  end.map(&:first)
end

#can_transition_to?(new_state, metadata = nil) ⇒ Boolean

Returns:

  • (Boolean)


195
196
197
198
199
200
201
202
# File 'lib/statesman/machine.rb', line 195

def can_transition_to?(new_state,  = nil)
  validate_transition(from: current_state,
                      to: new_state,
                      metadata: )
  true
rescue TransitionFailedError, GuardFailedError
  false
end

#current_stateObject



180
181
182
183
# File 'lib/statesman/machine.rb', line 180

def current_state
  last_action = last_transition
  last_action ? last_action.to_state : self.class.initial_state
end

#execute(phase, initial_state, new_state, transition) ⇒ Object



236
237
238
239
# File 'lib/statesman/machine.rb', line 236

def execute(phase, initial_state, new_state, transition)
  callbacks = callbacks_for(phase, from: initial_state, to: new_state)
  callbacks.each { |cb| cb.call(@object, transition) }
end

#historyObject



204
205
206
# File 'lib/statesman/machine.rb', line 204

def history
  @storage_adapter.history
end

#initialize(object, options = { transition_class: Statesman::Adapters::MemoryTransition }) ⇒ Object



169
170
171
172
173
174
175
176
177
178
# File 'lib/statesman/machine.rb', line 169

def initialize(object,
                  options = {
                    transition_class: Statesman::Adapters::MemoryTransition
                  })
  @object = object
  @transition_class = options[:transition_class]
  @storage_adapter = adapter_class(@transition_class)
                      .new(@transition_class, object, self)
  send(:after_initialize) if respond_to? :after_initialize
end

#last_transitionObject



191
192
193
# File 'lib/statesman/machine.rb', line 191

def last_transition
  @storage_adapter.last
end

#transition_to(new_state, metadata = nil) ⇒ Object



241
242
243
244
245
# File 'lib/statesman/machine.rb', line 241

def transition_to(new_state,  = nil)
  self.transition_to!(new_state, )
rescue TransitionFailedError, GuardFailedError
  false
end

#transition_to!(new_state, metadata = nil) ⇒ Object



208
209
210
211
212
213
214
215
216
217
218
219
# File 'lib/statesman/machine.rb', line 208

def transition_to!(new_state,  = nil)
  initial_state = current_state
  new_state = new_state.to_s

  validate_transition(from: initial_state,
                      to: new_state,
                      metadata: )

  @storage_adapter.create(initial_state, new_state, )

  true
end

#trigger(event_name, metadata = nil) ⇒ Object



247
248
249
250
251
# File 'lib/statesman/machine.rb', line 247

def trigger(event_name,  = nil)
  self.trigger!(event_name, )
rescue TransitionFailedError, GuardFailedError
  false
end

#trigger!(event_name, metadata = nil) ⇒ Object



221
222
223
224
225
226
227
228
229
230
231
232
233
234
# File 'lib/statesman/machine.rb', line 221

def trigger!(event_name,  = nil)
  transitions = self.class.events.fetch(event_name) do
    raise Statesman::TransitionFailedError,
          "Event #{event_name} not found"
  end

  new_state = transitions.fetch(current_state) do
    raise Statesman::TransitionFailedError,
          "State #{current_state} not found for Event #{event_name}"
  end

  transition_to!(new_state.first, )
  true
end