ardm-is-state_machine 1.2.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.
- checksums.yaml +7 -0
- data/.gitignore +35 -0
- data/.travis.yml +11 -0
- data/Gemfile +65 -0
- data/LICENSE +20 -0
- data/README.rdoc +102 -0
- data/Rakefile +4 -0
- data/ardm-is-state_machine.gemspec +24 -0
- data/lib/ardm-is-state_machine.rb +1 -0
- data/lib/dm-is-state_machine.rb +10 -0
- data/lib/dm-is-state_machine/is/data/event.rb +25 -0
- data/lib/dm-is-state_machine/is/data/machine.rb +90 -0
- data/lib/dm-is-state_machine/is/data/state.rb +21 -0
- data/lib/dm-is-state_machine/is/dsl/event_dsl.rb +81 -0
- data/lib/dm-is-state_machine/is/dsl/state_dsl.rb +40 -0
- data/lib/dm-is-state_machine/is/state_machine.rb +139 -0
- data/lib/dm-is-state_machine/is/version.rb +7 -0
- data/spec/examples/invalid_events.rb +20 -0
- data/spec/examples/invalid_states.rb +20 -0
- data/spec/examples/invalid_transitions_1.rb +22 -0
- data/spec/examples/invalid_transitions_2.rb +22 -0
- data/spec/examples/light_switch.rb +25 -0
- data/spec/examples/slot_machine.rb +48 -0
- data/spec/examples/traffic_light.rb +48 -0
- data/spec/integration/inheritance_spec.rb +11 -0
- data/spec/integration/invalid_events_spec.rb +11 -0
- data/spec/integration/invalid_states_spec.rb +11 -0
- data/spec/integration/invalid_transitions_spec.rb +21 -0
- data/spec/integration/slot_machine_spec.rb +86 -0
- data/spec/integration/traffic_light_spec.rb +181 -0
- data/spec/rcov.opts +6 -0
- data/spec/spec.opts +4 -0
- data/spec/spec_helper.rb +11 -0
- data/spec/unit/data/event_spec.rb +27 -0
- data/spec/unit/data/machine_spec.rb +102 -0
- data/spec/unit/data/state_spec.rb +21 -0
- data/spec/unit/dsl/event_dsl_spec.rb +55 -0
- data/spec/unit/dsl/state_dsl_spec.rb +24 -0
- data/spec/unit/state_machine_spec.rb +28 -0
- data/tasks/spec.rake +38 -0
- data/tasks/yard.rake +9 -0
- data/tasks/yardstick.rake +19 -0
- metadata +132 -0
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'examples/slot_machine'
|
3
|
+
|
4
|
+
describe SlotMachine do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@sm = SlotMachine.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a 'mode' column" do
|
11
|
+
@sm.attributes.should have_key(:mode)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should have a 'power_on' column" do
|
15
|
+
@sm.attributes.should have_key(:power_on)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should not have a 'state' column" do
|
19
|
+
@sm.attributes.should_not have_key(:state)
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should start in the off state" do
|
23
|
+
@sm.mode.should == "off"
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should start with power_on == false" do
|
27
|
+
@sm.power_on.should == false
|
28
|
+
end
|
29
|
+
|
30
|
+
describe "in :off mode" do
|
31
|
+
|
32
|
+
before(:each) do
|
33
|
+
@sm.mode = :off
|
34
|
+
@sm.power_on = false
|
35
|
+
end
|
36
|
+
|
37
|
+
it "should allow the mode to be set" do
|
38
|
+
@sm.mode = :idle
|
39
|
+
@sm.save
|
40
|
+
@sm.mode.should == "idle"
|
41
|
+
end
|
42
|
+
|
43
|
+
it "turn_on! should work from off mode" do
|
44
|
+
@sm.turn_on!
|
45
|
+
@sm.mode.should == "idle"
|
46
|
+
@sm.power_on.should == true
|
47
|
+
end
|
48
|
+
|
49
|
+
it "turn_on! should not work twice in a row" do
|
50
|
+
@sm.turn_on!
|
51
|
+
lambda {
|
52
|
+
@sm.turn_on!
|
53
|
+
}.should raise_error(DataMapper::Is::StateMachine::InvalidEvent)
|
54
|
+
end
|
55
|
+
|
56
|
+
end
|
57
|
+
|
58
|
+
describe "in :idle mode" do
|
59
|
+
|
60
|
+
before(:each) do
|
61
|
+
@sm.mode = :idle
|
62
|
+
@sm.power_on = true
|
63
|
+
end
|
64
|
+
|
65
|
+
it "turn_on! should raise error" do
|
66
|
+
lambda {
|
67
|
+
@sm.turn_on!
|
68
|
+
}.should raise_error(DataMapper::Is::StateMachine::InvalidEvent)
|
69
|
+
end
|
70
|
+
|
71
|
+
it "turn_off! should work" do
|
72
|
+
@sm.turn_off!
|
73
|
+
@sm.mode.should == "off"
|
74
|
+
@sm.power_on.should == false
|
75
|
+
end
|
76
|
+
|
77
|
+
it "turn_off! should not work twice in a row" do
|
78
|
+
@sm.turn_off!
|
79
|
+
lambda {
|
80
|
+
@sm.turn_off!
|
81
|
+
}.should raise_error(DataMapper::Is::StateMachine::InvalidEvent)
|
82
|
+
end
|
83
|
+
|
84
|
+
end
|
85
|
+
|
86
|
+
end
|
@@ -0,0 +1,181 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'examples/traffic_light'
|
3
|
+
|
4
|
+
describe TrafficLight do
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@t = TrafficLight.new
|
8
|
+
end
|
9
|
+
|
10
|
+
it "should have a 'color' column" do
|
11
|
+
@t.attributes.should have_key(:color)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should not have a 'state' column" do
|
15
|
+
@t.attributes.should_not have_key(:state)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should start off in the green state" do
|
19
|
+
@t.color.should == "green"
|
20
|
+
end
|
21
|
+
|
22
|
+
it "should allow the color to be set" do
|
23
|
+
@t.color = :yellow
|
24
|
+
@t.save
|
25
|
+
@t.color.should == "yellow"
|
26
|
+
end
|
27
|
+
|
28
|
+
it "should have called the :enter Proc" do
|
29
|
+
@t.log.should == %w(G)
|
30
|
+
end
|
31
|
+
|
32
|
+
it "should call the original initialize method" do
|
33
|
+
@t.init.should == [:init]
|
34
|
+
end
|
35
|
+
|
36
|
+
describe 'forward!' do
|
37
|
+
|
38
|
+
it "should respond to :forward!" do
|
39
|
+
@t.respond_to?(:forward!).should == true
|
40
|
+
end
|
41
|
+
|
42
|
+
it "should transition to :yellow, :red, :green" do
|
43
|
+
@t.color.should == "green"
|
44
|
+
@t.forward!
|
45
|
+
@t.color.should == "yellow"
|
46
|
+
@t.log.should == %w(G Y)
|
47
|
+
@t.forward!
|
48
|
+
@t.color.should == "red"
|
49
|
+
@t.log.should == %w(G Y R)
|
50
|
+
@t.forward!
|
51
|
+
@t.color.should == "green"
|
52
|
+
@t.log.should == %w(G Y R G)
|
53
|
+
@t.should be_new
|
54
|
+
end
|
55
|
+
|
56
|
+
it "should skip to :yellow then transition to :red, :green, :yellow" do
|
57
|
+
@t.color = :yellow
|
58
|
+
@t.color.should == "yellow"
|
59
|
+
@t.log.should == %w(G)
|
60
|
+
@t.forward!
|
61
|
+
@t.color.should == "red"
|
62
|
+
@t.log.should == %w(G R)
|
63
|
+
@t.forward!
|
64
|
+
@t.color.should == "green"
|
65
|
+
@t.log.should == %w(G R G)
|
66
|
+
@t.forward!
|
67
|
+
@t.color.should == "yellow"
|
68
|
+
@t.log.should == %w(G R G Y)
|
69
|
+
@t.should be_new
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should skip to :red then transition to :green, :yellow, :red" do
|
73
|
+
@t.color = :red
|
74
|
+
@t.color.should == "red"
|
75
|
+
@t.log.should == %w(G)
|
76
|
+
@t.forward!
|
77
|
+
@t.color.should == "green"
|
78
|
+
@t.log.should == %w(G G)
|
79
|
+
@t.forward!
|
80
|
+
@t.color.should == "yellow"
|
81
|
+
@t.log.should == %w(G G Y)
|
82
|
+
@t.forward!
|
83
|
+
@t.color.should == "red"
|
84
|
+
@t.log.should == %w(G G Y R)
|
85
|
+
@t.should be_new
|
86
|
+
end
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
describe 'backward!' do
|
91
|
+
|
92
|
+
it "should respond to 'backward!'" do
|
93
|
+
@t.respond_to?(:backward!).should == true
|
94
|
+
end
|
95
|
+
|
96
|
+
it "should transition to :red, :yellow, :green" do
|
97
|
+
@t.color.should == "green"
|
98
|
+
@t.log.should == %w(G)
|
99
|
+
@t.backward!
|
100
|
+
@t.color.should == "red"
|
101
|
+
@t.log.should == %w(G R)
|
102
|
+
@t.backward!
|
103
|
+
@t.color.should == "yellow"
|
104
|
+
@t.log.should == %w(G R Y)
|
105
|
+
@t.backward!
|
106
|
+
@t.color.should == "green"
|
107
|
+
@t.log.should == %w(G R Y G)
|
108
|
+
@t.should be_new
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should skip to :yellow then transition to :green, :red, :yellow" do
|
112
|
+
@t.color = :yellow
|
113
|
+
@t.color.should == "yellow"
|
114
|
+
@t.log.should == %w(G)
|
115
|
+
@t.backward!
|
116
|
+
@t.color.should == "green"
|
117
|
+
@t.log.should == %w(G G)
|
118
|
+
@t.backward!
|
119
|
+
@t.color.should == "red"
|
120
|
+
@t.log.should == %w(G G R)
|
121
|
+
@t.backward!
|
122
|
+
@t.color.should == "yellow"
|
123
|
+
@t.log.should == %w(G G R Y)
|
124
|
+
@t.should be_new
|
125
|
+
end
|
126
|
+
|
127
|
+
it "should skip to :red then transition to :yellow, :green, :red" do
|
128
|
+
@t.color = :red
|
129
|
+
@t.color.should == "red"
|
130
|
+
@t.log.should == %w(G)
|
131
|
+
@t.backward!
|
132
|
+
@t.color.should == "yellow"
|
133
|
+
@t.log.should == %w(G Y)
|
134
|
+
@t.backward!
|
135
|
+
@t.color.should == "green"
|
136
|
+
@t.log.should == %w(G Y G)
|
137
|
+
@t.backward!
|
138
|
+
@t.color.should == "red"
|
139
|
+
@t.log.should == %w(G Y G R)
|
140
|
+
@t.should be_new
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
describe "hooks" do
|
146
|
+
|
147
|
+
it "should log initial state before state is changed on a before hook" do
|
148
|
+
@t.forward!
|
149
|
+
@t.before_hook_log.should == %w(green)
|
150
|
+
@t.forward!
|
151
|
+
@t.before_hook_log.should == %w(green yellow)
|
152
|
+
@t.forward!
|
153
|
+
@t.before_hook_log.should == %w(green yellow red)
|
154
|
+
end
|
155
|
+
|
156
|
+
it "should log final state before state is changed on a before hook" do
|
157
|
+
@t.forward!
|
158
|
+
@t.after_hook_log.should == %w(yellow)
|
159
|
+
@t.forward!
|
160
|
+
@t.after_hook_log.should == %w(yellow red)
|
161
|
+
@t.forward!
|
162
|
+
@t.after_hook_log.should == %w(yellow red green)
|
163
|
+
end
|
164
|
+
|
165
|
+
end
|
166
|
+
|
167
|
+
describe "overwriting event methods" do
|
168
|
+
|
169
|
+
before(:all) do
|
170
|
+
TrafficLight.class_eval "def forward!(added_param); log << added_param; transition!(:forward); end"
|
171
|
+
end
|
172
|
+
|
173
|
+
it "should transition normally with added functionality" do
|
174
|
+
@t.color.should == "green"
|
175
|
+
@t.forward!("test")
|
176
|
+
@t.color.should == "yellow"
|
177
|
+
@t.log.should == %w(G test Y)
|
178
|
+
end
|
179
|
+
|
180
|
+
end
|
181
|
+
end
|
data/spec/rcov.opts
ADDED
data/spec/spec.opts
ADDED
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
require 'dm-core/spec/setup'
|
2
|
+
require 'dm-core/spec/lib/adapter_helpers'
|
3
|
+
|
4
|
+
require 'dm-is-state_machine'
|
5
|
+
require 'dm-migrations'
|
6
|
+
|
7
|
+
DataMapper::Spec.setup
|
8
|
+
|
9
|
+
Spec::Runner.configure do |config|
|
10
|
+
config.extend(DataMapper::Spec::Adapters::Helpers)
|
11
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module EventHelper
|
4
|
+
def new_event(*args)
|
5
|
+
DataMapper::Is::StateMachine::Data::Event.new(*args)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe DataMapper::Is::StateMachine::Data::Event do
|
10
|
+
include EventHelper
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
@machine = mock("machine")
|
14
|
+
@event = new_event(:ping, @machine)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#initialize should work" do
|
18
|
+
@event.name.should == :ping
|
19
|
+
@event.machine.should == @machine
|
20
|
+
@event.transitions.should == []
|
21
|
+
end
|
22
|
+
|
23
|
+
it "#add_transition should work" do
|
24
|
+
@event.add_transition(:nothing, :pinged)
|
25
|
+
@event.transitions.should == [{:from => :nothing, :to => :pinged }]
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module MachineHelper
|
4
|
+
def new_machine(*args)
|
5
|
+
DataMapper::Is::StateMachine::Data::Machine.new(*args)
|
6
|
+
end
|
7
|
+
|
8
|
+
def new_state(name, machine, options = {})
|
9
|
+
mock(name, :name => name, :machine => machine, :options => options)
|
10
|
+
end
|
11
|
+
|
12
|
+
def new_event(name, machine)
|
13
|
+
mock(name, :name => name, :machine => machine)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
describe DataMapper::Is::StateMachine::Data::Machine do
|
18
|
+
include MachineHelper
|
19
|
+
|
20
|
+
describe "new Machine, no events" do
|
21
|
+
before(:each) do
|
22
|
+
@machine = new_machine(:power, :off)
|
23
|
+
end
|
24
|
+
|
25
|
+
it "#column should work" do
|
26
|
+
@machine.column.should == :power
|
27
|
+
end
|
28
|
+
|
29
|
+
it "#initial should work" do
|
30
|
+
@machine.initial.should == :off
|
31
|
+
end
|
32
|
+
|
33
|
+
it "#events should work" do
|
34
|
+
@machine.events.should == []
|
35
|
+
end
|
36
|
+
|
37
|
+
it "#states should work" do
|
38
|
+
@machine.states.should == []
|
39
|
+
end
|
40
|
+
|
41
|
+
it "#find_event should return nothing" do
|
42
|
+
@machine.find_event(:turn_on).should == nil
|
43
|
+
end
|
44
|
+
|
45
|
+
it "#fire_event should raise error" do
|
46
|
+
lambda {
|
47
|
+
@machine.fire_event(:turn_on, nil)
|
48
|
+
}.should raise_error(DataMapper::Is::StateMachine::InvalidEvent)
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
describe "new Machine, 2 states, 1 event" do
|
53
|
+
before(:each) do
|
54
|
+
@machine = new_machine(:power, :off)
|
55
|
+
@machine.states << (@off_state = new_state(:off, @machine))
|
56
|
+
@machine.states << (@on_state = new_state(:on, @machine))
|
57
|
+
@machine.events << (@turn_on = new_event(:turn_on, @machine))
|
58
|
+
@turn_on.stub!(:transitions).and_return([{ :from => :off, :to => :on }])
|
59
|
+
end
|
60
|
+
|
61
|
+
it "#column should work" do
|
62
|
+
@machine.column.should == :power
|
63
|
+
end
|
64
|
+
|
65
|
+
it "#initial should work" do
|
66
|
+
@machine.initial.should == :off
|
67
|
+
end
|
68
|
+
|
69
|
+
it "#events should work" do
|
70
|
+
@machine.events.should == [@turn_on]
|
71
|
+
end
|
72
|
+
|
73
|
+
it "#states should work" do
|
74
|
+
@machine.states.should == [@off_state, @on_state]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "#current_state should work" do
|
78
|
+
@machine.current_state.should == @off_state
|
79
|
+
end
|
80
|
+
|
81
|
+
it "#current_state_name should work" do
|
82
|
+
@machine.current_state_name.should == :off
|
83
|
+
end
|
84
|
+
|
85
|
+
it "#find_event should return nothing" do
|
86
|
+
@machine.find_event(:turn_on).should == @turn_on
|
87
|
+
end
|
88
|
+
|
89
|
+
it "#fire_event should change state" do
|
90
|
+
resource = mock("resource")
|
91
|
+
resource.should_receive(:run_hook_if_present).exactly(2).times.with(nil)
|
92
|
+
@machine.fire_event(:turn_on, resource)
|
93
|
+
@machine.current_state.should == @on_state
|
94
|
+
@machine.current_state_name.should == :on
|
95
|
+
end
|
96
|
+
|
97
|
+
end
|
98
|
+
|
99
|
+
# TODO: spec fire_event where :run_hook_if_present fires two times,
|
100
|
+
# but with :enter the first and :exit the second.
|
101
|
+
|
102
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module StateHelper
|
4
|
+
def new_state(*args)
|
5
|
+
DataMapper::Is::StateMachine::Data::State.new(*args)
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
describe DataMapper::Is::StateMachine::Data::State do
|
10
|
+
include StateHelper
|
11
|
+
|
12
|
+
before(:each) do
|
13
|
+
@machine = mock("machine")
|
14
|
+
@state = new_state(:off, @machine)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "#initialize should work" do
|
18
|
+
@state.name.should == :off
|
19
|
+
@state.machine.should == @machine
|
20
|
+
end
|
21
|
+
end
|