state_machine 0.4.3 → 0.5.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.
Files changed (48) hide show
  1. data/CHANGELOG.rdoc +17 -0
  2. data/LICENSE +1 -1
  3. data/README.rdoc +54 -84
  4. data/Rakefile +1 -1
  5. data/examples/Car_state.png +0 -0
  6. data/examples/Vehicle_state.png +0 -0
  7. data/examples/auto_shop.rb +11 -0
  8. data/examples/car.rb +19 -0
  9. data/examples/traffic_light.rb +9 -0
  10. data/examples/vehicle.rb +35 -0
  11. data/lib/state_machine.rb +65 -52
  12. data/lib/state_machine/assertions.rb +1 -1
  13. data/lib/state_machine/callback.rb +13 -9
  14. data/lib/state_machine/eval_helpers.rb +4 -3
  15. data/lib/state_machine/event.rb +51 -33
  16. data/lib/state_machine/extensions.rb +2 -2
  17. data/lib/state_machine/guard.rb +47 -41
  18. data/lib/state_machine/integrations.rb +67 -0
  19. data/lib/state_machine/integrations/active_record.rb +62 -36
  20. data/lib/state_machine/integrations/active_record/observer.rb +41 -0
  21. data/lib/state_machine/integrations/data_mapper.rb +23 -37
  22. data/lib/state_machine/integrations/data_mapper/observer.rb +23 -9
  23. data/lib/state_machine/integrations/sequel.rb +23 -24
  24. data/lib/state_machine/machine.rb +380 -277
  25. data/lib/state_machine/node_collection.rb +142 -0
  26. data/lib/state_machine/state.rb +114 -69
  27. data/lib/state_machine/state_collection.rb +38 -0
  28. data/lib/state_machine/transition.rb +36 -17
  29. data/test/active_record.log +2940 -85664
  30. data/test/functional/state_machine_test.rb +49 -53
  31. data/test/sequel.log +747 -11990
  32. data/test/unit/assertions_test.rb +2 -1
  33. data/test/unit/callback_test.rb +14 -12
  34. data/test/unit/eval_helpers_test.rb +25 -6
  35. data/test/unit/event_test.rb +144 -124
  36. data/test/unit/guard_test.rb +118 -140
  37. data/test/unit/integrations/active_record_test.rb +102 -68
  38. data/test/unit/integrations/data_mapper_test.rb +48 -37
  39. data/test/unit/integrations/sequel_test.rb +34 -25
  40. data/test/unit/integrations_test.rb +42 -0
  41. data/test/unit/machine_test.rb +460 -531
  42. data/test/unit/node_collection_test.rb +208 -0
  43. data/test/unit/state_collection_test.rb +167 -0
  44. data/test/unit/state_machine_test.rb +1 -1
  45. data/test/unit/state_test.rb +223 -200
  46. data/test/unit/transition_test.rb +81 -46
  47. metadata +17 -3
  48. data/test/data_mapper.log +0 -30860
@@ -0,0 +1,208 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class NodeCollectionByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @collection = StateMachine::NodeCollection.new
6
+ end
7
+
8
+ def test_should_not_have_any_nodes
9
+ assert !@collection.any?
10
+ end
11
+
12
+ def test_should_have_a_zero_length
13
+ assert_equal 0, @collection.length
14
+ end
15
+
16
+ def test_should_index_by_name
17
+ @collection << object = Struct.new(:name).new(:parked)
18
+ assert_equal object, @collection[:parked]
19
+ end
20
+ end
21
+
22
+ class NodeCollectionTest < Test::Unit::TestCase
23
+ def setup
24
+ @collection = StateMachine::NodeCollection.new
25
+ end
26
+
27
+ def test_should_raise_exception_if_invalid_option_specified
28
+ exception = assert_raise(ArgumentError) { StateMachine::NodeCollection.new(:invalid => true) }
29
+ assert_equal 'Invalid key(s): invalid', exception.message
30
+ end
31
+
32
+ def test_should_raise_exception_on_lookup_if_invalid_index_specified
33
+ exception = assert_raise(ArgumentError) { @collection[:something, :invalid] }
34
+ assert_equal 'Invalid index: :invalid', exception.message
35
+ end
36
+
37
+ def test_should_raise_exception_on_fetch_if_invalid_index_specified
38
+ exception = assert_raise(ArgumentError) { @collection.fetch(:something, :invalid) }
39
+ assert_equal 'Invalid index: :invalid', exception.message
40
+ end
41
+ end
42
+
43
+ class NodeCollectionAfterBeingCopiedTest < Test::Unit::TestCase
44
+ def setup
45
+ @collection = StateMachine::NodeCollection.new
46
+ @collection << @parked = Struct.new(:name).new(:parked)
47
+
48
+ @copied_collection = @collection.dup
49
+ @copied_collection << @idling = Struct.new(:name).new(:idling)
50
+ end
51
+
52
+ def test_should_not_modify_the_original_list
53
+ assert_equal 1, @collection.length
54
+ assert_equal 2, @copied_collection.length
55
+ end
56
+
57
+ def test_should_not_modify_the_indices
58
+ assert_nil @collection[:idling]
59
+ assert_equal @idling, @copied_collection[:idling]
60
+ end
61
+
62
+ def test_should_copy_each_node
63
+ assert_not_same @parked, @copied_collection[:parked]
64
+ end
65
+ end
66
+
67
+ class NodeCollectionWithoutIndicesTest < Test::Unit::TestCase
68
+ def setup
69
+ @collection = StateMachine::NodeCollection.new(:index => {})
70
+ end
71
+
72
+ def test_should_allow_adding_node
73
+ @collection << Object.new
74
+ assert_equal 1, @collection.length
75
+ end
76
+
77
+ def test_should_not_allow_keys_retrieval
78
+ exception = assert_raise(ArgumentError) { @collection.keys }
79
+ assert_equal 'No indices configured', exception.message
80
+ end
81
+
82
+ def test_should_not_allow_lookup
83
+ @collection << object = Object.new
84
+ exception = assert_raise(ArgumentError) { @collection[0] }
85
+ assert_equal 'No indices configured', exception.message
86
+ end
87
+
88
+ def test_should_not_allow_fetching
89
+ @collection << object = Object.new
90
+ exception = assert_raise(ArgumentError) { @collection.fetch(0) }
91
+ assert_equal 'No indices configured', exception.message
92
+ end
93
+ end
94
+
95
+ class NodeCollectionWithIndicesTest < Test::Unit::TestCase
96
+ def setup
97
+ @collection = StateMachine::NodeCollection.new(:index => [:name, :value])
98
+
99
+ @object = Struct.new(:name, :value).new(:parked, 1)
100
+ @collection << @object
101
+ end
102
+
103
+ def test_should_use_first_index_by_default_on_key_retrieval
104
+ assert_equal [:parked], @collection.keys
105
+ end
106
+
107
+ def test_should_allow_customizing_index_for_key_retrieval
108
+ assert_equal [1], @collection.keys(:value)
109
+ end
110
+
111
+ def test_should_use_first_index_by_default_on_lookup
112
+ assert_equal @object, @collection[:parked]
113
+ assert_nil @collection[1]
114
+ end
115
+
116
+ def test_should_allow_customizing_index_on_lookup
117
+ assert_equal @object, @collection[1, :value]
118
+ assert_nil @collection[:parked, :value]
119
+ end
120
+
121
+ def test_should_use_first_index_by_default_on_fetch
122
+ assert_equal @object, @collection.fetch(:parked)
123
+ exception = assert_raise(ArgumentError) { @collection.fetch(1) }
124
+ assert_equal '1 is an invalid name', exception.message
125
+ end
126
+
127
+ def test_should_allow_customizing_index_on_fetch
128
+ assert_equal @object, @collection.fetch(1, :value)
129
+ exception = assert_raise(ArgumentError) { @collection.fetch(:parked, :value) }
130
+ assert_equal ':parked is an invalid value', exception.message
131
+ end
132
+ end
133
+
134
+ class NodeCollectionWithNodesTest < Test::Unit::TestCase
135
+ def setup
136
+ @collection = StateMachine::NodeCollection.new
137
+
138
+ @klass = Struct.new(:name)
139
+ @parked = @klass.new(:parked)
140
+ @idling = @klass.new(:idling)
141
+
142
+ @collection << @parked
143
+ @collection << @idling
144
+ end
145
+
146
+ def test_should_be_able_to_enumerate
147
+ order = []
148
+ @collection.each {|object| order << object}
149
+
150
+ assert_equal [@parked, @idling], order
151
+ end
152
+
153
+ def test_should_be_able_to_access_by_index
154
+ assert_equal @parked, @collection.at(0)
155
+ assert_equal @idling, @collection.at(1)
156
+ end
157
+ end
158
+
159
+ class NodeCollectionAfterUpdateTest < Test::Unit::TestCase
160
+ def setup
161
+ @collection = StateMachine::NodeCollection.new(:index => [:name, :value])
162
+
163
+ @klass = Struct.new(:name, :value)
164
+ @parked = @klass.new(:parked, 1)
165
+ @idling = @klass.new(:idling, 2)
166
+
167
+ @collection << @parked << @idling
168
+
169
+ @parked.name = :parking
170
+ @parked.value = 0
171
+ @collection.update(@parked)
172
+ end
173
+
174
+ def test_should_not_change_the_index
175
+ assert_equal @parked, @collection.at(0)
176
+ end
177
+
178
+ def test_should_not_duplicate_in_the_collection
179
+ assert_equal 2, @collection.length
180
+ end
181
+
182
+ def test_should_add_each_indexed_key
183
+ assert_equal @parked, @collection[:parking]
184
+ assert_equal @parked, @collection[0, :value]
185
+ end
186
+
187
+ def test_should_remove_each_old_indexed_key
188
+ assert_nil @collection[:parked]
189
+ assert_nil @collection[1, :value]
190
+ end
191
+ end
192
+
193
+ class NodeCollectionChangingMachineTest < Test::Unit::TestCase
194
+ def setup
195
+ @collection = StateMachine::NodeCollection.new
196
+
197
+ @klass = Struct.new(:name, :machine)
198
+ @collection << @parked = @klass.new(:parked)
199
+ @collection << @idling = @klass.new(:idling)
200
+
201
+ @collection.machine = :machine
202
+ end
203
+
204
+ def test_should_update_each_node_machine
205
+ assert_equal :machine, @parked.machine
206
+ assert_equal :machine, @idling.machine
207
+ end
208
+ end
@@ -0,0 +1,167 @@
1
+ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
2
+
3
+ class StateCollectionByDefaultTest < Test::Unit::TestCase
4
+ def setup
5
+ @states = StateMachine::StateCollection.new
6
+ end
7
+
8
+ def test_should_not_have_any_nodes
9
+ assert !@states.any?
10
+ end
11
+
12
+ def test_should_have_a_zero_length
13
+ assert_equal 0, @states.length
14
+ end
15
+
16
+ def test_should_be_empty_by_priority
17
+ assert_equal [], @states.by_priority
18
+ end
19
+ end
20
+
21
+ class StateCollectionWithInitialStateTest < Test::Unit::TestCase
22
+ def setup
23
+ @machine = StateMachine::Machine.new(Class.new)
24
+
25
+ @states = StateMachine::StateCollection.new
26
+ @states << @parked = StateMachine::State.new(@machine, :parked)
27
+ @states << @idling = StateMachine::State.new(@machine, :idling)
28
+
29
+ @parked.initial = true
30
+ end
31
+
32
+ def test_should_order_state_before_transition_states
33
+ @machine.event :ignite do
34
+ transition :to => :idling
35
+ end
36
+ assert_equal [@parked, @idling], @states.by_priority
37
+ end
38
+
39
+ def test_should_order_state_before_states_with_behaviors
40
+ @idling.context do
41
+ def speed
42
+ 0
43
+ end
44
+ end
45
+ assert_equal [@parked, @idling], @states.by_priority
46
+ end
47
+
48
+ def test_should_order_state_before_other_states
49
+ assert_equal [@parked, @idling], @states.by_priority
50
+ end
51
+
52
+ def test_should_order_state_before_callback_states
53
+ @machine.before_transition :from => :idling, :do => lambda {}
54
+ assert_equal [@parked, @idling], @states.by_priority
55
+ end
56
+ end
57
+
58
+ class StateCollectionWithStateBehaviorsTest < Test::Unit::TestCase
59
+ def setup
60
+ @machine = StateMachine::Machine.new(Class.new)
61
+
62
+ @states = StateMachine::StateCollection.new
63
+ @states << @parked = StateMachine::State.new(@machine, :parked)
64
+ @states << @idling = StateMachine::State.new(@machine, :idling)
65
+
66
+ @idling.context do
67
+ def speed
68
+ 0
69
+ end
70
+ end
71
+ end
72
+
73
+ def test_should_order_states_after_initial_state
74
+ @parked.initial = true
75
+ assert_equal [@parked, @idling], @states.by_priority
76
+ end
77
+
78
+ def test_should_order_states_after_transition_states
79
+ @machine.event :ignite do
80
+ transition :from => :parked
81
+ end
82
+ assert_equal [@parked, @idling], @states.by_priority
83
+ end
84
+
85
+ def test_should_order_states_before_other_states
86
+ assert_equal [@idling, @parked], @states.by_priority
87
+ end
88
+
89
+ def test_should_order_state_before_callback_states
90
+ @machine.before_transition :from => :parked, :do => lambda {}
91
+ assert_equal [@idling, @parked], @states.by_priority
92
+ end
93
+ end
94
+
95
+ class StateCollectionWithEventTransitionsTest < Test::Unit::TestCase
96
+ def setup
97
+ @machine = StateMachine::Machine.new(Class.new)
98
+
99
+ @states = StateMachine::StateCollection.new
100
+ @states << @parked = StateMachine::State.new(@machine, :parked)
101
+ @states << @idling = StateMachine::State.new(@machine, :idling)
102
+
103
+ @machine.event :ignite do
104
+ transition :to => :idling
105
+ end
106
+ end
107
+
108
+ def test_should_order_states_after_initial_state
109
+ @parked.initial = true
110
+ assert_equal [@parked, @idling], @states.by_priority
111
+ end
112
+
113
+ def test_should_order_states_before_states_with_behaviors
114
+ @parked.context do
115
+ def speed
116
+ 0
117
+ end
118
+ end
119
+ assert_equal [@idling, @parked], @states.by_priority
120
+ end
121
+
122
+ def test_should_order_states_before_other_states
123
+ assert_equal [@idling, @parked], @states.by_priority
124
+ end
125
+
126
+ def test_should_order_state_before_callback_states
127
+ @machine.before_transition :from => :parked, :do => lambda {}
128
+ assert_equal [@idling, @parked], @states.by_priority
129
+ end
130
+ end
131
+
132
+ class StateCollectionWithTransitionCallbacksTest < Test::Unit::TestCase
133
+ def setup
134
+ @machine = StateMachine::Machine.new(Class.new)
135
+
136
+ @states = StateMachine::StateCollection.new
137
+ @states << @parked = StateMachine::State.new(@machine, :parked)
138
+ @states << @idling = StateMachine::State.new(@machine, :idling)
139
+
140
+ @machine.before_transition :to => :idling, :do => lambda {}
141
+ end
142
+
143
+ def test_should_order_states_after_initial_state
144
+ @parked.initial = true
145
+ assert_equal [@parked, @idling], @states.by_priority
146
+ end
147
+
148
+ def test_should_order_states_after_transition_states
149
+ @machine.event :ignite do
150
+ transition :from => :parked
151
+ end
152
+ assert_equal [@parked, @idling], @states.by_priority
153
+ end
154
+
155
+ def test_should_order_states_after_states_with_behaviors
156
+ @parked.context do
157
+ def speed
158
+ 0
159
+ end
160
+ end
161
+ assert_equal [@parked, @idling], @states.by_priority
162
+ end
163
+
164
+ def test_should_order_states_after_other_states
165
+ assert_equal [@parked, @idling], @states.by_priority
166
+ end
167
+ end
@@ -7,7 +7,7 @@ class StateMachineByDefaultTest < Test::Unit::TestCase
7
7
  end
8
8
 
9
9
  def test_should_use_state_attribute
10
- assert_equal 'state', @machine.attribute
10
+ assert_equal :state, @machine.attribute
11
11
  end
12
12
  end
13
13
 
@@ -3,50 +3,86 @@ require File.expand_path(File.dirname(__FILE__) + '/../test_helper')
3
3
  class StateByDefaultTest < Test::Unit::TestCase
4
4
  def setup
5
5
  @machine = StateMachine::Machine.new(Class.new)
6
- @state = StateMachine::State.new(@machine, 'on')
6
+ @state = StateMachine::State.new(@machine, :parked)
7
7
  end
8
8
 
9
9
  def test_should_have_a_machine
10
10
  assert_equal @machine, @state.machine
11
11
  end
12
12
 
13
- def test_should_have_a_value
14
- assert_equal 'on', @state.value
13
+ def test_should_have_a_name
14
+ assert_equal :parked, @state.name
15
15
  end
16
16
 
17
- def test_should_not_have_any_methods
18
- expected = {}
19
- assert_equal expected, @state.methods
17
+ def test_should_use_stringify_the_name_as_the_value
18
+ assert_equal 'parked', @state.value
20
19
  end
21
20
 
22
21
  def test_should_not_be_initial
23
22
  assert !@state.initial
24
23
  end
24
+
25
+ def test_should_not_have_a_matcher
26
+ assert_nil @state.matcher
27
+ end
28
+
29
+ def test_should_not_have_any_methods
30
+ expected = {}
31
+ assert_equal expected, @state.methods
32
+ end
25
33
  end
26
34
 
27
35
  class StateTest < Test::Unit::TestCase
28
36
  def setup
29
37
  @machine = StateMachine::Machine.new(Class.new)
38
+ @state = StateMachine::State.new(@machine, :parked)
30
39
  end
31
40
 
32
41
  def test_should_raise_exception_if_invalid_option_specified
33
- assert_raise(ArgumentError) {StateMachine::State.new(@machine, 'on', :invalid => true)}
42
+ exception = assert_raise(ArgumentError) {StateMachine::State.new(@machine, :parked, :invalid => true)}
43
+ assert_equal 'Invalid key(s): invalid', exception.message
44
+ end
45
+
46
+ def test_should_allow_changing_machine
47
+ new_machine = StateMachine::Machine.new(Class.new)
48
+ @state.machine = new_machine
49
+ assert_equal new_machine, @state.machine
50
+ end
51
+
52
+ def test_should_allow_changing_value
53
+ @state.value = 1
54
+ assert_equal 1, @state.value
55
+ end
56
+
57
+ def test_should_allow_changing_initial
58
+ @state.initial = true
59
+ assert @state.initial
60
+ end
61
+
62
+ def test_should_allow_changing_matcher
63
+ matcher = lambda {}
64
+ @state.matcher = matcher
65
+ assert_equal matcher, @state.matcher
66
+ end
67
+
68
+ def test_should_use_pretty_inspect
69
+ assert_equal '#<StateMachine::State name=:parked value="parked" initial=false>', @state.inspect
34
70
  end
35
71
  end
36
72
 
37
- class StateWithNilValueTest < Test::Unit::TestCase
73
+ class StateWithoutNameTest < Test::Unit::TestCase
38
74
  def setup
39
75
  @klass = Class.new
40
76
  @machine = StateMachine::Machine.new(@klass)
41
77
  @state = StateMachine::State.new(@machine, nil)
42
78
  end
43
79
 
44
- def test_should_be_nil_without_object
45
- assert_nil @state.value
80
+ def test_should_have_a_nil_name
81
+ assert_nil @state.name
46
82
  end
47
83
 
48
- def test_should_be_nil_with_object
49
- assert_nil @state.value(@klass.new)
84
+ def test_should_have_a_nil_value
85
+ assert_nil @state.value
50
86
  end
51
87
 
52
88
  def test_should_not_redefine_nil_predicate
@@ -54,90 +90,119 @@ class StateWithNilValueTest < Test::Unit::TestCase
54
90
  assert !object.nil?
55
91
  assert !object.respond_to?('?')
56
92
  end
93
+
94
+ def test_should_have_a_description
95
+ assert_equal 'nil', @state.description
96
+ end
57
97
  end
58
98
 
59
- class StateWithStringValueTest < Test::Unit::TestCase
99
+ class StateWithNameTest < Test::Unit::TestCase
60
100
  def setup
61
101
  @klass = Class.new
62
102
  @machine = StateMachine::Machine.new(@klass)
63
- @state = StateMachine::State.new(@machine, 'on')
103
+ @state = StateMachine::State.new(@machine, :parked)
104
+ end
105
+
106
+ def test_should_have_a_name
107
+ assert_equal :parked, @state.name
64
108
  end
65
109
 
66
- def test_should_use_original_value_without_object
67
- assert_equal 'on', @state.value
110
+ def test_should_use_stringify_the_name_as_the_value
111
+ assert_equal 'parked', @state.value
68
112
  end
69
113
 
70
- def test_should_use_original_value_with_object
71
- assert_equal 'on', @state.value(@klass.new)
114
+ def test_should_match_stringified_name
115
+ assert @state.matches?('parked')
116
+ assert !@state.matches?('idling')
117
+ end
118
+
119
+ def test_should_not_include_value_in_description
120
+ assert_equal 'parked', @state.description
72
121
  end
73
122
 
74
123
  def test_should_define_predicate
75
- object = @klass.new
76
- assert object.respond_to?(:on?)
124
+ assert @klass.new.respond_to?(:parked?)
77
125
  end
78
126
  end
79
127
 
80
- class StateWithSymbolicValueTest < Test::Unit::TestCase
128
+ class StateWithNilValueTest < Test::Unit::TestCase
81
129
  def setup
82
130
  @klass = Class.new
83
131
  @machine = StateMachine::Machine.new(@klass)
84
- @state = StateMachine::State.new(@machine, :on)
132
+ @state = StateMachine::State.new(@machine, :parked, :value => nil)
133
+ end
134
+
135
+ def test_should_have_a_name
136
+ assert_equal :parked, @state.name
85
137
  end
86
138
 
87
- def test_should_use_original_value_without_object
88
- assert_equal :on, @state.value
139
+ def test_should_have_a_nil_value
140
+ assert_nil @state.value
89
141
  end
90
142
 
91
- def test_should_use_original_value_with_object
92
- assert_equal :on, @state.value(@klass.new)
143
+ def test_should_match_nil_values
144
+ assert @state.matches?(nil)
145
+ end
146
+
147
+ def test_should_have_a_description
148
+ assert_equal 'parked (nil)', @state.description
93
149
  end
94
150
 
95
151
  def test_should_define_predicate
96
152
  object = @klass.new
97
- assert object.respond_to?(:on?)
153
+ assert object.respond_to?(:parked?)
98
154
  end
99
155
  end
100
156
 
101
- class StateWithIntegerValueTest < Test::Unit::TestCase
157
+ class StateWithSymbolicValueTest < Test::Unit::TestCase
102
158
  def setup
103
159
  @klass = Class.new
104
160
  @machine = StateMachine::Machine.new(@klass)
105
- @state = StateMachine::State.new(@machine, 1)
161
+ @state = StateMachine::State.new(@machine, :parked, :value => :parked)
106
162
  end
107
163
 
108
- def test_should_use_original_value_without_object
109
- assert_equal 1, @state.value
164
+ def test_should_use_custom_value
165
+ assert_equal :parked, @state.value
166
+ end
167
+
168
+ def test_should_not_include_value_in_description
169
+ assert_equal 'parked', @state.description
110
170
  end
111
171
 
112
- def test_should_use_original_value_with_object
113
- assert_equal 1, @state.value(@klass.new)
172
+ def test_should_match_symbolic_value
173
+ assert @state.matches?(:parked)
174
+ assert !@state.matches?('parked')
114
175
  end
115
176
 
116
- def test_should_not_define_predicate
177
+ def test_should_define_predicate
117
178
  object = @klass.new
118
- assert !object.respond_to?('1?')
179
+ assert object.respond_to?(:parked?)
119
180
  end
120
181
  end
121
182
 
122
- class StateWithObjectValueTest < Test::Unit::TestCase
183
+ class StateWithIntegerValueTest < Test::Unit::TestCase
123
184
  def setup
124
185
  @klass = Class.new
125
186
  @machine = StateMachine::Machine.new(@klass)
126
- @value = Object.new
127
- @state = StateMachine::State.new(@machine, @value)
187
+ @state = StateMachine::State.new(@machine, :parked, :value => 1)
188
+ end
189
+
190
+ def test_should_use_custom_value
191
+ assert_equal 1, @state.value
128
192
  end
129
193
 
130
- def test_should_use_original_value_without_object
131
- assert_equal @value, @state.value
194
+ def test_should_include_value_in_description
195
+ assert_equal 'parked (1)', @state.description
132
196
  end
133
197
 
134
- def test_should_use_original_value_with_object
135
- assert_equal @value, @state.value(@klass.new)
198
+ def test_should_match_integer_value
199
+ assert @state.matches?(1)
200
+ assert !@state.matches?(2)
136
201
  end
137
202
 
138
- def test_should_not_define_predicate
203
+ def test_should_define_predicate
139
204
  object = @klass.new
140
- assert !object.respond_to?("#{@value.inspect}?")
205
+ assert object.respond_to?(:parked?)
141
206
  end
142
207
  end
143
208
 
@@ -146,35 +211,49 @@ class StateWithLambdaValueTest < Test::Unit::TestCase
146
211
  @klass = Class.new
147
212
  @args = nil
148
213
  @machine = StateMachine::Machine.new(@klass)
149
- @value = lambda {|*args| @args = args; 'on'}
150
- @state = StateMachine::State.new(@machine, @value)
214
+ @state = StateMachine::State.new(@machine, :parked, :value => lambda {|*args| @args = args; :parked})
151
215
  end
152
216
 
153
- def test_should_use_original_value_without_object
154
- assert_equal @value, @state.value
217
+ def test_should_use_evaluated_value
218
+ assert_equal :parked, @state.value
155
219
  end
156
220
 
157
- def test_should_use_evaluated_value_with_object
158
- assert_equal 'on', @state.value(@klass.new)
221
+ def test_should_include_masked_value_in_description
222
+ assert_equal 'parked (*)', @state.description
159
223
  end
160
224
 
161
- def test_should_pass_object_in_when_evaluating_value
162
- object = @klass.new
163
- @state.value(object)
164
-
165
- assert_equal [object], @args
225
+ def test_should_not_pass_in_any_arguments
226
+ @state.value
227
+ assert_equal [], @args
166
228
  end
167
229
 
168
- def test_should_not_define_predicate
230
+ def test_should_define_predicate
169
231
  object = @klass.new
170
- assert !object.respond_to?("#{@value.inspect}?")
232
+ assert object.respond_to?(:parked?)
233
+ end
234
+ end
235
+
236
+ class StateWithMatcherTest < Test::Unit::TestCase
237
+ def setup
238
+ @klass = Class.new
239
+ @args = nil
240
+ @machine = StateMachine::Machine.new(@klass)
241
+ @state = StateMachine::State.new(@machine, :parked, :if => lambda {|value| value == 1})
242
+ end
243
+
244
+ def test_should_not_match_actual_value
245
+ assert !@state.matches?('parked')
246
+ end
247
+
248
+ def test_should_match_evaluated_block
249
+ assert @state.matches?(1)
171
250
  end
172
251
  end
173
252
 
174
253
  class StateInitialTest < Test::Unit::TestCase
175
254
  def setup
176
255
  @machine = StateMachine::Machine.new(Class.new)
177
- @state = StateMachine::State.new(@machine, 'on', :initial => true)
256
+ @state = StateMachine::State.new(@machine, :parked, :initial => true)
178
257
  end
179
258
 
180
259
  def test_should_be_initial
@@ -185,7 +264,7 @@ end
185
264
  class StateNotInitialTest < Test::Unit::TestCase
186
265
  def setup
187
266
  @machine = StateMachine::Machine.new(Class.new)
188
- @state = StateMachine::State.new(@machine, 'on', :initial => false)
267
+ @state = StateMachine::State.new(@machine, :parked, :initial => false)
189
268
  end
190
269
 
191
270
  def test_should_not_be_initial
@@ -196,41 +275,37 @@ end
196
275
  class StateWithConflictingPredicateTest < Test::Unit::TestCase
197
276
  def setup
198
277
  @klass = Class.new do
199
- def on?
200
- true
278
+ def parked?
279
+ 1
201
280
  end
202
281
  end
203
282
  @machine = StateMachine::Machine.new(@klass)
204
- @state = StateMachine::State.new(@machine, 'on')
283
+ @state = StateMachine::State.new(@machine, :parked)
205
284
  @object = @klass.new
206
285
  end
207
286
 
208
- def test_should_not_define_state_predicate
209
- assert @object.on?
287
+ def test_should_redefine_state_predicate
288
+ assert_equal false, @object.parked?
210
289
  end
211
290
  end
212
291
 
213
292
  class StateWithNamespaceTest < Test::Unit::TestCase
214
293
  def setup
215
- @klass = Class.new do
216
- def on?
217
- true
218
- end
219
- end
220
- @machine = StateMachine::Machine.new(@klass, :namespace => 'switch')
221
- @state = StateMachine::State.new(@machine, 'on')
294
+ @klass = Class.new
295
+ @machine = StateMachine::Machine.new(@klass, :namespace => 'gear')
296
+ @state = StateMachine::State.new(@machine, :parked)
222
297
  @object = @klass.new
223
298
  end
224
299
 
225
300
  def test_should_namespace_predicate
226
- assert @object.respond_to?(:switch_on?)
301
+ assert @object.respond_to?(:gear_parked?)
227
302
  end
228
303
  end
229
304
 
230
305
  class StateAfterBeingCopiedTest < Test::Unit::TestCase
231
306
  def setup
232
307
  @machine = StateMachine::Machine.new(Class.new)
233
- @state = StateMachine::State.new(@machine, 'on')
308
+ @state = StateMachine::State.new(@machine, :parked)
234
309
  @copied_state = @state.dup
235
310
  end
236
311
 
@@ -244,24 +319,24 @@ class StateWithContextTest < Test::Unit::TestCase
244
319
  @klass = Class.new
245
320
  @machine = StateMachine::Machine.new(@klass)
246
321
  @ancestors = @klass.ancestors
247
- @state = StateMachine::State.new(@machine, 'on')
322
+ @state = StateMachine::State.new(@machine, :idling)
248
323
 
249
- color_method = nil
250
- glow_method = nil
324
+ speed_method = nil
325
+ rpm_method = nil
251
326
  @state.context do
252
- def color
253
- 'green'
327
+ def speed
328
+ 0
254
329
  end
255
- color_method = instance_method(:color)
330
+ speed_method = instance_method(:speed)
256
331
 
257
- def glow
258
- 3
332
+ def rpm
333
+ 1000
259
334
  end
260
- glow_method = instance_method(:glow)
335
+ rpm_method = instance_method(:rpm)
261
336
  end
262
337
 
263
- @color_method = color_method
264
- @glow_method = glow_method
338
+ @speed_method = speed_method
339
+ @rpm_method = rpm_method
265
340
  end
266
341
 
267
342
  def test_should_include_new_module_in_owner_class
@@ -270,17 +345,17 @@ class StateWithContextTest < Test::Unit::TestCase
270
345
  end
271
346
 
272
347
  def test_should_define_each_context_method_in_owner_class
273
- %w(color glow).each {|method| assert @klass.instance_methods.include?(method)}
348
+ %w(speed rpm).each {|method| assert @klass.method_defined?(method)}
274
349
  end
275
350
 
276
351
  def test_should_not_use_context_methods_as_owner_class_methods
277
- assert_not_equal @color_method, @klass.instance_method(:color)
278
- assert_not_equal @glow_method, @klass.instance_method(:glow)
352
+ assert_not_equal @speed_method, @klass.instance_method(:speed)
353
+ assert_not_equal @rpm_method, @klass.instance_method(:rpm)
279
354
  end
280
355
 
281
356
  def test_should_include_context_methods_in_state_methods
282
- assert_equal @color_method, @state.methods['color']
283
- assert_equal @glow_method, @state.methods['glow']
357
+ assert_equal @speed_method, @state.methods[:speed]
358
+ assert_equal @rpm_method, @state.methods[:rpm]
284
359
  end
285
360
  end
286
361
 
@@ -289,27 +364,27 @@ class StateWithMultipleContextsTest < Test::Unit::TestCase
289
364
  @klass = Class.new
290
365
  @machine = StateMachine::Machine.new(@klass)
291
366
  @ancestors = @klass.ancestors
292
- @state = StateMachine::State.new(@machine, 'on')
367
+ @state = StateMachine::State.new(@machine, :idling)
293
368
 
294
- color_method = nil
369
+ speed_method = nil
295
370
  @state.context do
296
- def color
297
- 'green'
371
+ def speed
372
+ 0
298
373
  end
299
374
 
300
- color_method = instance_method(:color)
375
+ speed_method = instance_method(:speed)
301
376
  end
302
- @color_method = color_method
377
+ @speed_method = speed_method
303
378
 
304
- glow_method = nil
379
+ rpm_method = nil
305
380
  @state.context do
306
- def glow
307
- 3
381
+ def rpm
382
+ 1000
308
383
  end
309
384
 
310
- glow_method = instance_method(:glow)
385
+ rpm_method = instance_method(:rpm)
311
386
  end
312
- @glow_method = glow_method
387
+ @rpm_method = rpm_method
313
388
  end
314
389
 
315
390
  def test_should_include_new_module_in_owner_class
@@ -318,40 +393,40 @@ class StateWithMultipleContextsTest < Test::Unit::TestCase
318
393
  end
319
394
 
320
395
  def test_should_define_each_context_method_in_owner_class
321
- %w(color glow).each {|method| assert @klass.instance_methods.include?(method)}
396
+ %w(speed rpm).each {|method| assert @klass.method_defined?(method)}
322
397
  end
323
398
 
324
399
  def test_should_not_use_context_methods_as_owner_class_methods
325
- assert_not_equal @color_method, @klass.instance_method(:color)
326
- assert_not_equal @glow_method, @klass.instance_method(:glow)
400
+ assert_not_equal @speed_method, @klass.instance_method(:speed)
401
+ assert_not_equal @rpm_method, @klass.instance_method(:rpm)
327
402
  end
328
403
 
329
404
  def test_should_include_context_methods_in_state_methods
330
- assert_equal @color_method, @state.methods['color']
331
- assert_equal @glow_method, @state.methods['glow']
405
+ assert_equal @speed_method, @state.methods[:speed]
406
+ assert_equal @rpm_method, @state.methods[:rpm]
332
407
  end
333
408
  end
334
409
 
335
410
  class StateWithExistingContextMethodTest < Test::Unit::TestCase
336
411
  def setup
337
412
  @klass = Class.new do
338
- def color
339
- 'always green'
413
+ def speed
414
+ 60
340
415
  end
341
416
  end
342
- @original_color_method = @klass.instance_method(:color)
417
+ @original_speed_method = @klass.instance_method(:speed)
343
418
 
344
419
  @machine = StateMachine::Machine.new(@klass)
345
- @state = StateMachine::State.new(@machine, 'on')
420
+ @state = StateMachine::State.new(@machine, :idling)
346
421
  @state.context do
347
- def color
348
- 'green'
422
+ def speed
423
+ 0
349
424
  end
350
425
  end
351
426
  end
352
427
 
353
428
  def test_should_not_override_method
354
- assert_equal @original_color_method, @klass.instance_method(:color)
429
+ assert_equal @original_speed_method, @klass.instance_method(:speed)
355
430
  end
356
431
  end
357
432
 
@@ -361,27 +436,27 @@ class StateWithRedefinedContextMethodTest < Test::Unit::TestCase
361
436
  @machine = StateMachine::Machine.new(@klass)
362
437
  @state = StateMachine::State.new(@machine, 'on')
363
438
 
364
- old_color_method = nil
439
+ old_speed_method = nil
365
440
  @state.context do
366
- def color
367
- 'green'
441
+ def speed
442
+ 0
368
443
  end
369
- old_color_method = instance_method(:color)
444
+ old_speed_method = instance_method(:speed)
370
445
  end
371
- @old_color_method = old_color_method
446
+ @old_speed_method = old_speed_method
372
447
 
373
- current_color_method = nil
448
+ current_speed_method = nil
374
449
  @state.context do
375
- def color
450
+ def speed
376
451
  'green'
377
452
  end
378
- current_color_method = instance_method(:color)
453
+ current_speed_method = instance_method(:speed)
379
454
  end
380
- @current_color_method = current_color_method
455
+ @current_speed_method = current_speed_method
381
456
  end
382
457
 
383
458
  def test_should_track_latest_defined_method
384
- assert_equal @current_color_method, @state.methods['color']
459
+ assert_equal @current_speed_method, @state.methods[:speed]
385
460
  end
386
461
  end
387
462
 
@@ -390,10 +465,10 @@ class StateWithInvalidMethodCallTest < Test::Unit::TestCase
390
465
  @klass = Class.new
391
466
  @machine = StateMachine::Machine.new(@klass)
392
467
  @ancestors = @klass.ancestors
393
- @state = StateMachine::State.new(@machine, 'on')
468
+ @state = StateMachine::State.new(@machine, :idling)
394
469
  @state.context do
395
- def color
396
- 'green'
470
+ def speed
471
+ 0
397
472
  end
398
473
  end
399
474
 
@@ -401,7 +476,8 @@ class StateWithInvalidMethodCallTest < Test::Unit::TestCase
401
476
  end
402
477
 
403
478
  def test_should_raise_an_exception
404
- assert_raise(NoMethodError) { @state.call(@object, :invalid) }
479
+ exception = assert_raise(NoMethodError) { @state.call(@object, :invalid) }
480
+ assert_equal "undefined method 'invalid' for #{@object} in state nil", exception.message
405
481
  end
406
482
  end
407
483
 
@@ -410,9 +486,9 @@ class StateWithValidMethodCallTest < Test::Unit::TestCase
410
486
  @klass = Class.new
411
487
  @machine = StateMachine::Machine.new(@klass)
412
488
  @ancestors = @klass.ancestors
413
- @state = StateMachine::State.new(@machine, 'on')
489
+ @state = StateMachine::State.new(@machine, :idling)
414
490
  @state.context do
415
- def color(arg = nil)
491
+ def speed(arg = nil)
416
492
  block_given? ? [arg, yield] : arg
417
493
  end
418
494
  end
@@ -421,53 +497,19 @@ class StateWithValidMethodCallTest < Test::Unit::TestCase
421
497
  end
422
498
 
423
499
  def test_should_not_raise_an_exception
424
- assert_nothing_raised { @state.call(@object, :color) }
500
+ assert_nothing_raised { @state.call(@object, :speed) }
425
501
  end
426
502
 
427
503
  def test_should_pass_arguments_through
428
- assert_equal 1, @state.call(@object, :color, 1)
504
+ assert_equal 1, @state.call(@object, :speed, 1)
429
505
  end
430
506
 
431
507
  def test_should_pass_blocks_through
432
- assert_equal [nil, 1], @state.call(@object, :color) {1}
508
+ assert_equal [nil, 1], @state.call(@object, :speed) {1}
433
509
  end
434
510
 
435
511
  def test_should_pass_both_arguments_and_blocks_through
436
- assert_equal [1, 2], @state.call(@object, :color, 1) {2}
437
- end
438
- end
439
-
440
- class StateIdGeneratorTest < Test::Unit::TestCase
441
- def test_should_use_nil_for_nil
442
- assert_equal 'nil', StateMachine::State.id_for(nil)
443
- end
444
-
445
- def test_should_use_to_s_for_string
446
- assert_equal 'on', StateMachine::State.id_for('on')
447
- end
448
-
449
- def test_should_use_to_s_for_symbol
450
- assert_equal 'on', StateMachine::State.id_for(:on)
451
- end
452
-
453
- def test_should_use_to_s_for_number
454
- assert_equal '1', StateMachine::State.id_for(1)
455
- end
456
-
457
- def test_should_use_to_s_for_object
458
- class << (state = Object.new)
459
- def to_s
460
- 'on'
461
- end
462
- end
463
-
464
- assert_equal 'on', StateMachine::State.id_for(state)
465
- end
466
-
467
- def test_should_use_lambda_id_for_proc
468
- state = lambda {}
469
-
470
- assert_equal "lambda#{state.object_id.abs}", StateMachine::State.id_for(state)
512
+ assert_equal [1, 2], @state.call(@object, :speed, 1) {2}
471
513
  end
472
514
  end
473
515
 
@@ -479,7 +521,7 @@ begin
479
521
  class StateDrawingTest < Test::Unit::TestCase
480
522
  def setup
481
523
  @machine = StateMachine::Machine.new(Class.new)
482
- @state = StateMachine::State.new(@machine, 'on')
524
+ @state = StateMachine::State.new(@machine, :parked, :value => 1)
483
525
 
484
526
  graph = GraphViz.new('G')
485
527
  @node = @state.draw(graph)
@@ -501,19 +543,19 @@ begin
501
543
  assert_equal '1', @node['height']
502
544
  end
503
545
 
504
- def test_should_use_value_as_name
505
- assert_equal 'on', @node.name
546
+ def test_should_use_stringified_name_as_name
547
+ assert_equal 'parked', @node.name
506
548
  end
507
549
 
508
- def test_should_use_stringified_value_as_label
509
- assert_equal 'on', @node['label']
550
+ def test_should_use_description_as_label
551
+ assert_equal 'parked (1)', @node['label']
510
552
  end
511
553
  end
512
554
 
513
555
  class StateDrawingInitialTest < Test::Unit::TestCase
514
556
  def setup
515
557
  @machine = StateMachine::Machine.new(Class.new)
516
- @state = StateMachine::State.new(@machine, 'on', :initial => true)
558
+ @state = StateMachine::State.new(@machine, :parked, :initial => true)
517
559
 
518
560
  graph = GraphViz.new('G')
519
561
  @node = @state.draw(graph)
@@ -524,7 +566,7 @@ begin
524
566
  end
525
567
  end
526
568
 
527
- class StateDrawingNilTest < Test::Unit::TestCase
569
+ class StateDrawingNilNameTest < Test::Unit::TestCase
528
570
  def setup
529
571
  @machine = StateMachine::Machine.new(Class.new)
530
572
  @state = StateMachine::State.new(@machine, nil)
@@ -533,49 +575,30 @@ begin
533
575
  @node = @state.draw(graph)
534
576
  end
535
577
 
536
- def test_should_use_value_as_name
578
+ def test_should_use_stringified_nil_as_name
537
579
  assert_equal 'nil', @node.name
538
580
  end
539
581
 
540
- def test_should_use_stringified_value_as_label
582
+ def test_should_use_description_as_label
541
583
  assert_equal 'nil', @node['label']
542
584
  end
543
585
  end
544
586
 
545
- class StateDrawingProcTest < Test::Unit::TestCase
546
- def setup
547
- @machine = StateMachine::Machine.new(Class.new)
548
- @value = lambda {}
549
- @state = StateMachine::State.new(@machine, @value)
550
-
551
- graph = GraphViz.new('G')
552
- @node = @state.draw(graph)
553
- end
554
-
555
- def test_should_use_lambda_id_as_name
556
- assert_equal "lambda#{@value.object_id.abs}", @node.name
557
- end
558
-
559
- def test_should_use_asterisk_as_label
560
- assert_equal '*', @node['label']
561
- end
562
- end
563
-
564
- class StateDrawingSymbolTest < Test::Unit::TestCase
587
+ class StateDrawingLambdaValueTest < Test::Unit::TestCase
565
588
  def setup
566
589
  @machine = StateMachine::Machine.new(Class.new)
567
- @state = StateMachine::State.new(@machine, :on)
590
+ @state = StateMachine::State.new(@machine, :parked, :value => lambda {})
568
591
 
569
592
  graph = GraphViz.new('G')
570
593
  @node = @state.draw(graph)
571
594
  end
572
595
 
573
- def test_should_use_stringified_value_as_name
574
- assert_equal 'on', @node.name
596
+ def test_should_use_stringified_name_as_name
597
+ assert_equal 'parked', @node.name
575
598
  end
576
599
 
577
- def test_should_use_stringified_value_as_label
578
- assert_equal 'on', @node['label']
600
+ def test_should_use_description_as_label
601
+ assert_equal 'parked (*)', @node['label']
579
602
  end
580
603
  end
581
604
  rescue LoadError