class StatefulEnum::Machine::Event

Attributes

name[R]
value_method_name[R]

Public Class Methods

new(model, column, states, prefix, suffix, name, &block) click to toggle source
# File lib/stateful_enum/machine.rb, line 32
def initialize(model, column, states, prefix, suffix, name, &block)
  @states, @name, @transitions, @before, @after = states, name, {}, [], []

  instance_eval(&block) if block

  transitions, before, after = @transitions, @before, @after
  @value_method_name = value_method_name = :"#{prefix}#{name}#{suffix}"

  # defining event methods
  model.class_eval do
    # def assign()
    detect_enum_conflict! column, value_method_name

    # defining callbacks
    define_callbacks value_method_name
    before.each do |before_callback|
      model.set_callback value_method_name, :before, before_callback
    end
    after.each do |after_callback|
      model.set_callback value_method_name, :after, after_callback
    end

    define_method value_method_name do
      to, condition = transitions[send(column).to_sym]
      #TODO better error
      if to && (!condition || instance_exec(&condition))
        #TODO transaction?
        run_callbacks value_method_name do
          original_method = self.class.send(:_enum_methods_module).instance_method "#{prefix}#{to}#{suffix}!"
          original_method.bind(self).call
        end
      else
        false
      end
    end

    # def assign!()
    detect_enum_conflict! column, "#{value_method_name}!"
    define_method "#{value_method_name}!" do
      send(value_method_name) || raise('Invalid transition')
    end

    # def can_assign?()
    detect_enum_conflict! column, "can_#{value_method_name}?"
    define_method "can_#{value_method_name}?" do
      state = send(column).to_sym
      return false unless transitions.key? state
      _to, condition = transitions[state]
      !condition || instance_exec(&condition)
    end

    # def assign_transition()
    detect_enum_conflict! column, "#{value_method_name}_transition"
    define_method "#{value_method_name}_transition" do
      transitions[send(column).to_sym].try! :first
    end
  end
end

Public Instance Methods

after(&block) click to toggle source
# File lib/stateful_enum/machine.rb, line 117
def after(&block)
  @after << block
end
all() click to toggle source
# File lib/stateful_enum/machine.rb, line 109
def all
  @states
end
before(&block) click to toggle source
# File lib/stateful_enum/machine.rb, line 113
def before(&block)
  @before << block
end
transition(transitions, options = {}) click to toggle source
# File lib/stateful_enum/machine.rb, line 91
def transition(transitions, options = {})
  if options.blank?
    options[:if] = transitions.delete :if
    #TODO should err if if & unless were specified together?
    if (unless_condition = transitions.delete :unless)
      options[:if] = -> { !instance_exec(&unless_condition) }
    end
  end
  transitions.each_pair do |from, to|
    raise "Undefined state #{to}" unless @states.include? to
    Array(from).each do |f|
      raise "Undefined state #{f}" unless @states.include? f
      raise "Duplicate entry: Transition from #{f} to #{@transitions[f].first} has already been defined." if @transitions[f]
      @transitions[f] = [to, options[:if]]
    end
  end
end