edge-state-machine 0.0.3 → 0.9.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.rdoc +128 -4
- data/edge-state-machine.gemspec +2 -2
- data/lib/edge-state-machine/version.rb +1 -1
- data/spec/active_record/active_record_helper.rb +2 -0
- data/spec/active_record/active_record_spec.rb +66 -64
- data/spec/active_record/double_machine_spec.rb +75 -0
- data/spec/active_record/migrations/create_double_machine.rb +8 -0
- data/spec/active_record/samples/double_machine.rb +59 -0
- data/spec/active_record/samples/traffic_light.rb +29 -0
- data/spec/event_spec.rb +6 -6
- data/spec/machine_spec.rb +2 -2
- data/spec/mongoid/double_machine_spec.rb +72 -0
- data/spec/mongoid/mongoid_helper.rb +1 -0
- data/spec/mongoid/mongoid_spec.rb +64 -62
- data/spec/mongoid/samples/double_machine.rb +61 -0
- data/spec/mongoid/samples/traffic_light.rb +31 -0
- data/spec/non_persistent/double_machine_spec.rb +44 -0
- data/spec/non_persistent/non_persistent_helper.rb +2 -0
- data/spec/non_persistent/non_persistent_spec.rb +41 -41
- data/spec/non_persistent/on_off_switch_spec.rb +51 -0
- data/spec/non_persistent/samples/double_machine.rb +48 -0
- data/spec/non_persistent/samples/microwave.rb +1 -0
- data/spec/non_persistent/samples/on_off_switch.rb +62 -0
- data/spec/state_spec.rb +11 -11
- data/spec/transition_spec.rb +25 -25
- metadata +27 -17
data/README.rdoc
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
= Edge State Machine
|
2
2
|
|
3
|
-
Edge
|
4
|
-
It offers support for ActiveRecord and Mongoid
|
3
|
+
Edge State Machine is a complete state machine solution.
|
4
|
+
It offers support for ActiveRecord and Mongoid for persistence.
|
5
5
|
|
6
6
|
{<img src="https://secure.travis-ci.org/danpersa/edge-state-machine.png"/>}[http://travis-ci.org/danpersa/edge-state-machine]
|
7
7
|
|
8
|
+
== Supported Features
|
9
|
+
|
10
|
+
* Multiple state machines per class each of them acting independently
|
11
|
+
* Find errors in state machine definitions as early as possible
|
12
|
+
* Transition guards
|
13
|
+
* Multiple actions executed on transitions
|
14
|
+
* Multiple actions executed on entering and exiting a state
|
15
|
+
* No other dependencies for non-persistent state machines
|
16
|
+
* Minimal dependencies for persistent ones
|
17
|
+
|
8
18
|
== Installation
|
9
19
|
|
10
20
|
If you're using Rails + ActiveRecord + Bundler
|
@@ -57,10 +67,124 @@ If you're using Rails + Mongoid + Bundler
|
|
57
67
|
end
|
58
68
|
end
|
59
69
|
|
60
|
-
|
70
|
+
== State Machine Examples
|
71
|
+
|
72
|
+
=== Microwave State Machine
|
73
|
+
|
74
|
+
class Microwave
|
75
|
+
state_machine :microwave do # name should be optional, if the name is not present, it should have a default name
|
76
|
+
# we give state machines names, so we can pun many machines inside a class
|
77
|
+
initial_state :unplugged # initial state should be optional, if the initial state is not present, the initial state will be the first defined state
|
78
|
+
|
79
|
+
state :unplugged
|
80
|
+
|
81
|
+
state :plugged
|
82
|
+
|
83
|
+
state :door_opened do
|
84
|
+
enter :light_on # enter should be executed on entering the state
|
85
|
+
exit :light_off # exit method should be executed on exiting the state
|
86
|
+
end
|
87
|
+
|
88
|
+
state :door_closed
|
89
|
+
|
90
|
+
state :started_in_grill_mode do
|
91
|
+
enter lambda { |t| p "Entering hate" } # should have support for Procs
|
92
|
+
exit :grill_off
|
93
|
+
end
|
94
|
+
|
95
|
+
state :started do
|
96
|
+
enter :microwaves_on
|
97
|
+
exit :microwaves_off
|
98
|
+
end
|
99
|
+
|
100
|
+
event :plug_in do
|
101
|
+
transition :from => :unplugged, :to => :plugged
|
102
|
+
end
|
103
|
+
|
104
|
+
event :open_door do
|
105
|
+
transition :from => :plugged, :to => :door_opened
|
106
|
+
end
|
107
|
+
|
108
|
+
event :close_door do
|
109
|
+
transition :from => :door_opened, :to => :door_closed,
|
110
|
+
:on_transition => :put_food_in_the_microwave # we can put many actions in an Array for the on_transition parameter
|
111
|
+
end
|
112
|
+
|
113
|
+
event :start do
|
114
|
+
transition :from => :door_closed, :to => [:started, :started_in_grill_mode],
|
115
|
+
:on_transition => :start_spinning_the_food,
|
116
|
+
:guard => :grill_button_pressed? # the method grill_button_pressed? should choose the next state
|
117
|
+
end
|
118
|
+
|
119
|
+
event :stop do
|
120
|
+
transition :from => [:started, :started_in_grill_mode], :to => :door_closed
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
=== Dice State Machine
|
126
|
+
|
127
|
+
class Dice
|
128
|
+
|
129
|
+
state_machine do
|
130
|
+
state :one
|
131
|
+
state :two
|
132
|
+
state :three
|
133
|
+
state :four
|
134
|
+
state :five
|
135
|
+
state :six
|
136
|
+
|
137
|
+
event :roll do
|
138
|
+
transition :from => [:one, :two, :three, :four, :five, :six],
|
139
|
+
:to => [:one, :two, :three, :four, :five, :six],
|
140
|
+
:guard => :roll_result,
|
141
|
+
:on_transition => :display_dice_rolling_animation
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def roll_result
|
146
|
+
# return one of the states
|
147
|
+
end
|
148
|
+
|
149
|
+
def display_dice_rolling_animation
|
150
|
+
# draw the new position of the dice
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
class User
|
155
|
+
state_machine do
|
156
|
+
state :pending # first one is initial state
|
157
|
+
state :active
|
158
|
+
state :blocked # the user in this state can't sign in
|
159
|
+
|
160
|
+
event :activate do
|
161
|
+
transition :from => [:pending], :to => :active, :on_transition => :do_activate
|
162
|
+
end
|
163
|
+
|
164
|
+
event :block do
|
165
|
+
transition :from => [:pending, :active], :to => :blocked
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
=== Other Examples
|
171
|
+
|
172
|
+
For other (more complex) examples, please check the following links:
|
173
|
+
|
174
|
+
* {Examples without Persistence}[https://github.com/danpersa/edge-state-machine/tree/master/spec/non_persistent/samples]
|
175
|
+
* {Examples with ActiveRecord}[https://github.com/danpersa/edge-state-machine/tree/master/spec/active_record/samples]
|
176
|
+
* {Examples with Mongoid}[https://github.com/danpersa/edge-state-machine/tree/master/spec/mongoid/samples]
|
177
|
+
|
178
|
+
== Notes
|
179
|
+
|
180
|
+
For classes with multiple state machines, the state names, machine names must be unique per class.
|
181
|
+
|
182
|
+
The same thing with the event names.
|
183
|
+
|
184
|
+
== Credits
|
61
185
|
|
62
186
|
The gem is based on Rick Olson's code of ActiveModel::StateMachine,
|
63
187
|
axed from ActiveModel in {this
|
64
188
|
commit}[http://github.com/rails/rails/commit/db49c706b62e7ea2ab93f05399dbfddf5087ee0c].
|
65
189
|
|
66
|
-
And on Krzysiek Heród's gem, {Transitions}[https://github.com/netizer/transitions], which added Mongoid support.
|
190
|
+
And on Krzysiek Heród's gem, {Transitions}[https://github.com/netizer/transitions], which added Mongoid support.
|
data/edge-state-machine.gemspec
CHANGED
@@ -8,8 +8,8 @@ Gem::Specification.new do |s|
|
|
8
8
|
s.authors = ["Dan Persa"]
|
9
9
|
s.email = ["dan.persa@gmail.com"]
|
10
10
|
s.homepage = "http://github.com/danpersa/edge-state-machine"
|
11
|
-
s.summary = %q{State
|
12
|
-
s.description = %q{
|
11
|
+
s.summary = %q{Edge State Machine}
|
12
|
+
s.description = %q{Edge State Machine is a complete state machine solution. It offers support for ActiveRecord and Mongoid for persistence.}
|
13
13
|
|
14
14
|
s.rubyforge_project = "edge-state-machine"
|
15
15
|
|
@@ -3,8 +3,10 @@ require 'active_record'
|
|
3
3
|
require 'active_support/core_ext/module/aliasing'
|
4
4
|
require 'active_record/migrations/create_orders'
|
5
5
|
require 'active_record/migrations/create_traffic_lights'
|
6
|
+
require 'active_record/migrations/create_double_machine'
|
6
7
|
require 'active_record/samples/traffic_light'
|
7
8
|
require 'active_record/samples/order'
|
9
|
+
require 'active_record/samples/double_machine'
|
8
10
|
|
9
11
|
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), "..", 'lib'))
|
10
12
|
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
@@ -1,127 +1,129 @@
|
|
1
1
|
require 'active_record/active_record_helper'
|
2
2
|
|
3
|
-
describe
|
3
|
+
describe 'active record state machine' do
|
4
4
|
|
5
|
-
context
|
5
|
+
context 'existing active record' do
|
6
6
|
before do
|
7
|
-
ActiveRecord::Base.establish_connection(:adapter =>
|
7
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
8
8
|
ActiveRecord::Migration.verbose = false
|
9
9
|
CreateTrafficLights.migrate(:up)
|
10
|
-
@light = TrafficLight.create!
|
11
10
|
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
@light.current_state.should == :off
|
12
|
+
let :light do
|
13
|
+
TrafficLight.create!
|
16
14
|
end
|
17
15
|
|
18
|
-
it
|
19
|
-
|
20
|
-
|
21
|
-
|
16
|
+
it 'should have an initial state' do
|
17
|
+
light.off?.should == true
|
18
|
+
light.current_state.should == :off
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'should go to a valid state on transition' do
|
22
|
+
light.reset
|
23
|
+
light.red?.should == true
|
24
|
+
light.current_state.should == :red
|
22
25
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
+
light.green_on
|
27
|
+
light.green?.should == true
|
28
|
+
light.current_state.should == :green
|
26
29
|
end
|
27
30
|
|
28
|
-
it
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
31
|
+
it 'should not persist state on transition' do
|
32
|
+
light.reset
|
33
|
+
light.current_state.should == :red
|
34
|
+
light.reload
|
35
|
+
light.state.should == 'off'
|
33
36
|
end
|
34
37
|
|
35
|
-
it
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
38
|
+
it 'should persists state on transition' do
|
39
|
+
light.reset!
|
40
|
+
light.current_state.should == :red
|
41
|
+
light.reload
|
42
|
+
light.state.should == 'red'
|
40
43
|
end
|
41
44
|
|
42
|
-
it
|
43
|
-
|
44
|
-
loaded_light = TrafficLight.find_by_id(
|
45
|
+
it 'should initialize the current state when loaded from database' do
|
46
|
+
light.reset!
|
47
|
+
loaded_light = TrafficLight.find_by_id(light.id)
|
45
48
|
loaded_light.current_state.should == :red
|
46
49
|
end
|
47
50
|
|
48
|
-
it
|
49
|
-
expect {
|
50
|
-
|
51
|
+
it 'should raise error on transition to an invalid state' do
|
52
|
+
expect { light.yellow_on }.should raise_error EdgeStateMachine::NoTransitionFound
|
53
|
+
light.current_state.should == :off
|
51
54
|
end
|
52
55
|
|
53
|
-
it
|
56
|
+
it 'should persist state when state is protected on transition' do
|
54
57
|
protected_light = ProtectedTrafficLight.create!
|
55
58
|
protected_light.reset!
|
56
59
|
protected_light.current_state.should == :red
|
57
60
|
protected_light.reload
|
58
|
-
protected_light.state.should ==
|
61
|
+
protected_light.state.should == 'red'
|
59
62
|
end
|
60
63
|
|
61
|
-
it
|
62
|
-
for s in
|
63
|
-
|
64
|
-
|
64
|
+
it 'should not validate when try transition with wrong state' do
|
65
|
+
for s in light.class.state_machines[:default].states.keys
|
66
|
+
light.state = s
|
67
|
+
light.valid?.should == true
|
65
68
|
end
|
66
|
-
|
67
|
-
|
69
|
+
light.state = 'invalid_one'
|
70
|
+
light.valid?.should_not == true
|
68
71
|
end
|
69
72
|
|
70
|
-
it
|
73
|
+
it 'should raise exception when model validation fails on transition' do
|
71
74
|
validating_light = ValidatingTrafficLight.create!
|
72
75
|
expect {validating_light.reset!}.should raise_error ActiveRecord::RecordInvalid
|
73
76
|
validating_light.red?.should == false
|
74
77
|
validating_light.off?.should == true
|
75
78
|
end
|
76
79
|
|
77
|
-
it
|
80
|
+
it 'should state query method used in a validation condition' do
|
78
81
|
validating_light = ConditionalValidatingTrafficLight.create!
|
79
82
|
#expect {validating_light.reset!}.should raise_error ActiveRecord::RecordInvalid
|
80
83
|
validating_light.off?.should == true
|
81
84
|
validating_light.red?.should == false
|
82
85
|
end
|
83
86
|
|
84
|
-
it
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
87
|
+
it 'should reload the model when current state resets' do
|
88
|
+
light.reset
|
89
|
+
light.red?.should == true
|
90
|
+
light.update_attribute(:state, 'green')
|
91
|
+
light.reload.green?.should == true # reloaded state should come from database
|
89
92
|
end
|
90
93
|
|
91
|
-
describe
|
92
|
-
it
|
94
|
+
describe 'scopes' do
|
95
|
+
it 'should be added for each state' do
|
93
96
|
TrafficLight.should respond_to(:off)
|
94
97
|
TrafficLight.should respond_to(:red)
|
95
98
|
end
|
96
99
|
|
97
|
-
it
|
98
|
-
|
99
|
-
|
100
|
+
it 'should not be added for each state' do
|
101
|
+
TrafficLightNoScope.should_not respond_to(:off)
|
102
|
+
TrafficLightNoScope.should_not respond_to(:red)
|
100
103
|
end
|
101
104
|
|
102
|
-
it
|
103
|
-
3.times { TrafficLight.create(:state =>
|
104
|
-
3.times { TrafficLight.create(:state =>
|
105
|
-
|
106
|
-
TrafficLight.off.count.should == 4
|
105
|
+
it 'should behave like scopes' do
|
106
|
+
3.times { TrafficLight.create(:state => 'off') }
|
107
|
+
3.times { TrafficLight.create(:state => 'red') }
|
108
|
+
TrafficLight.off.count.should == 3
|
107
109
|
TrafficLight.red.count.should == 3
|
108
110
|
end
|
109
111
|
end
|
110
112
|
end
|
111
113
|
|
112
|
-
context
|
113
|
-
|
114
|
-
|
114
|
+
context 'new active record' do
|
115
|
+
let :light do
|
116
|
+
TrafficLight.new
|
115
117
|
end
|
116
118
|
|
117
|
-
it
|
118
|
-
|
119
|
+
it 'should have the initial state set' do
|
120
|
+
light.current_state.should == :off
|
119
121
|
end
|
120
122
|
end
|
121
123
|
|
122
|
-
context
|
124
|
+
context 'timestamp' do
|
123
125
|
before do
|
124
|
-
ActiveRecord::Base.establish_connection(:adapter =>
|
126
|
+
ActiveRecord::Base.establish_connection(:adapter => 'sqlite3', :database => ':memory:')
|
125
127
|
ActiveRecord::Migration.verbose = false
|
126
128
|
CreateOrders.migrate(:up)
|
127
129
|
end
|
@@ -131,10 +133,10 @@ describe "active record state machine" do
|
|
131
133
|
end
|
132
134
|
|
133
135
|
# control case, no timestamp has been set so we should expect default behaviour
|
134
|
-
it
|
136
|
+
it 'should not raise any exceptions when moving to placed' do
|
135
137
|
@order = create_order
|
136
138
|
expect { @order.place! }.should_not raise_error
|
137
|
-
@order.state.should ==
|
139
|
+
@order.state.should == 'placed'
|
138
140
|
end
|
139
141
|
end
|
140
142
|
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'active_record/active_record_helper'
|
2
|
+
|
3
|
+
describe DoubleMachineActiveRecord do
|
4
|
+
|
5
|
+
before do
|
6
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
7
|
+
ActiveRecord::Migration.verbose = false
|
8
|
+
CreateDoubleMachine.migrate(:up)
|
9
|
+
end
|
10
|
+
|
11
|
+
let :double_machine do
|
12
|
+
DoubleMachineActiveRecord.create!
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'should have a current state equals with the initial state for each machine' do
|
16
|
+
double_machine.current_state.should == :first_state
|
17
|
+
double_machine.current_state(:second).should == :red
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'should have the corresponding methods for verifying the states' do
|
21
|
+
double_machine.first_state?.should == true
|
22
|
+
double_machine.second_state?.should == false
|
23
|
+
double_machine.red?.should == true
|
24
|
+
double_machine.green?.should == false
|
25
|
+
end
|
26
|
+
|
27
|
+
it 'should trigger events from the state machines' do
|
28
|
+
double_machine.first_move
|
29
|
+
double_machine.current_state.should == :second_state
|
30
|
+
double_machine.second_state?.should == true
|
31
|
+
|
32
|
+
double_machine.go_green
|
33
|
+
double_machine.current_state(:second).should == :green
|
34
|
+
double_machine.green?.should == true
|
35
|
+
|
36
|
+
double_machine.second_move
|
37
|
+
double_machine.current_state.should == :third_state
|
38
|
+
double_machine.third_state?.should == true
|
39
|
+
end
|
40
|
+
|
41
|
+
it 'should execute the on_transition method' do
|
42
|
+
double_machine.should_receive :do_move
|
43
|
+
double_machine.first_move
|
44
|
+
double_machine.go_green
|
45
|
+
|
46
|
+
double_machine.should_receive :turn_off
|
47
|
+
double_machine.should_receive :color_in_red
|
48
|
+
double_machine.go_red
|
49
|
+
end
|
50
|
+
|
51
|
+
context 'persistence ' do
|
52
|
+
it 'should create scopes for each state machine' do
|
53
|
+
3.times { DoubleMachineActiveRecord.create(:state => 'second_state', :second_state => 'blue') }
|
54
|
+
3.times { DoubleMachineActiveRecord.create(:state => 'first_state', :second_state => 'blue') }
|
55
|
+
DoubleMachineActiveRecord.first_state.count.should == 3
|
56
|
+
DoubleMachineActiveRecord.second_state.count.should == 3
|
57
|
+
DoubleMachineActiveRecord.blue.count.should == 6
|
58
|
+
end
|
59
|
+
|
60
|
+
it 'should save the state machines in the database' do
|
61
|
+
machine = DoubleMachineActiveRecord.create(:state => 'second_state', :second_state => 'blue')
|
62
|
+
machine.go_red!
|
63
|
+
machine.current_state(:second).should == :red
|
64
|
+
machine.red?.should == true
|
65
|
+
|
66
|
+
machine.second_move!
|
67
|
+
machine.third_state?.should == true
|
68
|
+
machine.current_state.should == :third_state
|
69
|
+
|
70
|
+
loaded_machine = DoubleMachineActiveRecord.find_by_id(machine.id)
|
71
|
+
loaded_machine.third_state?.should == true
|
72
|
+
loaded_machine.current_state.should == :third_state
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
require 'active_record/edge-state-machine'
|
3
|
+
|
4
|
+
ActiveRecord::Base.establish_connection(:adapter => "sqlite3", :database => ":memory:")
|
5
|
+
|
6
|
+
class DoubleMachineActiveRecord < ActiveRecord::Base
|
7
|
+
include ActiveRecord::EdgeStateMachine
|
8
|
+
|
9
|
+
state_machine do
|
10
|
+
# the machine is automatically named :default
|
11
|
+
# the scopes are not created by default
|
12
|
+
create_scopes true
|
13
|
+
# the persistence instance variable is the default one (:state)
|
14
|
+
state :first_state # first one is initial state
|
15
|
+
state :second_state
|
16
|
+
state :third_state # the user in this state can't sign in
|
17
|
+
|
18
|
+
event :first_move do
|
19
|
+
transition :from => :first_state, :to => :second_state, :on_transition => :do_move
|
20
|
+
end
|
21
|
+
|
22
|
+
event :second_move do
|
23
|
+
transition :from => :second_state, :to => :third_state
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
state_machine :second do
|
28
|
+
# the scopes are not created by default
|
29
|
+
create_scopes true
|
30
|
+
# for the second machine we must specify the name of the persistence instance variable
|
31
|
+
# so there are no conflicts between the state machines
|
32
|
+
persisted_to :second_state
|
33
|
+
initial_state :red
|
34
|
+
state :blue
|
35
|
+
state :green
|
36
|
+
state :red
|
37
|
+
|
38
|
+
event :go_blue do
|
39
|
+
transition :from => [:red, :green], :to => :blue
|
40
|
+
end
|
41
|
+
|
42
|
+
event :go_red do
|
43
|
+
transition :from => [:blue, :green], :to => :red, :on_transition => [:turn_off, :color_in_red]
|
44
|
+
end
|
45
|
+
|
46
|
+
event :go_green do
|
47
|
+
transition :from => [:blue, :red], :to => :green
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
def do_move
|
52
|
+
end
|
53
|
+
|
54
|
+
def turn_off
|
55
|
+
end
|
56
|
+
|
57
|
+
def color_in_red
|
58
|
+
end
|
59
|
+
end
|
@@ -43,4 +43,33 @@ end
|
|
43
43
|
|
44
44
|
class ConditionalValidatingTrafficLight < TrafficLight
|
45
45
|
validate :name, :presence => true, :length => { :within => 20..40 }, :confirmation => true, :if => :red?
|
46
|
+
end
|
47
|
+
|
48
|
+
class TrafficLightNoScope < ActiveRecord::Base
|
49
|
+
include ActiveRecord::EdgeStateMachine
|
50
|
+
|
51
|
+
state_machine do
|
52
|
+
persisted_to :state
|
53
|
+
state :off
|
54
|
+
|
55
|
+
state :red
|
56
|
+
state :green
|
57
|
+
state :yellow
|
58
|
+
|
59
|
+
event :red_on do
|
60
|
+
transition :to => :red, :from => [:yellow]
|
61
|
+
end
|
62
|
+
|
63
|
+
event :green_on do
|
64
|
+
transition :to => :green, :from => [:red]
|
65
|
+
end
|
66
|
+
|
67
|
+
event :yellow_on do
|
68
|
+
transition :to => :yellow, :from => [:green]
|
69
|
+
end
|
70
|
+
|
71
|
+
event :reset do
|
72
|
+
transition :to => :red, :from => [:off]
|
73
|
+
end
|
74
|
+
end
|
46
75
|
end
|
data/spec/event_spec.rb
CHANGED
@@ -34,17 +34,17 @@ describe EdgeStateMachine::Event do
|
|
34
34
|
end
|
35
35
|
end
|
36
36
|
|
37
|
-
it
|
37
|
+
it 'should set the name' do
|
38
38
|
@state_name.should == @event.name
|
39
39
|
end
|
40
40
|
|
41
|
-
it
|
41
|
+
it 'should create Transitions' do
|
42
42
|
EdgeStateMachine::Transition.should_receive(:new).with(:to => :closed, :from => [:open, :received])
|
43
43
|
new_event
|
44
44
|
end
|
45
45
|
|
46
|
-
describe
|
47
|
-
it
|
46
|
+
describe 'event arguments' do
|
47
|
+
it 'should pass arguments to transition method' do
|
48
48
|
subject = ArgumentsTestSubject.new
|
49
49
|
subject.current_state.should == :initial
|
50
50
|
subject.open!
|
@@ -52,13 +52,13 @@ describe EdgeStateMachine::Event do
|
|
52
52
|
end
|
53
53
|
end
|
54
54
|
|
55
|
-
describe
|
55
|
+
describe 'events being fired' do
|
56
56
|
before do
|
57
57
|
@machine = mock
|
58
58
|
@machine.stub!(:name).and_return(:default)
|
59
59
|
end
|
60
60
|
|
61
|
-
it
|
61
|
+
it 'should raise an EdgeStateMachine::NoTransitionFound error if the transitions are empty' do
|
62
62
|
event = EdgeStateMachine::Event.new(:event, @machine)
|
63
63
|
obj = mock
|
64
64
|
obj.stub!(:current_state).and_return(:open)
|
data/spec/machine_spec.rb
CHANGED
@@ -31,11 +31,11 @@ describe EdgeStateMachine::Machine do
|
|
31
31
|
MachineTestSubject.state_machines.size.should == 2
|
32
32
|
end
|
33
33
|
|
34
|
-
it
|
34
|
+
it 'should set #initial_state_name from initial_state method' do
|
35
35
|
MachineTestSubject.state_machines[:extra].initial_state_name.should == :bar
|
36
36
|
end
|
37
37
|
|
38
|
-
it
|
38
|
+
it 'should access non-default state machine' do
|
39
39
|
MachineTestSubject.state_machines[:extra].class.should == EdgeStateMachine::Machine
|
40
40
|
end
|
41
41
|
end
|