module Statesman::Machine
The main module, that should be `extend`ed in to state machine classes.
Public Class Methods
included(base)
click to toggle source
# File lib/statesman/machine.rb, line 12 def self.included(base) base.extend(ClassMethods) base.send(:attr_reader, :object) end
new(object, options = { transition_class: Statesman::Adapters::MemoryTransition, })
click to toggle source
# File lib/statesman/machine.rb, line 181 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, options ) send(:after_initialize) if respond_to? :after_initialize end
retry_conflicts(max_retries = 1) { || ... }
click to toggle source
Retry any transitions that fail due to a TransitionConflictError
# File lib/statesman/machine.rb, line 18 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
Public Instance Methods
allowed_transitions(metadata = {})
click to toggle source
# File lib/statesman/machine.rb, line 202 def allowed_transitions(metadata = {}) successors_for(current_state).select do |state| can_transition_to?(state, metadata) end end
can_transition_to?(new_state, metadata = {})
click to toggle source
# File lib/statesman/machine.rb, line 216 def can_transition_to?(new_state, metadata = {}) validate_transition(from: current_state, to: new_state, metadata: metadata) true rescue TransitionFailedError, GuardFailedError false end
current_state(force_reload: false)
click to toggle source
# File lib/statesman/machine.rb, line 193 def current_state(force_reload: false) last_action = last_transition(force_reload: force_reload) last_action ? last_action.to_state : self.class.initial_state end
execute(phase, initial_state, new_state, transition)
click to toggle source
# File lib/statesman/machine.rb, line 253 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
execute_on_failure(phase, initial_state, new_state, exception)
click to toggle source
# File lib/statesman/machine.rb, line 248 def execute_on_failure(phase, initial_state, new_state, exception) callbacks = callbacks_for(phase, from: initial_state, to: new_state) callbacks.each { |cb| cb.call(@object, exception) } end
history()
click to toggle source
# File lib/statesman/machine.rb, line 225 def history @storage_adapter.history end
in_state?(*states)
click to toggle source
# File lib/statesman/machine.rb, line 198 def in_state?(*states) states.flatten.any? { |state| current_state == state.to_s } end
last_transition(force_reload: false)
click to toggle source
# File lib/statesman/machine.rb, line 208 def last_transition(force_reload: false) @storage_adapter.last(force_reload: force_reload) end
last_transition_to(state)
click to toggle source
# File lib/statesman/machine.rb, line 212 def last_transition_to(state) history.reverse.find { |transition| transition.to_state.to_sym == state.to_sym } end
reset()
click to toggle source
# File lib/statesman/machine.rb, line 264 def reset @storage_adapter.reset end
transition_to(new_state, metadata = {})
click to toggle source
# File lib/statesman/machine.rb, line 258 def transition_to(new_state, metadata = {}) transition_to!(new_state, metadata) rescue TransitionFailedError, GuardFailedError false end
transition_to!(new_state, metadata = {})
click to toggle source
# File lib/statesman/machine.rb, line 229 def transition_to!(new_state, metadata = {}) initial_state = current_state new_state = new_state.to_s validate_transition(from: initial_state, to: new_state, metadata: metadata) @storage_adapter.create(initial_state, new_state, metadata) true rescue TransitionFailedError => e execute_on_failure(:after_transition_failure, initial_state, new_state, e) raise rescue GuardFailedError => e execute_on_failure(:after_guard_failure, initial_state, new_state, e) raise end
Private Instance Methods
adapter_class(transition_class)
click to toggle source
# File lib/statesman/machine.rb, line 270 def adapter_class(transition_class) if transition_class == Statesman::Adapters::MemoryTransition Adapters::Memory else Statesman.storage_adapter end end
callbacks_for(phase, options = { from: nil, to: nil })
click to toggle source
# File lib/statesman/machine.rb, line 286 def callbacks_for(phase, options = { from: nil, to: nil }) select_callbacks_for(self.class.callbacks[phase], options) end
guards_for(options = { from: nil, to: nil })
click to toggle source
# File lib/statesman/machine.rb, line 282 def guards_for(options = { from: nil, to: nil }) select_callbacks_for(self.class.callbacks[:guards], options) end
select_callbacks_for(callbacks, options = { from: nil, to: nil })
click to toggle source
# File lib/statesman/machine.rb, line 290 def select_callbacks_for(callbacks, options = { from: nil, to: nil }) from = to_s_or_nil(options[:from]) to = to_s_or_nil(options[:to]) callbacks.select { |callback| callback.applies_to?(from: from, to: to) } end
successors_for(from)
click to toggle source
# File lib/statesman/machine.rb, line 278 def successors_for(from) self.class.successors[from] || [] end
to_s_or_nil(input)
click to toggle source
# File lib/statesman/machine.rb, line 309 def to_s_or_nil(input) input.nil? ? input : input.to_s end
validate_transition(options = { from: nil, to: nil, metadata: nil })
click to toggle source
# File lib/statesman/machine.rb, line 296 def validate_transition(options = { from: nil, to: nil, metadata: nil }) from = to_s_or_nil(options[:from]) to = to_s_or_nil(options[:to]) successors = self.class.successors[from] || [] raise TransitionFailedError.new(from, to) unless successors.include?(to) # Call all guards, they raise exceptions if they fail guards_for(from: from, to: to).each do |guard| guard.call(@object, last_transition, options[:metadata]) end end