Class: StatefulEnum::Machine::Event

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

Direct Known Subclasses

Graph::EventDrawer, PlantUML::EventStore

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Event.



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
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
# File 'lib/stateful_enum/machine.rb', line 29

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
  new_method_name = "#{prefix}#{name}#{suffix}"

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

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

    define_method new_method_name do
      to, condition = transitions[send(column).to_sym]
      #TODO better error
      if to && (!condition || instance_exec(&condition))
        #TODO transaction?
        run_callbacks new_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, "#{new_method_name}!"
    define_method "#{new_method_name}!" do
      send(new_method_name) || raise('Invalid transition')
    end

    # def can_assign?()
    detect_enum_conflict! column, "can_#{new_method_name}?"
    define_method "can_#{new_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, "#{new_method_name}_transition"
    define_method "#{new_method_name}_transition" do
      transitions[send(column).to_sym].try! :first
    end
  end
end

Instance Method Details

#after(&block) ⇒ Object



114
115
116
# File 'lib/stateful_enum/machine.rb', line 114

def after(&block)
  @after << block
end

#allObject



106
107
108
# File 'lib/stateful_enum/machine.rb', line 106

def all
  @states
end

#before(&block) ⇒ Object



110
111
112
# File 'lib/stateful_enum/machine.rb', line 110

def before(&block)
  @before << block
end

#transition(transitions, options = {}) ⇒ Object



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
# File 'lib/stateful_enum/machine.rb', line 88

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