module Statesman::Machine::ClassMethods

Attributes

initial_state[R]

Public Instance Methods

after_guard_failure(options = {}, &block) click to toggle source
# File lib/statesman/machine.rb, line 95
def after_guard_failure(options = {}, &block)
  add_callback(callback_type: :after_guard_failure, callback_class: Callback,
               from: options[:from], to: options[:to], &block)
end
after_transition(options = { after_commit: false }, &block) click to toggle source
# File lib/statesman/machine.rb, line 83
def after_transition(options = { after_commit: false }, &block)
  callback_type = options[:after_commit] ? :after_commit : :after

  add_callback(callback_type: callback_type, callback_class: Callback,
               from: options[:from], to: options[:to], &block)
end
after_transition_failure(options = {}, &block) click to toggle source
# File lib/statesman/machine.rb, line 90
def after_transition_failure(options = {}, &block)
  add_callback(callback_type: :after_transition_failure, callback_class: Callback,
               from: options[:from], to: options[:to], &block)
end
before_transition(options = {}, &block) click to toggle source
# File lib/statesman/machine.rb, line 73
def before_transition(options = {}, &block)
  add_callback(callback_type: :before, callback_class: Callback,
               from: options[:from], to: options[:to], &block)
end
callbacks() click to toggle source
# File lib/statesman/machine.rb, line 49
def callbacks
  @callbacks ||= {
    before: [],
    after: [],
    after_transition_failure: [],
    after_guard_failure: [],
    after_commit: [],
    guards: [],
  }
end
guard_transition(options = {}, &block) click to toggle source
# File lib/statesman/machine.rb, line 78
def guard_transition(options = {}, &block)
  add_callback(callback_type: :guards, callback_class: Guard,
               from: options[:from], to: options[:to], &block)
end
state(name, options = { initial: false }) click to toggle source
# File lib/statesman/machine.rb, line 36
def state(name, options = { initial: false })
  name = name.to_s
  if options[:initial]
    validate_initial_state(name)
    @initial_state = name
  end
  states << name
end
states() click to toggle source
# File lib/statesman/machine.rb, line 32
def states
  @states ||= []
end
successors() click to toggle source
# File lib/statesman/machine.rb, line 45
def successors
  @successors ||= {}
end
transition(from: nil, to: nil) click to toggle source
# File lib/statesman/machine.rb, line 60
def transition(from: nil, to: nil)
  from = to_s_or_nil(from)
  to = array_to_s_or_nil(to)

  raise InvalidStateError, "No to states provided." if to.empty?

  successors[from] ||= []

  ([from] + to).each { |state| validate_state(state) }

  successors[from] += to
end
validate_callback_condition(options = { from: nil, to: nil }) click to toggle source
# File lib/statesman/machine.rb, line 100
def validate_callback_condition(options = { from: nil, to: nil })
  from = to_s_or_nil(options[:from])
  to   = array_to_s_or_nil(options[:to])

  ([from] + to).compact.each { |state| validate_state(state) }
  return if from.nil? && to.empty?

  validate_not_from_terminal_state(from)
  to.each { |state| validate_not_to_initial_state(state) }

  return if from.nil? || to.empty?

  to.each { |state| validate_from_and_to_state(from, state) }
end
validate_from_and_to_state(from, to) click to toggle source

Check that the transition is valid when 'from' and 'to' are given

# File lib/statesman/machine.rb, line 132
def validate_from_and_to_state(from, to)
  unless successors.fetch(from, []).include?(to)
    raise InvalidTransitionError,
          "Cannot transition from '#{from}' to '#{to}'"
  end
end
validate_not_from_terminal_state(from) click to toggle source

Check that the 'from' state is not terminal

# File lib/statesman/machine.rb, line 116
def validate_not_from_terminal_state(from)
  unless from.nil? || successors.key?(from)
    raise InvalidTransitionError,
          "Cannot transition away from terminal state '#{from}'"
  end
end
validate_not_to_initial_state(to) click to toggle source

Check that the 'to' state is not initial

# File lib/statesman/machine.rb, line 124
def validate_not_to_initial_state(to)
  unless to.nil? || successors.values.flatten.include?(to)
    raise InvalidTransitionError,
          "Cannot transition to initial state '#{to}'"
  end
end

Private Instance Methods

add_callback(callback_type: nil, callback_class: nil, from: nil, to: nil, &block) click to toggle source
# File lib/statesman/machine.rb, line 141
def add_callback(callback_type: nil, callback_class: nil,
                 from: nil, to: nil, &block)
  validate_callback_type_and_class(callback_type, callback_class)

  from = to_s_or_nil(from)
  to   = array_to_s_or_nil(to)

  validate_callback_condition(from: from, to: to)

  callbacks[callback_type] <<
    callback_class.new(from: from, to: to, callback: block)
end
array_to_s_or_nil(input) click to toggle source
# File lib/statesman/machine.rb, line 176
def array_to_s_or_nil(input)
  Array(input).map { |item| to_s_or_nil(item) }
end
to_s_or_nil(input) click to toggle source
# File lib/statesman/machine.rb, line 172
def to_s_or_nil(input)
  input.nil? ? input : input.to_s
end
validate_callback_type_and_class(callback_type, callback_class) click to toggle source
# File lib/statesman/machine.rb, line 154
def validate_callback_type_and_class(callback_type, callback_class)
  raise ArgumentError, "missing keyword: callback_type" if callback_type.nil?
  raise ArgumentError, "missing keyword: callback_class" if callback_class.nil?
end
validate_initial_state(state) click to toggle source
# File lib/statesman/machine.rb, line 165
def validate_initial_state(state)
  unless initial_state.nil?
    raise InvalidStateError, "Cannot set initial state to '#{state}', " \
                             "already defined as #{initial_state}."
  end
end
validate_state(state) click to toggle source
# File lib/statesman/machine.rb, line 159
def validate_state(state)
  unless states.include?(state.to_s)
    raise InvalidStateError, "Invalid state '#{state}'"
  end
end