simple_state_machine 0.6.1 → 0.6.2
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 +4 -4
- data/Changelog.rdoc +7 -0
- data/lib/simple_state_machine/version.rb +1 -1
- metadata +2 -41
- data/.github/workflows/build.yml +0 -46
- data/.gitignore +0 -4
- data/.rspec +0 -3
- data/.travis.yml +0 -17
- data/Gemfile +0 -11
- data/Rakefile +0 -28
- data/examples/conversation.rb +0 -33
- data/examples/lamp.rb +0 -21
- data/examples/relationship.rb +0 -87
- data/examples/traffic_light.rb +0 -17
- data/examples/user.rb +0 -41
- data/gemfiles/Gemfile.activerecord-5.2.x +0 -9
- data/gemfiles/Gemfile.activerecord-6.0.x +0 -9
- data/gemfiles/Gemfile.activerecord-6.1.x +0 -8
- data/gemfiles/Gemfile.activerecord-main.x +0 -9
- data/gemfiles/Gemfile.basic +0 -6
- data/lib/simple_state_machine/.DS_Store +0 -0
- data/simple_state_machine.gemspec +0 -21
- data/spec/.DS_Store +0 -0
- data/spec/active_record_spec.rb +0 -250
- data/spec/decorator/default_spec.rb +0 -195
- data/spec/examples_spec.rb +0 -60
- data/spec/mountable_spec.rb +0 -36
- data/spec/simple_state_machine_spec.rb +0 -165
- data/spec/spec_helper.rb +0 -20
- data/spec/state_machine_definition_spec.rb +0 -103
- data/spec/state_machine_spec.rb +0 -60
- data/spec/tools/graphviz_spec.rb +0 -30
- data/spec/tools/inspector_spec.rb +0 -70
data/spec/active_record_spec.rb
DELETED
@@ -1,250 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
require 'logger'
|
3
|
-
|
4
|
-
if defined? ActiveRecord
|
5
|
-
ActiveRecord::Base.logger = Logger.new "test.log"
|
6
|
-
ActiveRecord::Base.establish_connection('adapter' => RUBY_PLATFORM == 'java' ? 'jdbcsqlite3' : 'sqlite3', 'database' => ':memory:')
|
7
|
-
|
8
|
-
def setup_db
|
9
|
-
ActiveRecord::Schema.define(:version => 1) do
|
10
|
-
create_table :users do |t|
|
11
|
-
t.column :name, :string
|
12
|
-
t.column :state, :string
|
13
|
-
t.column :activation_code, :string
|
14
|
-
t.column :created_at, :datetime
|
15
|
-
t.column :updated_at, :datetime
|
16
|
-
end
|
17
|
-
create_table :tickets do |t|
|
18
|
-
t.column :ssm_state, :string
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
def teardown_db
|
24
|
-
ActiveRecord::Base.connection.tables.each do |table|
|
25
|
-
ActiveRecord::Base.connection.drop_table(table)
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
class Ticket < ActiveRecord::Base
|
30
|
-
extend SimpleStateMachine::ActiveRecord
|
31
|
-
|
32
|
-
state_machine_definition.state_method = :ssm_state
|
33
|
-
|
34
|
-
after_initialize :after_initialize
|
35
|
-
def after_initialize
|
36
|
-
self.ssm_state ||= 'open'
|
37
|
-
end
|
38
|
-
|
39
|
-
event :close, :open => :closed
|
40
|
-
end
|
41
|
-
|
42
|
-
describe ActiveRecord do
|
43
|
-
|
44
|
-
before do
|
45
|
-
setup_db
|
46
|
-
end
|
47
|
-
|
48
|
-
after do
|
49
|
-
teardown_db
|
50
|
-
end
|
51
|
-
|
52
|
-
it "has a default state" do
|
53
|
-
expect(User.new).to be_new
|
54
|
-
end
|
55
|
-
|
56
|
-
it "persists transitions when using send and a symbol" do
|
57
|
-
user = User.create!(:name => 'name')
|
58
|
-
expect(user.send(:invite_and_save)).to eq(true)
|
59
|
-
expect(User.find(user.id)).to be_invited
|
60
|
-
expect(User.find(user.id).activation_code).not_to be_nil
|
61
|
-
end
|
62
|
-
|
63
|
-
# TODO needs nesting/grouping, seems to have some duplication
|
64
|
-
|
65
|
-
describe "event_and_save" do
|
66
|
-
it "persists transitions" do
|
67
|
-
user = User.create!(:name => 'name')
|
68
|
-
expect(user.invite_and_save).to eq(true)
|
69
|
-
expect(User.find(user.id)).to be_invited
|
70
|
-
expect(User.find(user.id).activation_code).not_to be_nil
|
71
|
-
end
|
72
|
-
|
73
|
-
it "persists transitions when using send and a symbol" do
|
74
|
-
user = User.create!(:name => 'name')
|
75
|
-
expect(user.send(:invite_and_save)).to eq(true)
|
76
|
-
expect(User.find(user.id)).to be_invited
|
77
|
-
expect(User.find(user.id).activation_code).not_to be_nil
|
78
|
-
end
|
79
|
-
|
80
|
-
it "raises an error if an invalid state_transition is called" do
|
81
|
-
user = User.create!(:name => 'name')
|
82
|
-
expect {
|
83
|
-
user.confirm_invitation_and_save 'abc'
|
84
|
-
}.to raise_error(SimpleStateMachine::IllegalStateTransitionError,
|
85
|
-
"You cannot 'confirm_invitation' when state is 'new'")
|
86
|
-
end
|
87
|
-
|
88
|
-
it "returns false and keeps state if record is invalid" do
|
89
|
-
user = User.new
|
90
|
-
expect(user).to be_new
|
91
|
-
expect(user).not_to be_valid
|
92
|
-
expect(user.invite_and_save).to eq(false)
|
93
|
-
expect(user).to be_new
|
94
|
-
end
|
95
|
-
|
96
|
-
it "returns false, keeps state and keeps errors if event adds errors" do
|
97
|
-
user = User.create!(:name => 'name')
|
98
|
-
user.invite_and_save!
|
99
|
-
expect(user).to be_invited
|
100
|
-
expect(user.confirm_invitation_and_save('x')).to eq(false)
|
101
|
-
expect(user).to be_invited
|
102
|
-
expect(Array(user.errors[:activation_code])).to eq(['is invalid'])
|
103
|
-
end
|
104
|
-
|
105
|
-
it "rollsback if an exception is raised" do
|
106
|
-
user_class = Class.new(User)
|
107
|
-
user_class.instance_eval do
|
108
|
-
define_method :invite_without_managed_state do
|
109
|
-
User.create!(:name => 'name2') #this shouldn't be persisted
|
110
|
-
User.create! #this should raise an error
|
111
|
-
end
|
112
|
-
end
|
113
|
-
expect(user_class.count).to eq(0)
|
114
|
-
user = user_class.create!(:name => 'name')
|
115
|
-
expect {
|
116
|
-
user.transaction { user.invite_and_save }
|
117
|
-
}.to raise_error(ActiveRecord::RecordInvalid,
|
118
|
-
"Validation failed: Name can't be blank")
|
119
|
-
expect(user_class.count).to eq(1)
|
120
|
-
expect(user_class.first.name).to eq('name')
|
121
|
-
expect(user_class.first).to be_new
|
122
|
-
end
|
123
|
-
|
124
|
-
it "raises an error if an invalid state_transition is called" do
|
125
|
-
user = User.create!(:name => 'name')
|
126
|
-
expect {
|
127
|
-
user.confirm_invitation_and_save! 'abc'
|
128
|
-
}.to raise_error(SimpleStateMachine::IllegalStateTransitionError,
|
129
|
-
"You cannot 'confirm_invitation' when state is 'new'")
|
130
|
-
end
|
131
|
-
end
|
132
|
-
|
133
|
-
describe "event_and_save!" do
|
134
|
-
|
135
|
-
it "persists transitions" do
|
136
|
-
user = User.create!(:name => 'name')
|
137
|
-
expect(user.invite_and_save!).to eq(true)
|
138
|
-
expect(User.find(user.id)).to be_invited
|
139
|
-
expect(User.find(user.id).activation_code).not_to be_nil
|
140
|
-
end
|
141
|
-
|
142
|
-
it "raises an error if an invalid state_transition is called" do
|
143
|
-
user = User.create!(:name => 'name')
|
144
|
-
expect {
|
145
|
-
user.confirm_invitation_and_save! 'abc'
|
146
|
-
}.to raise_error(SimpleStateMachine::IllegalStateTransitionError,
|
147
|
-
"You cannot 'confirm_invitation' when state is 'new'")
|
148
|
-
end
|
149
|
-
|
150
|
-
it "raises a RecordInvalid and keeps state if record is invalid" do
|
151
|
-
user = User.new
|
152
|
-
expect(user).to be_new
|
153
|
-
expect(user).not_to be_valid
|
154
|
-
expect {
|
155
|
-
user.invite_and_save!
|
156
|
-
}.to raise_error(ActiveRecord::RecordInvalid,
|
157
|
-
"Validation failed: Name can't be blank")
|
158
|
-
expect(user).to be_new
|
159
|
-
end
|
160
|
-
|
161
|
-
it "raises a RecordInvalid and keeps state if event adds errors" do
|
162
|
-
user = User.create!(:name => 'name')
|
163
|
-
user.invite_and_save!
|
164
|
-
expect(user).to be_invited
|
165
|
-
expect {
|
166
|
-
user.confirm_invitation_and_save!('x')
|
167
|
-
}.to raise_error(ActiveRecord::RecordInvalid,
|
168
|
-
"Validation failed: Activation code is invalid")
|
169
|
-
expect(user).to be_invited
|
170
|
-
end
|
171
|
-
|
172
|
-
it "rollsback if an exception is raised" do
|
173
|
-
user_class = Class.new(User)
|
174
|
-
user_class.instance_eval do
|
175
|
-
define_method :invite_without_managed_state do
|
176
|
-
User.create!(:name => 'name2') #this shouldn't be persisted
|
177
|
-
User.create! #this should raise an error
|
178
|
-
end
|
179
|
-
end
|
180
|
-
expect(user_class.count).to eq(0)
|
181
|
-
user = user_class.create!(:name => 'name')
|
182
|
-
expect {
|
183
|
-
user.transaction { user.invite_and_save! }
|
184
|
-
}.to raise_error(ActiveRecord::RecordInvalid,
|
185
|
-
"Validation failed: Name can't be blank")
|
186
|
-
expect(user_class.count).to eq(1)
|
187
|
-
expect(user_class.first.name).to eq('name')
|
188
|
-
expect(user_class.first).to be_new
|
189
|
-
end
|
190
|
-
|
191
|
-
end
|
192
|
-
|
193
|
-
describe "event" do
|
194
|
-
it "persists transitions" do
|
195
|
-
user = User.create!(:name => 'name')
|
196
|
-
expect(user.invite).to eq(true)
|
197
|
-
expect(User.find(user.id)).to be_invited
|
198
|
-
expect(User.find(user.id).activation_code).not_to be_nil
|
199
|
-
end
|
200
|
-
|
201
|
-
it "returns false, keeps state and keeps errors if event adds errors" do
|
202
|
-
user = User.create!(:name => 'name')
|
203
|
-
user.invite_and_save!
|
204
|
-
expect(user).to be_invited
|
205
|
-
expect(user.confirm_invitation('x')).to eq(false)
|
206
|
-
expect(user).to be_invited
|
207
|
-
expect(Array(user.errors[:activation_code])).to eq(['is invalid'])
|
208
|
-
end
|
209
|
-
|
210
|
-
end
|
211
|
-
|
212
|
-
describe "event!" do
|
213
|
-
|
214
|
-
it "persists transitions" do
|
215
|
-
user = User.create!(:name => 'name')
|
216
|
-
expect(user.invite!).to eq(true)
|
217
|
-
expect(User.find(user.id)).to be_invited
|
218
|
-
expect(User.find(user.id).activation_code).not_to be_nil
|
219
|
-
end
|
220
|
-
|
221
|
-
it "raises a RecordInvalid and keeps state if record is invalid" do
|
222
|
-
user = User.new
|
223
|
-
expect(user).to be_new
|
224
|
-
expect(user).not_to be_valid
|
225
|
-
expect { user.invite! }.to raise_error(ActiveRecord::RecordInvalid, "Validation failed: Name can't be blank")
|
226
|
-
expect(user).to be_new
|
227
|
-
end
|
228
|
-
|
229
|
-
end
|
230
|
-
|
231
|
-
describe 'custom state method' do
|
232
|
-
|
233
|
-
it "persists transitions" do
|
234
|
-
ticket = Ticket.create!
|
235
|
-
expect(ticket.ssm_state).to eq('open')
|
236
|
-
expect(ticket.close!).to eq(true)
|
237
|
-
expect(ticket.ssm_state).to eq('closed')
|
238
|
-
end
|
239
|
-
|
240
|
-
it "persists transitions with !" do
|
241
|
-
ticket = Ticket.create!
|
242
|
-
expect(ticket.ssm_state).to eq('open')
|
243
|
-
ticket.close!
|
244
|
-
expect(ticket.ssm_state).to eq('closed')
|
245
|
-
end
|
246
|
-
|
247
|
-
end
|
248
|
-
|
249
|
-
end
|
250
|
-
end
|
@@ -1,195 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SimpleStateMachine::Decorator::Default do
|
4
|
-
|
5
|
-
context "given a class" do
|
6
|
-
before do
|
7
|
-
klass = Class.new do
|
8
|
-
# TODO remove the need for defining this method
|
9
|
-
def self.state_machine_definition
|
10
|
-
@state_machine_definition ||= SimpleStateMachine::StateMachineDefinition.new
|
11
|
-
end
|
12
|
-
end
|
13
|
-
decorator = described_class.new klass
|
14
|
-
decorator.decorate SimpleStateMachine::Transition.new(:event, :state1, :state2)
|
15
|
-
@instance = klass.new
|
16
|
-
@instance.state = 'state1'
|
17
|
-
end
|
18
|
-
|
19
|
-
describe "#initialize" do
|
20
|
-
it "defines a state_machine method" do
|
21
|
-
expect(@instance.state_machine).to be_an(SimpleStateMachine::StateMachine)
|
22
|
-
end
|
23
|
-
|
24
|
-
it "defines a state getter method" do
|
25
|
-
expect(@instance).to respond_to(:state)
|
26
|
-
end
|
27
|
-
|
28
|
-
it "defines a state setter method" do
|
29
|
-
expect(@instance).to respond_to(:state=)
|
30
|
-
end
|
31
|
-
end
|
32
|
-
|
33
|
-
describe "#decorate" do
|
34
|
-
it "defines state_helper_methods for both states" do
|
35
|
-
expect(@instance.state1?).to eq(true)
|
36
|
-
expect(@instance.state2?).to eq(false)
|
37
|
-
end
|
38
|
-
|
39
|
-
it "defines an event method" do
|
40
|
-
expect(@instance).to respond_to(:event)
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context "given a class with predefined public methods" do
|
46
|
-
before do
|
47
|
-
klass = Class.new do
|
48
|
-
# TODO remove the need for defining this method
|
49
|
-
def self.state_machine_definition
|
50
|
-
@state_machine_definition ||= SimpleStateMachine::StateMachineDefinition.new
|
51
|
-
end
|
52
|
-
# predefined methods
|
53
|
-
def state1?() "state1" end
|
54
|
-
def state2?() "state2" end
|
55
|
-
def event() "predefined method" end
|
56
|
-
end
|
57
|
-
transition = SimpleStateMachine::Transition.new(:event, :state1, :state2)
|
58
|
-
decorator = described_class.new klass
|
59
|
-
decorator.decorate transition
|
60
|
-
klass.state_machine_definition.transitions << transition
|
61
|
-
@instance = klass.new
|
62
|
-
@instance.state = 'state1'
|
63
|
-
end
|
64
|
-
|
65
|
-
describe "#initialize" do
|
66
|
-
it "defines a state_machine method" do
|
67
|
-
expect(@instance.state_machine).to be_an(SimpleStateMachine::StateMachine)
|
68
|
-
end
|
69
|
-
|
70
|
-
it "defines a state getter method" do
|
71
|
-
expect(@instance).to respond_to(:state)
|
72
|
-
end
|
73
|
-
|
74
|
-
it "defines a state setter method" do
|
75
|
-
expect(@instance).to respond_to(:state=)
|
76
|
-
end
|
77
|
-
end
|
78
|
-
|
79
|
-
describe "#decorate" do
|
80
|
-
it "does not overwrite predefined state_helper_methods" do
|
81
|
-
expect(@instance.state1?).to eq("state1")
|
82
|
-
expect(@instance.state2?).to eq("state2")
|
83
|
-
end
|
84
|
-
|
85
|
-
it "does not overwrite predefined event method" do
|
86
|
-
expect(@instance.event).to eq("predefined method")
|
87
|
-
end
|
88
|
-
end
|
89
|
-
end
|
90
|
-
|
91
|
-
context "given a class with predefined protected methods" do
|
92
|
-
before do
|
93
|
-
klass = Class.new do
|
94
|
-
# TODO remove the need for defining this method
|
95
|
-
def self.state_machine_definition
|
96
|
-
@state_machine_definition ||= SimpleStateMachine::StateMachineDefinition.new
|
97
|
-
end
|
98
|
-
# predefined methods
|
99
|
-
protected
|
100
|
-
def state1?() "state1" end
|
101
|
-
def state2?() "state2" end
|
102
|
-
def event() "predefined method" end
|
103
|
-
end
|
104
|
-
transition = SimpleStateMachine::Transition.new(:event, :state1, :state2)
|
105
|
-
decorator = described_class.new klass
|
106
|
-
decorator.decorate transition
|
107
|
-
klass.state_machine_definition.transitions << transition
|
108
|
-
@instance = klass.new
|
109
|
-
@instance.state = 'state1'
|
110
|
-
end
|
111
|
-
|
112
|
-
describe "#initialize" do
|
113
|
-
it "defines a state_machine method" do
|
114
|
-
expect(@instance.state_machine).to be_an(SimpleStateMachine::StateMachine)
|
115
|
-
end
|
116
|
-
|
117
|
-
it "defines a state getter method" do
|
118
|
-
expect(@instance).to respond_to(:state)
|
119
|
-
end
|
120
|
-
|
121
|
-
it "defines a state setter method" do
|
122
|
-
expect(@instance).to respond_to(:state=)
|
123
|
-
end
|
124
|
-
end
|
125
|
-
|
126
|
-
describe "#decorate" do
|
127
|
-
it "does not overwrite predefined protected state_helper_methods" do
|
128
|
-
expect(@instance.send(:state1?)).to eq("state1")
|
129
|
-
expect(@instance.send(:state2?)).to eq("state2")
|
130
|
-
end
|
131
|
-
|
132
|
-
it "keeps predefined protected state_helper_methods protected" do
|
133
|
-
expect { @instance.state1? }.to raise_error(NoMethodError)
|
134
|
-
expect { @instance.state2? }.to raise_error(NoMethodError)
|
135
|
-
end
|
136
|
-
|
137
|
-
it "does not overwrite predefined protected event method" do
|
138
|
-
expect(@instance.event).to eq("predefined method")
|
139
|
-
end
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
context "given a class with predefined private methods" do
|
144
|
-
before do
|
145
|
-
klass = Class.new do
|
146
|
-
# TODO the need for defining this method
|
147
|
-
def self.state_machine_definition
|
148
|
-
@state_machine_definition ||= SimpleStateMachine::StateMachineDefinition.new
|
149
|
-
end
|
150
|
-
# predefined methods
|
151
|
-
private
|
152
|
-
def state1?() "state1" end
|
153
|
-
def state2?() "state2" end
|
154
|
-
def event() "predefined method" end
|
155
|
-
end
|
156
|
-
transition = SimpleStateMachine::Transition.new(:event, :state1, :state2)
|
157
|
-
decorator = described_class.new klass
|
158
|
-
decorator.decorate transition
|
159
|
-
klass.state_machine_definition.transitions << transition
|
160
|
-
@instance = klass.new
|
161
|
-
@instance.state = 'state1'
|
162
|
-
end
|
163
|
-
|
164
|
-
describe "#initialize" do
|
165
|
-
it "defines a state_machine method" do
|
166
|
-
expect(@instance.state_machine).to be_an(SimpleStateMachine::StateMachine)
|
167
|
-
end
|
168
|
-
|
169
|
-
it "defines a state getter method" do
|
170
|
-
expect(@instance).to respond_to(:state)
|
171
|
-
end
|
172
|
-
|
173
|
-
it "defines a state setter method" do
|
174
|
-
expect(@instance).to respond_to(:state=)
|
175
|
-
end
|
176
|
-
end
|
177
|
-
|
178
|
-
describe "#decorate" do
|
179
|
-
it "does not overwrite predefined private state_helper_methods" do
|
180
|
-
expect(@instance.send(:state1?)).to eq("state1")
|
181
|
-
expect(@instance.send(:state2?)).to eq("state2")
|
182
|
-
end
|
183
|
-
|
184
|
-
it "keeps predefined private state_helper_methods private" do
|
185
|
-
expect { @instance.state1? }.to raise_error(NoMethodError)
|
186
|
-
expect { @instance.state2? }.to raise_error(NoMethodError)
|
187
|
-
end
|
188
|
-
|
189
|
-
it "does not overwrite predefined protected event method" do
|
190
|
-
expect(@instance.event).to eq("predefined method")
|
191
|
-
end
|
192
|
-
end
|
193
|
-
end
|
194
|
-
|
195
|
-
end
|
data/spec/examples_spec.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe "Examples" do
|
4
|
-
describe "TrafficLight" do
|
5
|
-
it "changes to the next state" do
|
6
|
-
tl = TrafficLight.new
|
7
|
-
expect(tl).to be_green
|
8
|
-
tl.change_state
|
9
|
-
expect(tl).to be_orange
|
10
|
-
tl.change_state
|
11
|
-
expect(tl).to be_red
|
12
|
-
tl.change_state
|
13
|
-
expect(tl).to be_green
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
describe "Lamp" do
|
18
|
-
it "changes between :on and :off" do
|
19
|
-
lamp = Lamp.new
|
20
|
-
expect(lamp).to be_off
|
21
|
-
lamp.push_button1
|
22
|
-
expect(lamp).to be_on
|
23
|
-
lamp.push_button2
|
24
|
-
expect(lamp).to be_off
|
25
|
-
lamp.push_button2
|
26
|
-
expect(lamp).to be_on
|
27
|
-
lamp.push_button1
|
28
|
-
expect(lamp).to be_off
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "Conversation" do
|
33
|
-
it "is :unread by default" do
|
34
|
-
conversation = Conversation.new
|
35
|
-
expect(conversation).to be_unread
|
36
|
-
end
|
37
|
-
|
38
|
-
it "changes to read on view" do
|
39
|
-
conversation = Conversation.new
|
40
|
-
conversation.view
|
41
|
-
expect(conversation).to be_read
|
42
|
-
end
|
43
|
-
|
44
|
-
it "changes to closed on close" do
|
45
|
-
conversation = Conversation.new
|
46
|
-
conversation.close
|
47
|
-
expect(conversation).to be_closed
|
48
|
-
end
|
49
|
-
|
50
|
-
it "changes to closed on close if :read" do
|
51
|
-
conversation = Conversation.new
|
52
|
-
conversation.view
|
53
|
-
conversation.close
|
54
|
-
expect(conversation).to be_closed
|
55
|
-
end
|
56
|
-
|
57
|
-
end
|
58
|
-
|
59
|
-
end
|
60
|
-
|
data/spec/mountable_spec.rb
DELETED
@@ -1,36 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SimpleStateMachine::Mountable do
|
4
|
-
class MountableExample < SimpleStateMachine::StateMachineDefinition
|
5
|
-
event(:event, :state1 => :state2)
|
6
|
-
|
7
|
-
def decorator_class
|
8
|
-
SimpleStateMachine::Decorator::Default
|
9
|
-
end
|
10
|
-
end
|
11
|
-
|
12
|
-
let(:klass) do
|
13
|
-
Class.new do
|
14
|
-
attr_accessor :event_called
|
15
|
-
extend SimpleStateMachine::Mountable
|
16
|
-
mount_state_machine MountableExample
|
17
|
-
def event_without_managed_state
|
18
|
-
@event_called = true
|
19
|
-
end
|
20
|
-
end
|
21
|
-
end
|
22
|
-
subject do
|
23
|
-
klass.new.tap{|i| i.state = 'state1' }
|
24
|
-
end
|
25
|
-
|
26
|
-
it "has state_helper methods" do
|
27
|
-
expect(subject).to be_state1
|
28
|
-
expect(subject).not_to be_state2
|
29
|
-
end
|
30
|
-
|
31
|
-
it "calls existing methods" do
|
32
|
-
subject.event
|
33
|
-
expect(subject).to be_state2
|
34
|
-
expect(subject.event_called).to eq(true)
|
35
|
-
end
|
36
|
-
end
|
@@ -1,165 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe SimpleStateMachine do
|
4
|
-
|
5
|
-
it "has an error that extends RuntimeError" do
|
6
|
-
expect(SimpleStateMachine::IllegalStateTransitionError.superclass).to eq(RuntimeError)
|
7
|
-
end
|
8
|
-
|
9
|
-
let(:klass) do
|
10
|
-
Class.new do
|
11
|
-
extend SimpleStateMachine
|
12
|
-
def initialize(state = 'state1')
|
13
|
-
@state = state
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
describe ".event" do
|
19
|
-
|
20
|
-
it "returns what the decorated method returns" do
|
21
|
-
klass.instance_eval do
|
22
|
-
event :event1, :state1 => :state2
|
23
|
-
define_method :event2 do
|
24
|
-
'event2'
|
25
|
-
end
|
26
|
-
event :event2, :state2 => :state3
|
27
|
-
end
|
28
|
-
subject = klass.new
|
29
|
-
expect(subject.event1).to eq(nil)
|
30
|
-
expect(subject.event2).to eq('event2')
|
31
|
-
end
|
32
|
-
|
33
|
-
it "calls existing methods" do
|
34
|
-
klass.instance_eval do
|
35
|
-
attr_accessor :event_called
|
36
|
-
define_method :event do
|
37
|
-
@event_called = true
|
38
|
-
end
|
39
|
-
event :event, :state1 => :state2
|
40
|
-
end
|
41
|
-
subject = klass.new
|
42
|
-
subject.event
|
43
|
-
expect(subject.event_called).to eq(true)
|
44
|
-
end
|
45
|
-
|
46
|
-
context "given an event has multiple transitions" do
|
47
|
-
before do
|
48
|
-
klass.instance_eval do
|
49
|
-
event :event, :state1 => :state2, :state2 => :state3
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
it "changes state for all transitions" do
|
54
|
-
subject = klass.new
|
55
|
-
expect(subject).to be_state1
|
56
|
-
subject.event
|
57
|
-
expect(subject).to be_state2
|
58
|
-
subject.event
|
59
|
-
expect(subject).to be_state3
|
60
|
-
end
|
61
|
-
end
|
62
|
-
|
63
|
-
context "given an event has multiple from states" do
|
64
|
-
before do
|
65
|
-
klass.instance_eval do
|
66
|
-
event :event, [:state1, :state2] => :state3
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
it "changes state for all from states" do
|
71
|
-
subject = klass.new
|
72
|
-
subject.event
|
73
|
-
expect(subject).to be_state3
|
74
|
-
subject = klass.new 'state2'
|
75
|
-
expect(subject).to be_state2
|
76
|
-
subject.event
|
77
|
-
expect(subject).to be_state3
|
78
|
-
end
|
79
|
-
end
|
80
|
-
|
81
|
-
context "given an event has :all as from state" do
|
82
|
-
before do
|
83
|
-
klass.instance_eval do
|
84
|
-
event :other_event, :state1 => :state2
|
85
|
-
event :event, :all => :state3
|
86
|
-
end
|
87
|
-
end
|
88
|
-
|
89
|
-
it "changes state from all states" do
|
90
|
-
subject = klass.new
|
91
|
-
subject.event
|
92
|
-
expect(subject).to be_state3
|
93
|
-
subject = klass.new 'state2'
|
94
|
-
expect(subject).to be_state2
|
95
|
-
subject.event
|
96
|
-
expect(subject).to be_state3
|
97
|
-
end
|
98
|
-
end
|
99
|
-
|
100
|
-
context "given state is a symbol instead of a string" do
|
101
|
-
before do
|
102
|
-
klass.instance_eval do
|
103
|
-
event :event, :state1 => :state2
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
it "changes state" do
|
108
|
-
subject = klass.new :state1
|
109
|
-
expect(subject.state).to eq(:state1)
|
110
|
-
subject.send(:event)
|
111
|
-
expect(subject).to be_state2
|
112
|
-
end
|
113
|
-
end
|
114
|
-
|
115
|
-
context "given an RuntimeError begin state" do
|
116
|
-
it "changes state to error_state when error can be caught" do
|
117
|
-
class_with_error = Class.new(klass)
|
118
|
-
class_with_error.instance_eval do
|
119
|
-
define_method :raise_error do
|
120
|
-
raise RuntimeError.new
|
121
|
-
end
|
122
|
-
event :raise_error, :state1 => :state2, RuntimeError => :failed
|
123
|
-
end
|
124
|
-
subject = class_with_error.new
|
125
|
-
expect(subject).to be_state1
|
126
|
-
subject.raise_error
|
127
|
-
expect(subject).to be_failed
|
128
|
-
end
|
129
|
-
|
130
|
-
it "changes state to error_state when error superclass can be caught" do
|
131
|
-
error_subclass = Class.new(RuntimeError)
|
132
|
-
class_with_error = Class.new(klass)
|
133
|
-
class_with_error.instance_eval do
|
134
|
-
define_method :raise_error do
|
135
|
-
raise error_subclass.new
|
136
|
-
end
|
137
|
-
event :raise_error, :state1 => :state2, RuntimeError => :failed
|
138
|
-
end
|
139
|
-
subject = class_with_error.new
|
140
|
-
expect(subject).to be_state1
|
141
|
-
subject.raise_error
|
142
|
-
expect(subject).to be_failed
|
143
|
-
end
|
144
|
-
end
|
145
|
-
|
146
|
-
context "given an invalid state_transition is called" do
|
147
|
-
before do
|
148
|
-
klass.instance_eval do
|
149
|
-
event :event, :state1 => :state2
|
150
|
-
event :event2, :state2 => :state3
|
151
|
-
end
|
152
|
-
end
|
153
|
-
|
154
|
-
it "raises an IllegalStateTransitionError" do
|
155
|
-
subject = klass.new
|
156
|
-
expect { subject.event2 }.to raise_error(
|
157
|
-
SimpleStateMachine::IllegalStateTransitionError,
|
158
|
-
"You cannot 'event2' when state is 'state1'")
|
159
|
-
end
|
160
|
-
end
|
161
|
-
|
162
|
-
end
|
163
|
-
|
164
|
-
end
|
165
|
-
|