simple_state_machine 0.5.2 → 0.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/build.yml +46 -0
  3. data/.gitignore +3 -0
  4. data/.travis.yml +17 -0
  5. data/Changelog.rdoc +16 -0
  6. data/Gemfile +7 -0
  7. data/README.rdoc +154 -99
  8. data/examples/conversation.rb +5 -5
  9. data/examples/lamp.rb +5 -5
  10. data/examples/relationship.rb +8 -8
  11. data/examples/traffic_light.rb +3 -3
  12. data/examples/user.rb +8 -4
  13. data/gemfiles/Gemfile.activerecord-5.2.x +9 -0
  14. data/gemfiles/Gemfile.activerecord-6.0.x +9 -0
  15. data/gemfiles/Gemfile.activerecord-6.1.x +8 -0
  16. data/gemfiles/Gemfile.activerecord-main.x +9 -0
  17. data/gemfiles/Gemfile.basic +6 -0
  18. data/lib/simple_state_machine/.DS_Store +0 -0
  19. data/lib/simple_state_machine/active_record.rb +2 -64
  20. data/lib/simple_state_machine/decorator/active_record.rb +68 -0
  21. data/lib/simple_state_machine/decorator/default.rb +91 -0
  22. data/lib/simple_state_machine/railtie.rb +1 -1
  23. data/lib/simple_state_machine/simple_state_machine.rb +8 -251
  24. data/lib/simple_state_machine/state_machine.rb +88 -0
  25. data/lib/simple_state_machine/state_machine_definition.rb +72 -0
  26. data/lib/simple_state_machine/tools/graphviz.rb +21 -0
  27. data/lib/simple_state_machine/tools/inspector.rb +44 -0
  28. data/lib/simple_state_machine/transition.rb +40 -0
  29. data/lib/simple_state_machine/version.rb +1 -1
  30. data/lib/simple_state_machine.rb +13 -3
  31. data/lib/tasks/graphviz.rake +31 -0
  32. data/simple_state_machine.gemspec +14 -24
  33. data/spec/.DS_Store +0 -0
  34. data/spec/active_record_spec.rb +216 -179
  35. data/spec/{decorator_spec.rb → decorator/default_spec.rb} +32 -32
  36. data/spec/examples_spec.rb +17 -17
  37. data/spec/mountable_spec.rb +26 -14
  38. data/spec/simple_state_machine_spec.rb +128 -92
  39. data/spec/spec_helper.rb +18 -5
  40. data/spec/state_machine_definition_spec.rb +48 -34
  41. data/spec/state_machine_spec.rb +36 -2
  42. data/spec/tools/graphviz_spec.rb +30 -0
  43. data/spec/tools/inspector_spec.rb +70 -0
  44. metadata +54 -128
  45. data/autotest/discover.rb +0 -1
  46. data/lib/tasks/graphiz.rake +0 -13
  47. data/rails/graphiz.rake +0 -16
@@ -4,73 +4,11 @@ module SimpleStateMachine::ActiveRecord
4
4
  include SimpleStateMachine::Extendable
5
5
  include SimpleStateMachine::Inheritable
6
6
 
7
- class Decorator < SimpleStateMachine::Decorator
8
-
9
- # decorates subject with:
10
- # * {event_name}_and_save
11
- # * {event_name}_and_save!
12
- # * {event_name}!
13
- def decorate transition
14
- super transition
15
- event_name = transition.event_name.to_s
16
- event_name_and_save = "#{event_name}_and_save"
17
- unless @subject.method_defined?(event_name_and_save)
18
- @subject.send(:define_method, event_name_and_save) do |*args|
19
- old_state = self.send(self.class.state_machine_definition.state_method)
20
- send "with_managed_state_#{event_name}", *args
21
- if !self.errors.entries.empty?
22
- self.send("#{self.class.state_machine_definition.state_method}=", old_state)
23
- return false
24
- else
25
- if save
26
- return true
27
- else
28
- self.send("#{self.class.state_machine_definition.state_method}=", old_state)
29
- return false
30
- end
31
- end
32
- end
33
- end
34
- event_name_and_save_bang = "#{event_name_and_save}!"
35
- unless @subject.method_defined?(event_name_and_save_bang)
36
- @subject.send(:define_method, event_name_and_save_bang) do |*args|
37
- old_state = self.send(self.class.state_machine_definition.state_method)
38
- send "with_managed_state_#{event_name}", *args
39
- if !self.errors.entries.empty?
40
- self.send("#{self.class.state_machine_definition.state_method}=", old_state)
41
- raise ActiveRecord::RecordInvalid.new(self)
42
- end
43
- begin
44
- save!
45
- rescue ActiveRecord::RecordInvalid
46
- self.send("#{self.class.state_machine_definition.state_method}=", old_state)
47
- raise #re raise
48
- end
49
- end
50
- @subject.send :alias_method, "#{transition.event_name}!", event_name_and_save_bang
51
- end
52
- end
53
-
54
- protected
55
-
56
- def alias_event_methods event_name
57
- @subject.send(:define_method, "cannot_call_#{event_name}") do |*args|
58
- raise "You cannot call #{event_name}. Use #{event_name}! instead"
59
- end
60
- @subject.send :alias_method, "without_managed_state_#{event_name}", event_name
61
- @subject.send :alias_method, event_name, "cannot_call_#{event_name}"
62
- end
63
-
64
- def define_state_setter_method; end
65
-
66
- def define_state_getter_method; end
67
-
68
- end
69
-
70
7
  def state_machine_definition
71
8
  unless @state_machine_definition
72
9
  @state_machine_definition = SimpleStateMachine::StateMachineDefinition.new
73
- @state_machine_definition.lazy_decorator = lambda { Decorator.new(self) }
10
+ @state_machine_definition.decorator_class = SimpleStateMachine::Decorator::ActiveRecord
11
+ @state_machine_definition.subject = self
74
12
  end
75
13
  @state_machine_definition
76
14
  end
@@ -0,0 +1,68 @@
1
+ module SimpleStateMachine
2
+ module Decorator
3
+ class ActiveRecord < SimpleStateMachine::Decorator::Default
4
+
5
+ # decorates subject with:
6
+ # * {event_name}_and_save
7
+ # * {event_name}_and_save!
8
+ # * {event_name}!
9
+ # * {event_name}
10
+ def decorate transition
11
+ super transition
12
+ event_name = transition.event_name.to_s
13
+ decorate_save event_name
14
+ decorate_save! event_name
15
+ end
16
+
17
+ protected
18
+
19
+ def decorate_save event_name
20
+ event_name_and_save = "#{event_name}_and_save"
21
+ unless @subject.method_defined?(event_name_and_save)
22
+ @subject.send(:define_method, event_name_and_save) do |*args|
23
+ old_state = self.send(self.class.state_machine_definition.state_method)
24
+ send "#{event_name}_with_managed_state", *args
25
+ if self.errors.entries.empty? && save
26
+ true
27
+ else
28
+ self.send("#{self.class.state_machine_definition.state_method}=", old_state)
29
+ false
30
+ end
31
+ end
32
+ @subject.send :alias_method, "#{event_name}", event_name_and_save
33
+ end
34
+ end
35
+
36
+ def decorate_save! event_name
37
+ event_name_and_save_bang = "#{event_name}_and_save!"
38
+ unless @subject.method_defined?(event_name_and_save_bang)
39
+ @subject.send(:define_method, event_name_and_save_bang) do |*args|
40
+ old_state = self.send(self.class.state_machine_definition.state_method)
41
+ send "#{event_name}_with_managed_state", *args
42
+ if self.errors.entries.empty?
43
+ begin
44
+ save!
45
+ rescue ::ActiveRecord::RecordInvalid
46
+ self.send("#{self.class.state_machine_definition.state_method}=", old_state)
47
+ raise #re raise
48
+ end
49
+ else
50
+ self.send("#{self.class.state_machine_definition.state_method}=", old_state)
51
+ raise ::ActiveRecord::RecordInvalid.new(self)
52
+ end
53
+ end
54
+ @subject.send :alias_method, "#{event_name}!", event_name_and_save_bang
55
+ end
56
+ end
57
+
58
+ def alias_event_methods event_name
59
+ @subject.send :alias_method, "#{event_name}_without_managed_state", event_name
60
+ end
61
+
62
+ def define_state_setter_method; end
63
+
64
+ def define_state_getter_method; end
65
+
66
+ end
67
+ end
68
+ end
@@ -0,0 +1,91 @@
1
+ module SimpleStateMachine
2
+ module Decorator
3
+ ##
4
+ # Decorates @subject with methods to access the state machine
5
+ class Default
6
+
7
+ attr_writer :subject
8
+ def initialize(subject)
9
+ @subject = subject
10
+ end
11
+
12
+ def decorate transition
13
+ define_state_machine_method
14
+ define_state_getter_method
15
+ define_state_setter_method
16
+
17
+ define_state_helper_method(transition.from)
18
+ define_state_helper_method(transition.to)
19
+ define_event_method(transition.event_name)
20
+ decorate_event_method(transition.event_name)
21
+ end
22
+
23
+ private
24
+
25
+ def define_state_machine_method
26
+ unless any_method_defined?("state_machine")
27
+ @subject.send(:define_method, "state_machine") do
28
+ @state_machine ||= StateMachine.new(self)
29
+ end
30
+ end
31
+ end
32
+
33
+ def define_state_helper_method state
34
+ unless any_method_defined?("#{state.to_s}?")
35
+ @subject.send(:define_method, "#{state.to_s}?") do
36
+ self.send(self.class.state_machine_definition.state_method) == state.to_s
37
+ end
38
+ end
39
+ end
40
+
41
+ def define_event_method event_name
42
+ unless any_method_defined?("#{event_name}")
43
+ @subject.send(:define_method, "#{event_name}") {}
44
+ end
45
+ end
46
+
47
+ def decorate_event_method event_name
48
+ # TODO put in transaction for activeRecord?
49
+ unless @subject.method_defined?("#{event_name}_with_managed_state")
50
+ @subject.send(:define_method, "#{event_name}_with_managed_state") do |*args|
51
+ return state_machine.transition(event_name) do
52
+ send("#{event_name}_without_managed_state", *args)
53
+ end
54
+ end
55
+ alias_event_methods event_name
56
+ end
57
+ end
58
+
59
+ def define_state_setter_method
60
+ unless any_method_defined?("#{state_method}=")
61
+ @subject.send(:define_method, "#{state_method}=") do |new_state|
62
+ instance_variable_set(:"@#{self.class.state_machine_definition.state_method}", new_state)
63
+ end
64
+ end
65
+ end
66
+
67
+ def define_state_getter_method
68
+ unless any_method_defined?(state_method)
69
+ @subject.send(:attr_reader, state_method)
70
+ end
71
+ end
72
+
73
+ def any_method_defined?(method)
74
+ @subject.method_defined?(method) ||
75
+ @subject.protected_method_defined?(method) ||
76
+ @subject.private_method_defined?(method)
77
+ end
78
+
79
+ protected
80
+
81
+ def alias_event_methods event_name
82
+ @subject.send :alias_method, "#{event_name}_without_managed_state", event_name
83
+ @subject.send :alias_method, event_name, "#{event_name}_with_managed_state"
84
+ end
85
+
86
+ def state_method
87
+ @subject.state_machine_definition.state_method
88
+ end
89
+ end
90
+ end
91
+ end
@@ -4,7 +4,7 @@ require 'rails'
4
4
  module SimpleStateMachine
5
5
  class Railtie < Rails::Railtie
6
6
  rake_tasks do
7
- load "tasks/graphiz.rake"
7
+ load "tasks/graphviz.rake"
8
8
  end
9
9
  end
10
10
  end
@@ -1,17 +1,12 @@
1
1
  module SimpleStateMachine
2
2
 
3
- require 'cgi'
4
-
5
- class IllegalStateTransitionError < ::RuntimeError
6
- end
7
-
8
3
  ##
9
4
  # Allows class to mount a state_machine
10
5
  module Mountable
11
6
  def state_machine_definition
12
7
  unless @state_machine_definition
13
8
  @state_machine_definition = StateMachineDefinition.new
14
- @state_machine_definition.lazy_decorator = lambda { Decorator.new(self) }
9
+ @state_machine_definition.subject = self
15
10
  end
16
11
  @state_machine_definition
17
12
  end
@@ -22,22 +17,22 @@ module SimpleStateMachine
22
17
  state_machine_definition.decorator.decorate(transition)
23
18
  end
24
19
  end
20
+
21
+ def mount_state_machine mountable_class
22
+ self.state_machine_definition = mountable_class.new
23
+ self.state_machine_definition.subject = self
24
+ self.state_machine_definition.add_events
25
+ end
25
26
  end
26
27
  include Mountable
27
28
 
28
29
  ##
29
30
  # Adds state machine methods to the extended class
30
31
  module Extendable
31
-
32
32
  # mark the method as an event and specify how the state should transition
33
33
  def event event_name, state_transitions
34
- state_transitions.each do |froms, to|
35
- [froms].flatten.each do |from|
36
- state_machine_definition.add_transition(event_name, from, to)
37
- end
38
- end
34
+ state_machine_definition.define_event event_name, state_transitions
39
35
  end
40
-
41
36
  end
42
37
  include Extendable
43
38
 
@@ -54,242 +49,4 @@ module SimpleStateMachine
54
49
  end
55
50
  include Inheritable
56
51
 
57
- ##
58
- # Defines state machine transitions
59
- class StateMachineDefinition
60
-
61
- attr_writer :state_method, :decorator, :lazy_decorator
62
-
63
- def decorator
64
- @decorator ||= @lazy_decorator.call
65
- end
66
-
67
- def transitions
68
- @transitions ||= []
69
- end
70
-
71
- def add_transition event_name, from, to
72
- transition = Transition.new(event_name, from, to)
73
- transitions << transition
74
- decorator.decorate(transition)
75
- end
76
-
77
- def state_method
78
- @state_method ||= :state
79
- end
80
-
81
- # Human readable format: old_state.event! => new_state
82
- def to_s
83
- transitions.map(&:to_s).join("\n")
84
- end
85
-
86
- # Graphiz dot format for rendering as a directional graph
87
- def to_graphiz_dot
88
- transitions.map { |t| t.to_graphiz_dot }.join(";")
89
- end
90
-
91
- # Generates a url that renders states and events as a directional graph.
92
- # See http://code.google.com/apis/chart/docs/gallery/graphviz.html
93
- def google_chart_url
94
- "http://chart.googleapis.com/chart?cht=gv&chl=digraph{#{::CGI.escape to_graphiz_dot}}"
95
- end
96
- end
97
-
98
- ##
99
- # Defines the state machine used by the instance
100
- class StateMachine
101
-
102
- def initialize(subject)
103
- @subject = subject
104
- end
105
-
106
- # Returns the next state for the subject for event_name
107
- def next_state(event_name)
108
- transition = transitions.select{|t| t.is_transition_for?(event_name, @subject.send(state_method))}.first
109
- transition ? transition.to : nil
110
- end
111
-
112
- # Returns the error state for the subject for event_name and error
113
- def error_state(event_name, error)
114
- transition = transitions.select{|t| t.is_error_transition_for?(event_name, error) }.first
115
- transition ? transition.to : nil
116
- end
117
-
118
- # Transitions to the next state if next_state exists.
119
- # Calls illegal_event_callback event_name if no next_state is found
120
- def transition(event_name)
121
- if to = next_state(event_name)
122
- begin
123
- result = yield
124
- rescue => e
125
- if error_state = error_state(event_name, e)
126
- @subject.send("#{state_method}=", error_state)
127
- return result
128
- else
129
- raise
130
- end
131
- end
132
- # TODO refactor out to AR module
133
- if defined?(::ActiveRecord) && @subject.is_a?(::ActiveRecord::Base)
134
- if @subject.errors.entries.empty?
135
- @subject.send("#{state_method}=", to)
136
- return true
137
- else
138
- return false
139
- end
140
- else
141
- @subject.send("#{state_method}=", to)
142
- return result
143
- end
144
- else
145
- illegal_event_callback event_name
146
- end
147
- end
148
-
149
- private
150
-
151
- def state_machine_definition
152
- @subject.class.state_machine_definition
153
- end
154
-
155
- def transitions
156
- state_machine_definition.transitions
157
- end
158
-
159
- def state_method
160
- state_machine_definition.state_method
161
- end
162
-
163
- # override with your own implementation, like setting errors in your model
164
- def illegal_event_callback event_name
165
- raise IllegalStateTransitionError.new("You cannot '#{event_name}' when state is '#{@subject.send(state_method)}'")
166
- end
167
-
168
- end
169
-
170
- ##
171
- # Defines transitions for events
172
- class Transition
173
- attr_reader :event_name, :from, :to
174
- def initialize(event_name, from, to)
175
- @event_name = event_name.to_s
176
- @from = from.is_a?(Class) ? from : from.to_s
177
- @to = to.to_s
178
- end
179
-
180
- # returns true if it's a transition for event_name
181
- def is_transition_for?(event_name, subject_state)
182
- is_same_event?(event_name) && is_same_from?(subject_state)
183
- end
184
-
185
- # returns true if it's a error transition for event_name and error
186
- def is_error_transition_for?(event_name, error)
187
- is_same_event?(event_name) && error.class == from
188
- end
189
-
190
- def to_s
191
- "#{from}.#{event_name}! => #{to}"
192
- end
193
-
194
- def to_graphiz_dot
195
- %("#{from}"->"#{to}"[label=#{event_name}])
196
- end
197
-
198
-
199
- private
200
-
201
- def is_same_event?(event_name)
202
- self.event_name == event_name.to_s
203
- end
204
-
205
- def is_same_from?(subject_from)
206
- from.to_s == 'all' || subject_from.to_s == from.to_s
207
- end
208
- end
209
-
210
- ##
211
- # Decorates @subject with methods to access the state machine
212
- class Decorator
213
-
214
- attr_writer :subject
215
- def initialize(subject)
216
- @subject = subject
217
- define_state_machine_method
218
- define_state_getter_method
219
- define_state_setter_method
220
- end
221
-
222
- def decorate transition
223
- define_state_helper_method(transition.from)
224
- define_state_helper_method(transition.to)
225
- define_event_method(transition.event_name)
226
- decorate_event_method(transition.event_name)
227
- end
228
-
229
- private
230
-
231
- def define_state_machine_method
232
- @subject.send(:define_method, "state_machine") do
233
- @state_machine ||= StateMachine.new(self)
234
- end
235
- end
236
-
237
- def define_state_helper_method state
238
- unless any_method_defined?("#{state.to_s}?")
239
- @subject.send(:define_method, "#{state.to_s}?") do
240
- self.send(self.class.state_machine_definition.state_method) == state.to_s
241
- end
242
- end
243
- end
244
-
245
- def define_event_method event_name
246
- unless any_method_defined?("#{event_name}")
247
- @subject.send(:define_method, "#{event_name}") {}
248
- end
249
- end
250
-
251
- def decorate_event_method event_name
252
- # TODO put in transaction for activeRecord?
253
- unless @subject.method_defined?("with_managed_state_#{event_name}")
254
- @subject.send(:define_method, "with_managed_state_#{event_name}") do |*args|
255
- return state_machine.transition(event_name) do
256
- send("without_managed_state_#{event_name}", *args)
257
- end
258
- end
259
- alias_event_methods event_name
260
- end
261
- end
262
-
263
- def define_state_setter_method
264
- unless any_method_defined?("#{state_method}=")
265
- @subject.send(:define_method, "#{state_method}=") do |new_state|
266
- instance_variable_set(:"@#{self.class.state_machine_definition.state_method}", new_state)
267
- end
268
- end
269
- end
270
-
271
- def define_state_getter_method
272
- unless any_method_defined?(state_method)
273
- @subject.send(:attr_reader, state_method)
274
- end
275
- end
276
-
277
- def any_method_defined?(method)
278
- @subject.method_defined?(method) ||
279
- @subject.protected_method_defined?(method) ||
280
- @subject.private_method_defined?(method)
281
- end
282
-
283
- protected
284
-
285
- def alias_event_methods event_name
286
- @subject.send :alias_method, "without_managed_state_#{event_name}", event_name
287
- @subject.send :alias_method, event_name, "with_managed_state_#{event_name}"
288
- end
289
-
290
- def state_method
291
- @subject.state_machine_definition.state_method
292
- end
293
- end
294
-
295
52
  end
@@ -0,0 +1,88 @@
1
+ module SimpleStateMachine
2
+
3
+ class IllegalStateTransitionError < ::RuntimeError; end
4
+
5
+ ##
6
+ # Defines the state machine used by the instance
7
+ class StateMachine
8
+ attr_reader :raised_error
9
+
10
+ def initialize(subject)
11
+ @subject = subject
12
+ end
13
+
14
+ # Returns the next state for the subject for event_name
15
+ def next_state(event_name)
16
+ transition = transitions.select{|t| t.is_transition_for?(event_name, @subject.send(state_method))}.first
17
+ transition ? transition.to : nil
18
+ end
19
+
20
+ # Returns the error state for the subject for event_name and error
21
+ def error_state(event_name, error)
22
+ transition = transitions.select{|t| t.is_error_transition_for?(event_name, error) }.first
23
+ transition ? transition.to : nil
24
+ end
25
+
26
+ # Transitions to the next state if next_state exists.
27
+ # When an error occurs, it uses the error to determine next state.
28
+ # If no next state can be determined it transitions to the default error
29
+ # state if defined, otherwise the error is re-raised.
30
+ # Calls illegal_event_callback event_name if no next_state is found
31
+ def transition(event_name)
32
+ clear_raised_error
33
+ if to = next_state(event_name)
34
+ begin
35
+ result = yield
36
+ rescue => e
37
+ error_state = error_state(event_name, e) ||
38
+ state_machine_definition.default_error_state
39
+ if error_state
40
+ @raised_error = e
41
+ @subject.send("#{state_method}=", error_state)
42
+ return result
43
+ else
44
+ raise
45
+ end
46
+ end
47
+ # TODO refactor out to AR module
48
+ if defined?(::ActiveRecord) && @subject.is_a?(::ActiveRecord::Base)
49
+ if @subject.errors.entries.empty?
50
+ @subject.send("#{state_method}=", to)
51
+ return true
52
+ else
53
+ return false
54
+ end
55
+ else
56
+ @subject.send("#{state_method}=", to)
57
+ return result
58
+ end
59
+ else
60
+ illegal_event_callback event_name
61
+ end
62
+ end
63
+
64
+ private
65
+
66
+ def clear_raised_error
67
+ @raised_error = nil
68
+ end
69
+
70
+ def state_machine_definition
71
+ @subject.class.state_machine_definition
72
+ end
73
+
74
+ def transitions
75
+ state_machine_definition.transitions
76
+ end
77
+
78
+ def state_method
79
+ state_machine_definition.state_method
80
+ end
81
+
82
+ # override with your own implementation, like setting errors in your model
83
+ def illegal_event_callback event_name
84
+ raise IllegalStateTransitionError.new("You cannot '#{event_name}' when state is '#{@subject.send(state_method)}'")
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,72 @@
1
+ module SimpleStateMachine
2
+ ##
3
+ # Defines state machine transitions
4
+ class StateMachineDefinition
5
+
6
+ attr_writer :default_error_state, :state_method, :subject, :decorator,
7
+ :decorator_class
8
+
9
+ def decorator
10
+ @decorator ||= decorator_class.new(@subject)
11
+ end
12
+
13
+ def decorator_class
14
+ @decorator_class ||= Decorator::Default
15
+ end
16
+
17
+ def default_error_state
18
+ @default_error_state && @default_error_state.to_s
19
+ end
20
+
21
+ def transitions
22
+ @transitions ||= []
23
+ end
24
+
25
+ def define_event event_name, state_transitions
26
+ state_transitions.each do |froms, to|
27
+ [froms].flatten.each do |from|
28
+ add_transition(event_name, from, to)
29
+ end
30
+ end
31
+ end
32
+
33
+ def add_transition event_name, from, to
34
+ transition = Transition.new(event_name, from, to)
35
+ transitions << transition
36
+ decorator.decorate(transition)
37
+ end
38
+
39
+ def state_method
40
+ @state_method ||= :state
41
+ end
42
+
43
+ # Human readable format: old_state.event! => new_state
44
+ def to_s
45
+ transitions.map(&:to_s).join("\n")
46
+ end
47
+
48
+ module Mountable
49
+ def event event_name, state_transitions
50
+ events << [event_name, state_transitions]
51
+ end
52
+
53
+ def events
54
+ @events ||= []
55
+ end
56
+
57
+ module InstanceMethods
58
+ def add_events
59
+ self.class.events.each do |event_name, state_transitions|
60
+ define_event event_name, state_transitions
61
+ end
62
+ end
63
+ end
64
+ end
65
+ extend Mountable
66
+ include Mountable::InstanceMethods
67
+
68
+ # TODO only include in rake task?
69
+ include ::SimpleStateMachine::Tools::Graphviz
70
+ include ::SimpleStateMachine::Tools::Inspector
71
+ end
72
+ end