Class: StatefulEnum::Machine::Event

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

Direct Known Subclasses

Graph::EventDrawer, PlantUML::EventStore

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

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

Returns a new instance of Event.



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
87
88
89
# 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

Instance Attribute Details

#nameObject (readonly)

Returns the value of attribute name.



30
31
32
# File 'lib/stateful_enum/machine.rb', line 30

def name
  @name
end

#value_method_nameObject (readonly)

Returns the value of attribute value_method_name.



30
31
32
# File 'lib/stateful_enum/machine.rb', line 30

def value_method_name
  @value_method_name
end

Instance Method Details

#after(&block) ⇒ Object



117
118
119
# File 'lib/stateful_enum/machine.rb', line 117

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

#allObject



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

def all
  @states
end

#before(&block) ⇒ Object



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

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

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



91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
# 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