Class: CequelStatefulEnum::Machine::Event

Inherits:
Object
  • Object
show all
Defined in:
lib/cequel_stateful_enum/machine.rb

Instance Method Summary collapse

Constructor Details

#initialize(model, column, states, name, &block) ⇒ Event

Returns a new instance of Event.

Raises:



23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
# File 'lib/cequel_stateful_enum/machine.rb', line 23

def initialize(model, column, states, name, &block)
  can = "can_#{name}?"
  raise DefinitionError, "one of the #{name}, #{name}! or #{can} methods already defined" if ([name, "#{name}!", can] & model.instance_methods).any?

  @states, @name, @transitions, @before, @after = states, name, {}, [], []
  instance_eval(&block) if block

  transitions, before, after = @transitions, @before, @after

  # defining event methods
  model.class_eval do
    define_method name do |save: true, danger: false|
      next false unless send(can, danger: danger)
      to = transitions[send(column).to_sym].first
      before.each { |callback| instance_eval(&callback) }
      send("#{column}=", to)
      if save
        if danger
          save!
        else
          result = self.save
        end
      end
      after.each { |callback| instance_eval(&callback) } unless result == false
      result.nil? ? true : result
    end

    define_method "#{name}!" do |save: true|
      send(name, save: save, danger: true)
    end

    define_method can do |danger: false|
      from = send(column).to_sym
      to, condition = transitions[from]
      if !to
        raise StateError, "can't fire #{name} event from state #{from}" if danger
        false
      elsif condition && !instance_exec(&condition)
        raise ConditionError, "conditions for #{name} event does not met" if danger
        false
      else
        true
      end
    end
  end
end

Instance Method Details

#after(symbol = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


115
116
117
118
119
# File 'lib/cequel_stateful_enum/machine.rb', line 115

def after(symbol = nil, &block)
  raise ArgumentError, 'use Symbol or block for `after` callback' unless block_given? ? symbol.nil? : symbol.is_a?(Symbol)
  block ||= -> { send(symbol) }
  @after.push(block)
end

#allObject



105
106
107
# File 'lib/cequel_stateful_enum/machine.rb', line 105

def all
  @states
end

#before(symbol = nil, &block) ⇒ Object

Raises:

  • (ArgumentError)


109
110
111
112
113
# File 'lib/cequel_stateful_enum/machine.rb', line 109

def before(symbol = nil, &block)
  raise ArgumentError, 'use Symbol or block for `before` callback' unless block_given? ? symbol.nil? : symbol.is_a?(Symbol)
  block ||= -> { send(symbol) }
  @before.push(block)
end

#transition(transitions) ⇒ Object



70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
# File 'lib/cequel_stateful_enum/machine.rb', line 70

def transition(transitions)
  condition = transitions.delete(:if)
  unless condition.nil? || condition.is_a?(Symbol) || condition.respond_to?(:call)
    raise ArgumentError, "`if` condition can be nil, Symbol or callable object, but #{condition.class} given"
  end
  if condition.is_a?(Symbol)
    symbol = condition
    condition = -> { send(symbol) }
  end
  if unless_condition = transitions.delete(:unless)
    unless unless_condition.nil? || unless_condition.is_a?(Symbol) || unless_condition.respond_to?(:call)
      raise ArgumentError, "`unless` condition can be nil, Symbol or callable object, but #{unless_condition.class} given"
    end
    if unless_condition.is_a?(Symbol)
      symbol = unless_condition
      unless_condition = -> { send(symbol) }
    end
    condition = if condition
      if_condition = condition
      -> { instance_exec(&if_condition) && !instance_exec(&unless_condition) }
    else
      -> { !instance_exec(&unless_condition) }
    end
  end

  transitions.each_pair do |froms, to|
    raise DefinitionError, "undefined state #{to}" unless @states.include? to
    Array(froms).each do |from|
      raise DefinitionError, "undefined state #{from}" unless @states.include? from
      raise DefinitionError, "duplicate entry: transition from #{from} to #{@transitions[from].first} has already been defined" if @transitions[from]
      @transitions[from] = [to, condition]
    end
  end
end