state_machine 0.1.0
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.
- data/CHANGELOG +101 -0
- data/MIT-LICENSE +20 -0
- data/README +97 -0
- data/Rakefile +79 -0
- data/init.rb +1 -0
- data/lib/state_machine.rb +92 -0
- data/lib/state_machine/event.rb +127 -0
- data/lib/state_machine/machine.rb +141 -0
- data/lib/state_machine/transition.rb +75 -0
- data/test/app_root/app/models/auto_shop.rb +34 -0
- data/test/app_root/app/models/car.rb +19 -0
- data/test/app_root/app/models/highway.rb +3 -0
- data/test/app_root/app/models/motorcycle.rb +3 -0
- data/test/app_root/app/models/switch.rb +12 -0
- data/test/app_root/app/models/toggle_switch.rb +2 -0
- data/test/app_root/app/models/vehicle.rb +71 -0
- data/test/app_root/db/migrate/001_create_switches.rb +12 -0
- data/test/app_root/db/migrate/002_create_auto_shops.rb +13 -0
- data/test/app_root/db/migrate/003_create_highways.rb +11 -0
- data/test/app_root/db/migrate/004_create_vehicles.rb +16 -0
- data/test/factory.rb +61 -0
- data/test/functional/state_machine_test.rb +443 -0
- data/test/test_helper.rb +13 -0
- data/test/unit/event_test.rb +234 -0
- data/test/unit/machine_test.rb +152 -0
- data/test/unit/state_machine_test.rb +102 -0
- data/test/unit/transition_test.rb +298 -0
- metadata +91 -0
@@ -0,0 +1,298 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
|
2
|
+
|
3
|
+
class TransitionTest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
6
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
7
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, 'off', 'on')
|
8
|
+
end
|
9
|
+
|
10
|
+
def test_should_have_a_from_state
|
11
|
+
assert_equal 'off', @transition.from_state
|
12
|
+
end
|
13
|
+
|
14
|
+
def test_should_have_a_to_state
|
15
|
+
assert_equal 'on', @transition.to_state
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_should_not_be_a_loopback
|
19
|
+
assert !@transition.loopback?
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_should_not_be_able_to_perform_if_record_state_is_not_from_state
|
23
|
+
record = new_switch(:state => 'on')
|
24
|
+
assert !@transition.can_perform_on?(record)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_should_be_able_to_perform_if_record_state_is_from_state
|
28
|
+
record = new_switch(:state => 'off')
|
29
|
+
assert @transition.can_perform_on?(record)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
class TransitionWithoutFromStateTest < Test::Unit::TestCase
|
34
|
+
def setup
|
35
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
36
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
37
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, nil, 'on')
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_should_not_have_a_from_state
|
41
|
+
assert_nil @transition.from_state
|
42
|
+
end
|
43
|
+
|
44
|
+
def test_should_be_able_to_perform_on_all_states
|
45
|
+
record = new_switch(:state => 'off')
|
46
|
+
assert @transition.can_perform_on?(record)
|
47
|
+
|
48
|
+
record = new_switch(:state => 'on')
|
49
|
+
assert @transition.can_perform_on?(record)
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
class TransitionWithLoopbackTest < Test::Unit::TestCase
|
54
|
+
def setup
|
55
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
56
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
57
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'on')
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_should_have_a_from_state
|
61
|
+
assert_equal 'on', @transition.from_state
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_should_have_a_to_state
|
65
|
+
assert_equal 'on', @transition.to_state
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_should_be_a_loopback
|
69
|
+
assert @transition.loopback?
|
70
|
+
end
|
71
|
+
|
72
|
+
def test_should_be_able_to_perform_if_record_is_in_from_state
|
73
|
+
record = new_switch(:state => 'on')
|
74
|
+
assert @transition.can_perform_on?(record)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class TransitionAfterBeingPerformedTest < Test::Unit::TestCase
|
79
|
+
def setup
|
80
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
81
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
82
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, 'off', 'on')
|
83
|
+
|
84
|
+
@record = create_switch(:state => 'off')
|
85
|
+
@transition.perform(@record)
|
86
|
+
@record.reload
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_should_update_the_state_to_the_to_state
|
90
|
+
assert_equal 'on', @record.state
|
91
|
+
end
|
92
|
+
|
93
|
+
def test_should_no_longer_be_able_to_perform_on_the_record
|
94
|
+
assert !@transition.can_perform_on?(@record)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class TransitionWithLoopbackAfterBeingPerformedTest < Test::Unit::TestCase
|
99
|
+
def setup
|
100
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
101
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
102
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'on')
|
103
|
+
|
104
|
+
@record = create_switch(:state => 'on')
|
105
|
+
@transition.perform(@record)
|
106
|
+
@record.reload
|
107
|
+
end
|
108
|
+
|
109
|
+
def test_should_not_update_the_attribute
|
110
|
+
assert_equal 'on', @record.state
|
111
|
+
end
|
112
|
+
|
113
|
+
def test_should_still_be_able_to_perform_on_the_record
|
114
|
+
assert @transition.can_perform_on?(@record)
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
class TransitionWithCallbacksTest < Test::Unit::TestCase
|
119
|
+
def setup
|
120
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
121
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
122
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, 'off', 'on')
|
123
|
+
@record = create_switch(:state => 'off')
|
124
|
+
|
125
|
+
Switch.define_callbacks :before_exit_state_off, :before_enter_state_on, :after_exit_state_off, :after_enter_state_on
|
126
|
+
end
|
127
|
+
|
128
|
+
def test_should_not_perform_if_before_exit_callback_fails
|
129
|
+
Switch.before_exit_state_off Proc.new {|record| false}
|
130
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
131
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
132
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
133
|
+
|
134
|
+
assert !@transition.perform(@record)
|
135
|
+
assert_equal %w(), @record.callbacks
|
136
|
+
end
|
137
|
+
|
138
|
+
def test_should_not_perform_if_before_enter_callback_fails
|
139
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
140
|
+
Switch.before_enter_state_on Proc.new {|record| false}
|
141
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
142
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
143
|
+
|
144
|
+
assert !@transition.perform(@record)
|
145
|
+
assert_equal %w(before_exit), @record.callbacks
|
146
|
+
end
|
147
|
+
|
148
|
+
def test_should_not_perform_if_after_exit_callback_fails
|
149
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
150
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
151
|
+
Switch.after_exit_state_off Proc.new {|record| false}
|
152
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
153
|
+
|
154
|
+
assert !@transition.perform(@record)
|
155
|
+
assert_equal %w(before_exit before_enter), @record.callbacks
|
156
|
+
end
|
157
|
+
|
158
|
+
def test_should_not_perform_if_after_enter_callback_fails
|
159
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
160
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
161
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
162
|
+
Switch.after_enter_state_on Proc.new {|record| false}
|
163
|
+
|
164
|
+
assert !@transition.perform(@record)
|
165
|
+
assert_equal %w(before_exit before_enter after_exit), @record.callbacks
|
166
|
+
end
|
167
|
+
|
168
|
+
def test_should_perform_if_all_callbacks_are_successful
|
169
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
170
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
171
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
172
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
173
|
+
|
174
|
+
assert @transition.perform(@record)
|
175
|
+
assert_equal %w(before_exit before_enter after_exit after_enter), @record.callbacks
|
176
|
+
end
|
177
|
+
|
178
|
+
def teardown
|
179
|
+
Switch.class_eval do
|
180
|
+
@before_exit_state_off_callbacks = nil
|
181
|
+
@before_enter_state_on_callbacks = nil
|
182
|
+
@after_exit_state_off_callbacks = nil
|
183
|
+
@after_enter_state_on_callbacks = nil
|
184
|
+
end
|
185
|
+
end
|
186
|
+
end
|
187
|
+
|
188
|
+
class TransitionWithoutFromStateAndCallbacksTest < Test::Unit::TestCase
|
189
|
+
def setup
|
190
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
191
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
192
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, nil, 'on')
|
193
|
+
@record = create_switch(:state => 'off')
|
194
|
+
|
195
|
+
Switch.define_callbacks :before_exit_state_off, :before_enter_state_on, :after_exit_state_off, :after_enter_state_on
|
196
|
+
end
|
197
|
+
|
198
|
+
def test_should_not_perform_if_before_exit_callback_fails
|
199
|
+
Switch.before_exit_state_off Proc.new {|record| false}
|
200
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
201
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
202
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
203
|
+
|
204
|
+
assert !@transition.perform(@record)
|
205
|
+
assert_equal %w(), @record.callbacks
|
206
|
+
end
|
207
|
+
|
208
|
+
def test_should_not_perform_if_before_enter_callback_fails
|
209
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
210
|
+
Switch.before_enter_state_on Proc.new {|record| false}
|
211
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
212
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
213
|
+
|
214
|
+
assert !@transition.perform(@record)
|
215
|
+
assert_equal %w(before_exit), @record.callbacks
|
216
|
+
end
|
217
|
+
|
218
|
+
def test_should_not_perform_if_after_exit_callback_fails
|
219
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
220
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
221
|
+
Switch.after_exit_state_off Proc.new {|record| false}
|
222
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
223
|
+
|
224
|
+
assert !@transition.perform(@record)
|
225
|
+
assert_equal %w(before_exit before_enter), @record.callbacks
|
226
|
+
end
|
227
|
+
|
228
|
+
def test_should_not_perform_if_after_enter_callback_fails
|
229
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
230
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
231
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
232
|
+
Switch.after_enter_state_on Proc.new {|record| false}
|
233
|
+
|
234
|
+
assert !@transition.perform(@record)
|
235
|
+
assert_equal %w(before_exit before_enter after_exit), @record.callbacks
|
236
|
+
end
|
237
|
+
|
238
|
+
def test_should_perform_if_all_callbacks_are_successful
|
239
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
240
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
241
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
242
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
243
|
+
|
244
|
+
assert @transition.perform(@record)
|
245
|
+
assert_equal %w(before_exit before_enter after_exit after_enter), @record.callbacks
|
246
|
+
end
|
247
|
+
|
248
|
+
def teardown
|
249
|
+
Switch.class_eval do
|
250
|
+
@before_exit_state_off_callbacks = nil
|
251
|
+
@before_enter_state_on_callbacks = nil
|
252
|
+
@after_exit_state_off_callbacks = nil
|
253
|
+
@after_enter_state_on_callbacks = nil
|
254
|
+
end
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
class TransitionWithLoopbackAndCallbacksTest < Test::Unit::TestCase
|
259
|
+
def setup
|
260
|
+
@machine = PluginAWeek::StateMachine::Machine.new(Switch, 'state', :initial => 'off')
|
261
|
+
@event = PluginAWeek::StateMachine::Event.new(@machine, 'turn_on')
|
262
|
+
@transition = PluginAWeek::StateMachine::Transition.new(@event, 'on', 'on')
|
263
|
+
@record = create_switch(:state => 'on')
|
264
|
+
|
265
|
+
Switch.define_callbacks :before_exit_state_off, :before_enter_state_on, :after_exit_state_off, :after_enter_state_on
|
266
|
+
Switch.before_exit_state_off Proc.new {|record| record.callbacks << 'before_exit'; true}
|
267
|
+
Switch.before_enter_state_on Proc.new {|record| record.callbacks << 'before_enter'; true}
|
268
|
+
Switch.after_exit_state_off Proc.new {|record| record.callbacks << 'after_exit'; true}
|
269
|
+
Switch.after_enter_state_on Proc.new {|record| record.callbacks << 'after_enter'; true}
|
270
|
+
|
271
|
+
assert @transition.perform(@record)
|
272
|
+
end
|
273
|
+
|
274
|
+
def test_should_not_run_before_exit_callbacks
|
275
|
+
assert !@record.callbacks.include?('before_exit')
|
276
|
+
end
|
277
|
+
|
278
|
+
def test_should_not_run_before_enter_callbacks
|
279
|
+
assert !@record.callbacks.include?('before_enter')
|
280
|
+
end
|
281
|
+
|
282
|
+
def test_should_not_run_after_exit_callbacks
|
283
|
+
assert !@record.callbacks.include?('after_exit')
|
284
|
+
end
|
285
|
+
|
286
|
+
def test_should_not_run_after_enter_callbacks
|
287
|
+
assert !@record.callbacks.include?('after_enter')
|
288
|
+
end
|
289
|
+
|
290
|
+
def teardown
|
291
|
+
Switch.class_eval do
|
292
|
+
@before_exit_state_off_callbacks = nil
|
293
|
+
@before_enter_state_on_callbacks = nil
|
294
|
+
@after_exit_state_off_callbacks = nil
|
295
|
+
@after_enter_state_on_callbacks = nil
|
296
|
+
end
|
297
|
+
end
|
298
|
+
end
|
metadata
ADDED
@@ -0,0 +1,91 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: state_machine
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Aaron Pfeifer
|
8
|
+
autorequire: state_machine
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2008-05-05 00:00:00 -04:00
|
13
|
+
default_executable:
|
14
|
+
dependencies: []
|
15
|
+
|
16
|
+
description:
|
17
|
+
email: aaron@pluginaweek.org
|
18
|
+
executables: []
|
19
|
+
|
20
|
+
extensions: []
|
21
|
+
|
22
|
+
extra_rdoc_files: []
|
23
|
+
|
24
|
+
files:
|
25
|
+
- lib/state_machine.rb
|
26
|
+
- lib/state_machine
|
27
|
+
- lib/state_machine/machine.rb
|
28
|
+
- lib/state_machine/event.rb
|
29
|
+
- lib/state_machine/transition.rb
|
30
|
+
- test/factory.rb
|
31
|
+
- test/app_root
|
32
|
+
- test/app_root/db
|
33
|
+
- test/app_root/db/migrate
|
34
|
+
- test/app_root/db/migrate/004_create_vehicles.rb
|
35
|
+
- test/app_root/db/migrate/003_create_highways.rb
|
36
|
+
- test/app_root/db/migrate/002_create_auto_shops.rb
|
37
|
+
- test/app_root/db/migrate/001_create_switches.rb
|
38
|
+
- test/app_root/app
|
39
|
+
- test/app_root/app/models
|
40
|
+
- test/app_root/app/models/auto_shop.rb
|
41
|
+
- test/app_root/app/models/switch.rb
|
42
|
+
- test/app_root/app/models/vehicle.rb
|
43
|
+
- test/app_root/app/models/motorcycle.rb
|
44
|
+
- test/app_root/app/models/toggle_switch.rb
|
45
|
+
- test/app_root/app/models/car.rb
|
46
|
+
- test/app_root/app/models/highway.rb
|
47
|
+
- test/functional
|
48
|
+
- test/functional/state_machine_test.rb
|
49
|
+
- test/test_helper.rb
|
50
|
+
- test/unit
|
51
|
+
- test/unit/event_test.rb
|
52
|
+
- test/unit/machine_test.rb
|
53
|
+
- test/unit/transition_test.rb
|
54
|
+
- test/unit/state_machine_test.rb
|
55
|
+
- CHANGELOG
|
56
|
+
- init.rb
|
57
|
+
- MIT-LICENSE
|
58
|
+
- Rakefile
|
59
|
+
- README
|
60
|
+
has_rdoc: true
|
61
|
+
homepage: http://www.pluginaweek.org
|
62
|
+
post_install_message:
|
63
|
+
rdoc_options: []
|
64
|
+
|
65
|
+
require_paths:
|
66
|
+
- lib
|
67
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: "0"
|
72
|
+
version:
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
version: "0"
|
78
|
+
version:
|
79
|
+
requirements: []
|
80
|
+
|
81
|
+
rubyforge_project:
|
82
|
+
rubygems_version: 1.1.0
|
83
|
+
signing_key:
|
84
|
+
specification_version: 2
|
85
|
+
summary: Adds support for creating state machines for attributes within a model
|
86
|
+
test_files:
|
87
|
+
- test/functional/state_machine_test.rb
|
88
|
+
- test/unit/event_test.rb
|
89
|
+
- test/unit/machine_test.rb
|
90
|
+
- test/unit/transition_test.rb
|
91
|
+
- test/unit/state_machine_test.rb
|