verborghs-state_machine 0.9.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (89) hide show
  1. data/CHANGELOG.rdoc +360 -0
  2. data/LICENSE +20 -0
  3. data/README.rdoc +635 -0
  4. data/Rakefile +77 -0
  5. data/examples/AutoShop_state.png +0 -0
  6. data/examples/Car_state.png +0 -0
  7. data/examples/TrafficLight_state.png +0 -0
  8. data/examples/Vehicle_state.png +0 -0
  9. data/examples/auto_shop.rb +11 -0
  10. data/examples/car.rb +19 -0
  11. data/examples/merb-rest/controller.rb +51 -0
  12. data/examples/merb-rest/model.rb +28 -0
  13. data/examples/merb-rest/view_edit.html.erb +24 -0
  14. data/examples/merb-rest/view_index.html.erb +23 -0
  15. data/examples/merb-rest/view_new.html.erb +13 -0
  16. data/examples/merb-rest/view_show.html.erb +17 -0
  17. data/examples/rails-rest/controller.rb +43 -0
  18. data/examples/rails-rest/migration.rb +11 -0
  19. data/examples/rails-rest/model.rb +23 -0
  20. data/examples/rails-rest/view_edit.html.erb +25 -0
  21. data/examples/rails-rest/view_index.html.erb +23 -0
  22. data/examples/rails-rest/view_new.html.erb +14 -0
  23. data/examples/rails-rest/view_show.html.erb +17 -0
  24. data/examples/traffic_light.rb +7 -0
  25. data/examples/vehicle.rb +31 -0
  26. data/init.rb +1 -0
  27. data/lib/state_machine/assertions.rb +36 -0
  28. data/lib/state_machine/callback.rb +241 -0
  29. data/lib/state_machine/condition_proxy.rb +106 -0
  30. data/lib/state_machine/eval_helpers.rb +83 -0
  31. data/lib/state_machine/event.rb +267 -0
  32. data/lib/state_machine/event_collection.rb +122 -0
  33. data/lib/state_machine/extensions.rb +149 -0
  34. data/lib/state_machine/guard.rb +230 -0
  35. data/lib/state_machine/initializers/merb.rb +1 -0
  36. data/lib/state_machine/initializers/rails.rb +5 -0
  37. data/lib/state_machine/initializers.rb +4 -0
  38. data/lib/state_machine/integrations/active_model/locale.rb +11 -0
  39. data/lib/state_machine/integrations/active_model/observer.rb +45 -0
  40. data/lib/state_machine/integrations/active_model.rb +445 -0
  41. data/lib/state_machine/integrations/active_record/locale.rb +20 -0
  42. data/lib/state_machine/integrations/active_record.rb +522 -0
  43. data/lib/state_machine/integrations/data_mapper/observer.rb +175 -0
  44. data/lib/state_machine/integrations/data_mapper.rb +379 -0
  45. data/lib/state_machine/integrations/mongo_mapper.rb +309 -0
  46. data/lib/state_machine/integrations/sequel.rb +356 -0
  47. data/lib/state_machine/integrations.rb +83 -0
  48. data/lib/state_machine/machine.rb +1645 -0
  49. data/lib/state_machine/machine_collection.rb +64 -0
  50. data/lib/state_machine/matcher.rb +123 -0
  51. data/lib/state_machine/matcher_helpers.rb +54 -0
  52. data/lib/state_machine/node_collection.rb +152 -0
  53. data/lib/state_machine/state.rb +260 -0
  54. data/lib/state_machine/state_collection.rb +112 -0
  55. data/lib/state_machine/transition.rb +399 -0
  56. data/lib/state_machine/transition_collection.rb +244 -0
  57. data/lib/state_machine.rb +421 -0
  58. data/lib/tasks/state_machine.rake +1 -0
  59. data/lib/tasks/state_machine.rb +27 -0
  60. data/test/files/en.yml +9 -0
  61. data/test/files/switch.rb +11 -0
  62. data/test/functional/state_machine_test.rb +980 -0
  63. data/test/test_helper.rb +4 -0
  64. data/test/unit/assertions_test.rb +40 -0
  65. data/test/unit/callback_test.rb +728 -0
  66. data/test/unit/condition_proxy_test.rb +328 -0
  67. data/test/unit/eval_helpers_test.rb +222 -0
  68. data/test/unit/event_collection_test.rb +324 -0
  69. data/test/unit/event_test.rb +795 -0
  70. data/test/unit/guard_test.rb +909 -0
  71. data/test/unit/integrations/active_model_test.rb +956 -0
  72. data/test/unit/integrations/active_record_test.rb +1918 -0
  73. data/test/unit/integrations/data_mapper_test.rb +1814 -0
  74. data/test/unit/integrations/mongo_mapper_test.rb +1382 -0
  75. data/test/unit/integrations/sequel_test.rb +1492 -0
  76. data/test/unit/integrations_test.rb +50 -0
  77. data/test/unit/invalid_event_test.rb +7 -0
  78. data/test/unit/invalid_transition_test.rb +7 -0
  79. data/test/unit/machine_collection_test.rb +565 -0
  80. data/test/unit/machine_test.rb +2349 -0
  81. data/test/unit/matcher_helpers_test.rb +37 -0
  82. data/test/unit/matcher_test.rb +155 -0
  83. data/test/unit/node_collection_test.rb +207 -0
  84. data/test/unit/state_collection_test.rb +280 -0
  85. data/test/unit/state_machine_test.rb +31 -0
  86. data/test/unit/state_test.rb +848 -0
  87. data/test/unit/transition_collection_test.rb +2098 -0
  88. data/test/unit/transition_test.rb +1384 -0
  89. metadata +176 -0
@@ -0,0 +1,324 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class EventCollectionByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @machine = StateMachine::Machine.new(Class.new)
6
+ @events = StateMachine::EventCollection.new(@machine)
7
+ end
8
+
9
+ def test_should_not_have_any_nodes
10
+ assert_equal 0, @events.length
11
+ end
12
+
13
+ def test_should_have_a_machine
14
+ assert_equal @machine, @events.machine
15
+ end
16
+
17
+ def test_should_not_have_any_valid_events_for_an_object
18
+ assert @events.valid_for(@object).empty?
19
+ end
20
+
21
+ def test_should_not_have_any_transitions_for_an_object
22
+ assert @events.transitions_for(@object).empty?
23
+ end
24
+ end
25
+
26
+ class EventCollectionTest < Test::Unit::TestCase
27
+ def setup
28
+ machine = StateMachine::Machine.new(Class.new, :namespace => 'alarm')
29
+ @events = StateMachine::EventCollection.new(machine)
30
+
31
+ @events << @open = StateMachine::Event.new(machine, :enable)
32
+ end
33
+
34
+ def test_should_index_by_name
35
+ assert_equal @open, @events[:enable, :name]
36
+ end
37
+
38
+ def test_should_index_by_name_by_default
39
+ assert_equal @open, @events[:enable]
40
+ end
41
+
42
+ def test_should_index_by_qualified_name
43
+ assert_equal @open, @events[:enable_alarm, :qualified_name]
44
+ end
45
+ end
46
+
47
+ class EventCollectionWithEventsWithTransitionsTest < Test::Unit::TestCase
48
+ def setup
49
+ @klass = Class.new
50
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
51
+ @events = StateMachine::EventCollection.new(@machine)
52
+
53
+ @machine.state :idling, :stalled
54
+ @machine.event :ignite
55
+
56
+ @events << @ignite = StateMachine::Event.new(@machine, :ignite)
57
+ @ignite.transition :parked => :idling
58
+ @ignite.transition :stalled => :idling
59
+ end
60
+
61
+ def test_should_only_include_valid_events_for_an_object
62
+ object = @klass.new
63
+ object.state = 'parked'
64
+ assert_equal [@ignite], @events.valid_for(object)
65
+
66
+ object.state = 'stalled'
67
+ assert_equal [@ignite], @events.valid_for(object)
68
+
69
+ object.state = 'idling'
70
+ assert_equal [], @events.valid_for(object)
71
+ end
72
+
73
+ def test_should_only_include_valid_transitions_for_an_object
74
+ object = @klass.new
75
+ object.state = 'parked'
76
+ assert_equal [{:object => object, :attribute => :state, :event => :ignite, :from => 'parked', :to => 'idling'}], @events.transitions_for(object).map {|transition| transition.attributes}
77
+
78
+ object.state = 'stalled'
79
+ assert_equal [{:object => object, :attribute => :state, :event => :ignite, :from => 'stalled', :to => 'idling'}], @events.transitions_for(object).map {|transition| transition.attributes}
80
+
81
+ object.state = 'idling'
82
+ assert_equal [], @events.transitions_for(object)
83
+ end
84
+
85
+ def test_should_filter_valid_transitions_for_an_object_if_requirements_specified
86
+ object = @klass.new
87
+ assert_equal [{:object => object, :attribute => :state, :event => :ignite, :from => 'stalled', :to => 'idling'}], @events.transitions_for(object, :from => :stalled).map {|transition| transition.attributes}
88
+ assert_equal [], @events.transitions_for(object, :from => :idling).map {|transition| transition.attributes}
89
+ end
90
+ end
91
+
92
+ class EventCollectionWithMultipleEventsTest < Test::Unit::TestCase
93
+ def setup
94
+ @klass = Class.new
95
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
96
+ @events = StateMachine::EventCollection.new(@machine)
97
+
98
+ @machine.state :first_gear
99
+ @machine.event :park, :shift_down
100
+
101
+ @events << @park = StateMachine::Event.new(@machine, :park)
102
+ @park.transition :first_gear => :parked
103
+
104
+ @events << @shift_down = StateMachine::Event.new(@machine, :shift_down)
105
+ @shift_down.transition :first_gear => :parked
106
+ end
107
+
108
+ def test_should_only_include_all_valid_events_for_an_object
109
+ object = @klass.new
110
+ object.state = 'first_gear'
111
+ assert_equal [@park, @shift_down], @events.valid_for(object)
112
+ end
113
+ end
114
+
115
+ class EventCollectionWithoutMachineActionTest < Test::Unit::TestCase
116
+ def setup
117
+ @klass = Class.new
118
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked)
119
+ @events = StateMachine::EventCollection.new(@machine)
120
+
121
+ @machine.event :ignite
122
+ @events << StateMachine::Event.new(@machine, :ignite)
123
+
124
+ @object = @klass.new
125
+ end
126
+
127
+ def test_should_not_have_an_attribute_transition
128
+ assert_nil @events.attribute_transition_for(@object)
129
+ end
130
+ end
131
+
132
+ class EventCollectionAttributeWithMachineActionTest < Test::Unit::TestCase
133
+ def setup
134
+ @klass = Class.new do
135
+ def save
136
+ end
137
+ end
138
+
139
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save)
140
+ @events = StateMachine::EventCollection.new(@machine)
141
+
142
+ @machine.event :ignite
143
+ @machine.state :parked, :idling
144
+ @events << @ignite = StateMachine::Event.new(@machine, :ignite)
145
+
146
+ @object = @klass.new
147
+ end
148
+
149
+ def test_should_not_have_transition_if_nil
150
+ @object.state_event = nil
151
+ assert_nil @events.attribute_transition_for(@object)
152
+ end
153
+
154
+ def test_should_not_have_transition_if_empty
155
+ @object.state_event = ''
156
+ assert_nil @events.attribute_transition_for(@object)
157
+ end
158
+
159
+ def test_should_have_invalid_transition_if_invalid_event_specified
160
+ @object.state_event = 'invalid'
161
+ assert_equal false, @events.attribute_transition_for(@object)
162
+ end
163
+
164
+ def test_should_have_invalid_transition_if_event_cannot_be_fired
165
+ @object.state_event = 'ignite'
166
+ assert_equal false, @events.attribute_transition_for(@object)
167
+ end
168
+
169
+ def test_should_have_valid_transition_if_event_can_be_fired
170
+ @ignite.transition :parked => :idling
171
+ @object.state_event = 'ignite'
172
+
173
+ assert_instance_of StateMachine::Transition, @events.attribute_transition_for(@object)
174
+ end
175
+
176
+ def test_should_have_valid_transition_if_already_defined_in_transition_cache
177
+ @ignite.transition :parked => :idling
178
+ @object.state_event = nil
179
+ @object.send(:state_event_transition=, transition = @ignite.transition_for(@object))
180
+
181
+ assert_equal transition, @events.attribute_transition_for(@object)
182
+ end
183
+
184
+ def test_should_use_transition_cache_if_both_event_and_transition_are_present
185
+ @ignite.transition :parked => :idling
186
+ @object.state_event = 'ignite'
187
+ @object.send(:state_event_transition=, transition = @ignite.transition_for(@object))
188
+
189
+ assert_equal transition, @events.attribute_transition_for(@object)
190
+ end
191
+ end
192
+
193
+ class EventCollectionAttributeWithNamespacedMachineTest < Test::Unit::TestCase
194
+ def setup
195
+ @klass = Class.new do
196
+ def save
197
+ end
198
+ end
199
+
200
+ @machine = StateMachine::Machine.new(@klass, :namespace => 'alarm', :initial => :active, :action => :save)
201
+ @events = StateMachine::EventCollection.new(@machine)
202
+
203
+ @machine.event :disable
204
+ @machine.state :active, :off
205
+ @events << @disable = StateMachine::Event.new(@machine, :disable)
206
+
207
+ @object = @klass.new
208
+ end
209
+
210
+ def test_should_not_have_transition_if_nil
211
+ @object.state_event = nil
212
+ assert_nil @events.attribute_transition_for(@object)
213
+ end
214
+
215
+ def test_should_have_invalid_transition_if_event_cannot_be_fired
216
+ @object.state_event = 'disable'
217
+ assert_equal false, @events.attribute_transition_for(@object)
218
+ end
219
+
220
+ def test_should_have_valid_transition_if_event_can_be_fired
221
+ @disable.transition :active => :off
222
+ @object.state_event = 'disable'
223
+
224
+ assert_instance_of StateMachine::Transition, @events.attribute_transition_for(@object)
225
+ end
226
+ end
227
+
228
+ class EventCollectionWithValidationsTest < Test::Unit::TestCase
229
+ def setup
230
+ StateMachine::Integrations.const_set('Custom', Module.new do
231
+ def invalidate(object, attribute, message, values = [])
232
+ (object.errors ||= []) << generate_message(message, values)
233
+ end
234
+
235
+ def reset(object)
236
+ object.errors = []
237
+ end
238
+ end)
239
+
240
+ @klass = Class.new do
241
+ attr_accessor :errors
242
+
243
+ def initialize
244
+ @errors = []
245
+ super
246
+ end
247
+ end
248
+
249
+ @machine = StateMachine::Machine.new(@klass, :initial => :parked, :action => :save, :integration => :custom)
250
+ @events = StateMachine::EventCollection.new(@machine)
251
+
252
+ @machine.event :ignite
253
+ @parked, @idling = @machine.state :parked, :idling
254
+ @events << @ignite = StateMachine::Event.new(@machine, :ignite)
255
+
256
+ @object = @klass.new
257
+ end
258
+
259
+ def test_should_invalidate_if_invalid_event_specified
260
+ @object.state_event = 'invalid'
261
+ @events.attribute_transition_for(@object, true)
262
+
263
+ assert_equal ['is invalid'], @object.errors
264
+ end
265
+
266
+ def test_should_invalidate_if_event_cannot_be_fired
267
+ @object.state = 'idling'
268
+ @object.state_event = 'ignite'
269
+ @events.attribute_transition_for(@object, true)
270
+
271
+ assert_equal ['cannot transition when idling'], @object.errors
272
+ end
273
+
274
+ def test_should_invalidate_with_human_name_if_invalid_event_specified
275
+ @idling.human_name = 'waiting'
276
+ @object.state = 'idling'
277
+ @object.state_event = 'ignite'
278
+ @events.attribute_transition_for(@object, true)
279
+
280
+ assert_equal ['cannot transition when waiting'], @object.errors
281
+ end
282
+
283
+ def test_should_not_invalidate_event_can_be_fired
284
+ @ignite.transition :parked => :idling
285
+ @object.state_event = 'ignite'
286
+ @events.attribute_transition_for(@object, true)
287
+
288
+ assert_equal [], @object.errors
289
+ end
290
+
291
+ def teardown
292
+ StateMachine::Integrations.send(:remove_const, 'Custom')
293
+ end
294
+ end
295
+
296
+ class EventCollectionWithCustomMachineAttributeTest < Test::Unit::TestCase
297
+ def setup
298
+ @klass = Class.new do
299
+ def save
300
+ end
301
+ end
302
+
303
+ @machine = StateMachine::Machine.new(@klass, :state, :attribute => :state_id, :initial => :parked, :action => :save)
304
+ @events = StateMachine::EventCollection.new(@machine)
305
+
306
+ @machine.event :ignite
307
+ @machine.state :parked, :idling
308
+ @events << @ignite = StateMachine::Event.new(@machine, :ignite)
309
+
310
+ @object = @klass.new
311
+ end
312
+
313
+ def test_should_not_have_transition_if_nil
314
+ @object.state_event = nil
315
+ assert_nil @events.attribute_transition_for(@object)
316
+ end
317
+
318
+ def test_should_have_valid_transition_if_event_can_be_fired
319
+ @ignite.transition :parked => :idling
320
+ @object.state_event = 'ignite'
321
+
322
+ assert_instance_of StateMachine::Transition, @events.attribute_transition_for(@object)
323
+ end
324
+ end