module Statesmin::Machine
The main module, that should be `extend`ed in to state machine classes.
Attributes
current_state[R]
Public Class Methods
included(base)
click to toggle source
# File lib/statesmin/machine.rb, line 9 def self.included(base) base.extend(ClassMethods) base.send(:attr_reader, :object) end
new(object, options = {})
click to toggle source
# File lib/statesmin/machine.rb, line 172 def initialize(object, options = {}) @object = object if (new_state = options[:state] && options[:state].to_s) self.class.validate_state(new_state) @current_state = new_state else @current_state = self.class.initial_state end 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/statesmin/machine.rb, line 15 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()
click to toggle source
# File lib/statesmin/machine.rb, line 188 def allowed_transitions successors_for(current_state).select do |state| can_transition_to?(state) end end
can_transition_to?(new_state, metadata = {})
click to toggle source
# File lib/statesmin/machine.rb, line 194 def can_transition_to?(new_state, metadata = {}) validate_transition(from: current_state, to: new_state, metadata: metadata) true rescue TransitionFailedError, GuardFailedError false end
execute(phase, initial_state, new_state, transition)
click to toggle source
# File lib/statesmin/machine.rb, line 217 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
in_state?(*states)
click to toggle source
# File lib/statesmin/machine.rb, line 184 def in_state?(*states) states.flatten.any? { |state| current_state == state.to_s } end
transition_to(new_state, metadata = {}, &block)
click to toggle source
# File lib/statesmin/machine.rb, line 222 def transition_to(new_state, metadata = {}, &block) self.transition_to!(new_state, metadata, &block) rescue TransitionFailedError, GuardFailedError false end
transition_to!(new_state, metadata = {}, &block)
click to toggle source
# File lib/statesmin/machine.rb, line 203 def transition_to!(new_state, metadata = {}, &block) initial_state = current_state new_state = new_state.to_s validate_transition(from: initial_state, to: new_state, metadata: metadata) block_value = block.call(new_state, metadata) if block_given? @current_state = new_state block_value || true end
Private Instance Methods
adapter_class(transition_class)
click to toggle source
# File lib/statesmin/machine.rb, line 230 def adapter_class(transition_class) if transition_class == Statesmin::Adapters::MemoryTransition Adapters::Memory else Statesmin.storage_adapter end end
callbacks_for(phase, options = { from: nil, to: nil })
click to toggle source
# File lib/statesmin/machine.rb, line 246 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/statesmin/machine.rb, line 242 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/statesmin/machine.rb, line 250 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/statesmin/machine.rb, line 238 def successors_for(from) self.class.successors[from] || [] end
to_s_or_nil(input)
click to toggle source
# File lib/statesmin/machine.rb, line 272 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/statesmin/machine.rb, line 256 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] || [] unless successors.include?(to) raise TransitionFailedError, "Cannot transition from '#{from}' to '#{to}'" end # Call all guards, they raise exceptions if they fail guards_for(from: from, to: to).each do |guard| guard.call(@object, options[:metadata]) end end