statesman 1.1.0 → 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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +7 -1
  3. data/.travis.yml +19 -4
  4. data/CHANGELOG.md +30 -0
  5. data/README.md +11 -35
  6. data/lib/generators/statesman/add_constraints_to_most_recent_generator.rb +28 -0
  7. data/lib/generators/statesman/add_most_recent_generator.rb +25 -0
  8. data/lib/generators/statesman/generator_helpers.rb +6 -2
  9. data/lib/generators/statesman/templates/add_constraints_to_most_recent_migration.rb.erb +13 -0
  10. data/lib/generators/statesman/templates/add_most_recent_migration.rb.erb +9 -0
  11. data/lib/generators/statesman/templates/create_migration.rb.erb +4 -3
  12. data/lib/generators/statesman/templates/update_migration.rb.erb +5 -4
  13. data/lib/statesman.rb +1 -0
  14. data/lib/statesman/adapters/active_record.rb +23 -8
  15. data/lib/statesman/adapters/active_record_queries.rb +62 -15
  16. data/lib/statesman/railtie.rb +9 -0
  17. data/lib/statesman/version.rb +1 -1
  18. data/lib/tasks/statesman.rake +49 -0
  19. data/spec/fixtures/add_constraints_to_most_recent_for_bacon_transitions.rb +13 -0
  20. data/spec/fixtures/add_most_recent_to_bacon_transitions.rb +9 -0
  21. data/spec/generators/statesman/active_record_transition_generator_spec.rb +0 -2
  22. data/spec/generators/statesman/add_constraints_to_most_recent_generator_spec.rb +38 -0
  23. data/spec/generators/statesman/add_most_recent_generator_spec.rb +35 -0
  24. data/spec/generators/statesman/migration_generator_spec.rb +10 -1
  25. data/spec/generators/statesman/mongoid_transition_generator_spec.rb +0 -2
  26. data/spec/spec_helper.rb +22 -7
  27. data/spec/statesman/adapters/active_record_queries_spec.rb +110 -28
  28. data/spec/statesman/adapters/active_record_spec.rb +61 -31
  29. data/spec/statesman/adapters/mongoid_spec.rb +8 -17
  30. data/spec/statesman/adapters/shared_examples.rb +10 -17
  31. data/spec/statesman/callback_spec.rb +2 -6
  32. data/spec/statesman/config_spec.rb +2 -5
  33. data/spec/statesman/guard_spec.rb +3 -9
  34. data/spec/statesman/machine_spec.rb +91 -129
  35. data/spec/support/active_record.rb +35 -4
  36. data/spec/support/generators_shared_examples.rb +1 -4
  37. data/statesman.gemspec +5 -3
  38. metadata +52 -10
@@ -2,18 +2,14 @@ require "spec_helper"
2
2
  require "statesman/adapters/shared_examples"
3
3
  require "statesman/exceptions"
4
4
 
5
- describe Statesman::Adapters::ActiveRecord do
5
+ describe Statesman::Adapters::ActiveRecord, active_record: true do
6
6
  before do
7
7
  prepare_model_table
8
8
  prepare_transitions_table
9
9
  end
10
10
 
11
11
  before { MyActiveRecordModelTransition.serialize(:metadata, JSON) }
12
- let(:observer) do
13
- result = double(Statesman::Machine)
14
- allow(result).to receive(:execute)
15
- result
16
- end
12
+ let(:observer) { double(Statesman::Machine, execute: nil) }
17
13
  let(:model) { MyActiveRecordModel.create(current_state: :pending) }
18
14
  it_behaves_like "an adapter", described_class, MyActiveRecordModelTransition
19
15
 
@@ -24,11 +20,12 @@ describe Statesman::Adapters::ActiveRecord do
24
20
  allow(metadata_column).to receive_messages(sql_type: '')
25
21
  allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
26
22
  { 'metadata' => metadata_column })
27
- if ::ActiveRecord.gem_version >= Gem::Version.new('4.2.0.a')
23
+ if ::ActiveRecord.respond_to?(:gem_version) &&
24
+ ::ActiveRecord.gem_version >= Gem::Version.new('4.2.0.a')
28
25
  allow(metadata_column).to receive_messages(cast_type: '')
29
26
  else
30
- allow(MyActiveRecordModelTransition)
31
- .to receive_messages(serialized_attributes: {})
27
+ allow(MyActiveRecordModelTransition).
28
+ to receive_messages(serialized_attributes: {})
32
29
  end
33
30
  end
34
31
 
@@ -46,16 +43,17 @@ describe Statesman::Adapters::ActiveRecord do
46
43
  allow(metadata_column).to receive_messages(sql_type: 'json')
47
44
  allow(MyActiveRecordModelTransition).to receive_messages(columns_hash:
48
45
  { 'metadata' => metadata_column })
49
- if ::ActiveRecord.gem_version >= Gem::Version.new('4.2.0.a')
46
+ if ::ActiveRecord.respond_to?(:gem_version) &&
47
+ ::ActiveRecord.gem_version >= Gem::Version.new('4.2.0.a')
50
48
  serialized_type = ::ActiveRecord::Type::Serialized.new(
51
49
  '', ::ActiveRecord::Coders::JSON
52
50
  )
53
- expect(metadata_column)
54
- .to receive(:cast_type)
55
- .and_return(serialized_type)
51
+ expect(metadata_column).
52
+ to receive(:cast_type).
53
+ and_return(serialized_type)
56
54
  else
57
- expect(MyActiveRecordModelTransition)
58
- .to receive_messages(serialized_attributes: { 'metadata' => '' })
55
+ expect(MyActiveRecordModelTransition).
56
+ to receive_messages(serialized_attributes: { 'metadata' => '' })
59
57
  end
60
58
  end
61
59
 
@@ -83,15 +81,15 @@ describe Statesman::Adapters::ActiveRecord do
83
81
  adapter2.create(:x, :y)
84
82
  adapter.last
85
83
  adapter2.create(:y, :z)
86
- expect { adapter.create(:y, :z) }
87
- .to raise_exception(Statesman::TransitionConflictError)
84
+ expect { adapter.create(:y, :z) }.
85
+ to raise_exception(Statesman::TransitionConflictError)
88
86
  end
89
87
  end
90
88
 
91
89
  context "when other exceptions occur" do
92
90
  before do
93
- allow_any_instance_of(MyActiveRecordModelTransition)
94
- .to receive(:save!).and_raise(error)
91
+ allow_any_instance_of(MyActiveRecordModelTransition).
92
+ to receive(:save!).and_raise(error)
95
93
  end
96
94
 
97
95
  context "ActiveRecord::RecordNotUnique unrelated to this transition" do
@@ -104,6 +102,44 @@ describe Statesman::Adapters::ActiveRecord do
104
102
  it { is_expected.to raise_exception(StandardError) }
105
103
  end
106
104
  end
105
+
106
+ context "when the transition_class has a most_recent column" do
107
+ subject { create }
108
+
109
+ context "with no previous transition" do
110
+ its(:most_recent) { is_expected.to eq(true) }
111
+ end
112
+
113
+ context "with a previous transition" do
114
+ let!(:previous_transition) { adapter.create(from, to) }
115
+ its(:most_recent) { is_expected.to eq(true) }
116
+
117
+ it "updates the previous transition's most_recent flag" do
118
+ expect { create }.
119
+ to change { previous_transition.reload.most_recent }.
120
+ from(true).to(false)
121
+ end
122
+
123
+ context "and the parent model is updated in a callback" do
124
+ before do
125
+ allow(observer).to receive(:execute) do |phase|
126
+ if phase == :before
127
+ model.update_attributes!(current_state: :ready)
128
+ end
129
+ end
130
+ end
131
+
132
+ it "doesn't save the transition too early" do
133
+ expect { create }.to_not raise_exception
134
+ end
135
+ end
136
+ end
137
+ end
138
+
139
+ context "when the transition_class doesn't have a most_recent column" do
140
+ before { drop_most_recent_column }
141
+ it { is_expected.to_not raise_exception }
142
+ end
107
143
  end
108
144
 
109
145
  describe "#last" do
@@ -111,18 +147,14 @@ describe Statesman::Adapters::ActiveRecord do
111
147
  described_class.new(MyActiveRecordModelTransition, model, observer)
112
148
  end
113
149
 
114
- before do
115
- adapter.create(:x, :y)
116
- end
150
+ before { adapter.create(:x, :y) }
117
151
 
118
152
  context "with a previously looked up transition" do
119
- before do
120
- adapter.last
121
- end
153
+ before { adapter.last }
122
154
 
123
155
  it "caches the transition" do
124
- expect_any_instance_of(MyActiveRecordModel)
125
- .to receive(:my_active_record_model_transitions).never
156
+ expect_any_instance_of(MyActiveRecordModel).
157
+ to receive(:my_active_record_model_transitions).never
126
158
  adapter.last
127
159
  end
128
160
 
@@ -135,10 +167,8 @@ describe Statesman::Adapters::ActiveRecord do
135
167
  end
136
168
 
137
169
  context "with a pre-fetched transition history" do
138
- before do
139
- adapter.create(:x, :y)
140
- model.my_active_record_model_transitions.load_target
141
- end
170
+ before { adapter.create(:x, :y) }
171
+ before { model.my_active_record_model_transitions.load_target }
142
172
 
143
173
  it "doesn't query the database" do
144
174
  expect(MyActiveRecordModelTransition).not_to receive(:connection)
@@ -5,23 +5,16 @@ require "support/mongoid"
5
5
  require "mongoid"
6
6
 
7
7
  describe Statesman::Adapters::Mongoid, mongo: true do
8
-
9
- after do
10
- Mongoid.purge!
11
- end
12
- let(:observer) do
13
- result = double(Statesman::Machine)
14
- allow(result).to receive(:execute)
15
- result
16
- end
8
+ after { Mongoid.purge! }
9
+ let(:observer) { double(Statesman::Machine, execute: nil) }
17
10
  let(:model) { MyMongoidModel.create(current_state: :pending) }
18
11
  it_behaves_like "an adapter", described_class, MyMongoidModelTransition
19
12
 
20
13
  describe "#initialize" do
21
14
  context "with unserialized metadata" do
22
15
  before do
23
- allow_any_instance_of(described_class)
24
- .to receive_messages(transition_class_hash_fields: [])
16
+ allow_any_instance_of(described_class).
17
+ to receive_messages(transition_class_hash_fields: [])
25
18
  end
26
19
 
27
20
  it "raises an exception if metadata is not serialized" do
@@ -39,14 +32,12 @@ describe Statesman::Adapters::Mongoid, mongo: true do
39
32
  end
40
33
 
41
34
  context "with a previously looked up transition" do
42
- before do
43
- adapter.create(:x, :y)
44
- adapter.last
45
- end
35
+ before { adapter.create(:x, :y) }
36
+ before { adapter.last }
46
37
 
47
38
  it "caches the transition" do
48
- expect_any_instance_of(MyMongoidModel)
49
- .to receive(:my_mongoid_model_transitions).never
39
+ expect_any_instance_of(MyMongoidModel).
40
+ to receive(:my_mongoid_model_transitions).never
50
41
  adapter.last
51
42
  end
52
43
 
@@ -12,11 +12,7 @@ require "spec_helper"
12
12
  # last: Returns the latest transition history item
13
13
  #
14
14
  shared_examples_for "an adapter" do |adapter_class, transition_class|
15
- let(:observer) do
16
- result = double(Statesman::Machine)
17
- allow(result).to receive(:execute)
18
- result
19
- end
15
+ let(:observer) { double(Statesman::Machine, execute: nil) }
20
16
  let(:adapter) { adapter_class.new(transition_class, model, observer) }
21
17
 
22
18
  describe "#initialize" do
@@ -55,8 +51,8 @@ shared_examples_for "an adapter" do |adapter_class, transition_class|
55
51
 
56
52
  context "with before callbacks" do
57
53
  it "is called before the state transition" do
58
- expect(observer).to receive(:execute)
59
- .with(:before, anything, anything, anything) {
54
+ expect(observer).to receive(:execute).
55
+ with(:before, anything, anything, anything) {
60
56
  expect(adapter.history.length).to eq(0)
61
57
  }.once
62
58
  adapter.create(from, to)
@@ -66,9 +62,8 @@ shared_examples_for "an adapter" do |adapter_class, transition_class|
66
62
 
67
63
  context "with after callbacks" do
68
64
  it "is called after the state transition" do
69
- expect(observer).to receive(:execute)
70
- .with(:after, anything, anything, anything) {
71
- |_phase, _from_state, _to_state, transition|
65
+ expect(observer).to receive(:execute).
66
+ with(:after, anything, anything, anything) { |_, _, _, transition|
72
67
  expect(adapter.last).to eq(transition)
73
68
  }.once
74
69
  adapter.create(from, to)
@@ -77,9 +72,8 @@ shared_examples_for "an adapter" do |adapter_class, transition_class|
77
72
  it "exposes the new transition for subsequent transitions" do
78
73
  adapter.create(from, to)
79
74
 
80
- expect(observer).to receive(:execute)
81
- .with(:after, anything, anything, anything) {
82
- |_phase, _from_state, _to_state, transition|
75
+ expect(observer).to receive(:execute).
76
+ with(:after, anything, anything, anything) { |_, _, _, transition|
83
77
  expect(adapter.last).to eq(transition)
84
78
  }.once
85
79
  adapter.create(to, there)
@@ -104,16 +98,15 @@ shared_examples_for "an adapter" do |adapter_class, transition_class|
104
98
  context "sorting" do
105
99
  let!(:transition2) { adapter.create(:x, :y) }
106
100
  subject { adapter.history }
101
+
107
102
  it { is_expected.to eq(adapter.history.sort_by(&:sort_key)) }
108
103
  end
109
104
  end
110
105
  end
111
106
 
112
107
  describe "#last" do
113
- before do
114
- adapter.create(:x, :y)
115
- adapter.create(:y, :z)
116
- end
108
+ before { adapter.create(:x, :y) }
109
+ before { adapter.create(:y, :z) }
117
110
  subject { adapter.last }
118
111
 
119
112
  it { is_expected.to be_a(transition_class) }
@@ -61,9 +61,7 @@ describe Statesman::Callback do
61
61
  end
62
62
 
63
63
  context "with any to and any from value on the callback" do
64
- let(:callback) do
65
- Statesman::Callback.new(callback: cb_lambda)
66
- end
64
+ let(:callback) { Statesman::Callback.new(callback: cb_lambda) }
67
65
  let(:from) { :x }
68
66
  let(:to) { :y }
69
67
 
@@ -93,9 +91,7 @@ describe Statesman::Callback do
93
91
  end
94
92
 
95
93
  context "with any to value on the callback" do
96
- let(:callback) do
97
- Statesman::Callback.new(from: :x, callback: cb_lambda)
98
- end
94
+ let(:callback) { Statesman::Callback.new(from: :x, callback: cb_lambda) }
99
95
  let(:to) { :y }
100
96
 
101
97
  context "and an allowed to value" do
@@ -2,16 +2,13 @@ require "spec_helper"
2
2
 
3
3
  describe Statesman::Config do
4
4
  let(:instance) { Statesman::Config.new }
5
-
6
- after do
7
- # Don't leak global config changes into other specs
8
- Statesman.configure { storage_adapter(Statesman::Adapters::Memory) }
9
- end
5
+ after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } }
10
6
 
11
7
  describe "#storage_adapter" do
12
8
  let(:adapter) { Class.new }
13
9
  before { instance.storage_adapter(adapter) }
14
10
  subject { instance.adapter_class }
11
+
15
12
  it { is_expected.to be(adapter) }
16
13
 
17
14
  it "is DSL configurable" do
@@ -7,22 +7,16 @@ describe Statesman::Guard do
7
7
  specify { expect(guard).to be_a(Statesman::Callback) }
8
8
 
9
9
  describe "#call" do
10
- subject { guard.call }
10
+ subject(:call) { guard.call }
11
11
 
12
12
  context "success" do
13
13
  let(:callback) { -> { true } }
14
-
15
- it "does not raise an error" do
16
- expect { guard.call }.to_not raise_error
17
- end
14
+ specify { expect { call }.to_not raise_error }
18
15
  end
19
16
 
20
17
  context "error" do
21
18
  let(:callback) { -> { false } }
22
-
23
- it "raises an error" do
24
- expect { guard.call }.to raise_error(Statesman::GuardFailedError)
25
- end
19
+ specify { expect { call }.to raise_error(Statesman::GuardFailedError) }
26
20
  end
27
21
  end
28
22
  end
@@ -15,9 +15,8 @@ describe Statesman::Machine do
15
15
 
16
16
  context "when an initial state is already defined" do
17
17
  it "raises an error" do
18
- expect do
19
- machine.state(:y, initial: true)
20
- end.to raise_error(Statesman::InvalidStateError)
18
+ expect { machine.state(:y, initial: true) }.
19
+ to raise_error(Statesman::InvalidStateError)
21
20
  end
22
21
  end
23
22
  end
@@ -51,15 +50,15 @@ describe Statesman::Machine do
51
50
 
52
51
  context "when an irrelevant exception occurs" do
53
52
  it "runs the transition once" do
54
- expect(instance)
55
- .to receive(:transition_to).once
56
- .and_raise(StandardError)
53
+ expect(instance).
54
+ to receive(:transition_to).once.
55
+ and_raise(StandardError)
57
56
  transition_state rescue nil # rubocop:disable RescueModifier
58
57
  end
59
58
 
60
59
  it "re-raises the exception" do
61
- allow(instance).to receive(:transition_to).once
62
- .and_raise(StandardError)
60
+ allow(instance).to receive(:transition_to).once.
61
+ and_raise(StandardError)
63
62
  expect { transition_state }.to raise_error(StandardError)
64
63
  end
65
64
  end
@@ -67,31 +66,31 @@ describe Statesman::Machine do
67
66
  context "when a TransitionConflictError occurs" do
68
67
  context "and is resolved on the second attempt" do
69
68
  it "runs the transition twice" do
70
- expect(instance)
71
- .to receive(:transition_to).once
72
- .and_raise(Statesman::TransitionConflictError)
73
- .ordered
74
- expect(instance)
75
- .to receive(:transition_to).once.ordered.and_call_original
69
+ expect(instance).
70
+ to receive(:transition_to).once.
71
+ and_raise(Statesman::TransitionConflictError).
72
+ ordered
73
+ expect(instance).
74
+ to receive(:transition_to).once.ordered.and_call_original
76
75
  transition_state
77
76
  end
78
77
  end
79
78
 
80
79
  context "and keeps occurring" do
81
80
  it "runs the transition `retry_attempts + 1` times" do
82
- expect(instance)
83
- .to receive(:transition_to)
84
- .exactly(retry_attempts + 1).times
85
- .and_raise(Statesman::TransitionConflictError)
81
+ expect(instance).
82
+ to receive(:transition_to).
83
+ exactly(retry_attempts + 1).times.
84
+ and_raise(Statesman::TransitionConflictError)
86
85
  transition_state rescue nil # rubocop:disable RescueModifier
87
86
  end
88
87
 
89
88
  it "re-raises the conflict" do
90
- allow(instance)
91
- .to receive(:transition_to)
92
- .and_raise(Statesman::TransitionConflictError)
93
- expect { transition_state }
94
- .to raise_error(Statesman::TransitionConflictError)
89
+ allow(instance).
90
+ to receive(:transition_to).
91
+ and_raise(Statesman::TransitionConflictError)
92
+ expect { transition_state }.
93
+ to raise_error(Statesman::TransitionConflictError)
95
94
  end
96
95
  end
97
96
  end
@@ -108,49 +107,43 @@ describe Statesman::Machine do
108
107
 
109
108
  context "given neither a 'from' nor a 'to' state" do
110
109
  it "raises an error" do
111
- expect do
112
- machine.transition
113
- end.to raise_error(Statesman::InvalidStateError)
110
+ expect { machine.transition }.
111
+ to raise_error(Statesman::InvalidStateError)
114
112
  end
115
113
  end
116
114
 
117
115
  context "given no 'from' state and a valid 'to' state" do
118
116
  it "raises an error" do
119
- expect do
120
- machine.transition from: nil, to: :x
121
- end.to raise_error(Statesman::InvalidStateError)
117
+ expect { machine.transition from: nil, to: :x }.
118
+ to raise_error(Statesman::InvalidStateError)
122
119
  end
123
120
  end
124
121
 
125
122
  context "given a valid 'from' state and a no 'to' state" do
126
123
  it "raises an error" do
127
- expect do
128
- machine.transition from: :x, to: nil
129
- end.to raise_error(Statesman::InvalidStateError)
124
+ expect { machine.transition from: :x, to: nil }.
125
+ to raise_error(Statesman::InvalidStateError)
130
126
  end
131
127
  end
132
128
 
133
129
  context "given a valid 'from' state and an empty 'to' state array" do
134
130
  it "raises an error" do
135
- expect do
136
- machine.transition from: :x, to: []
137
- end.to raise_error(Statesman::InvalidStateError)
131
+ expect { machine.transition from: :x, to: [] }.
132
+ to raise_error(Statesman::InvalidStateError)
138
133
  end
139
134
  end
140
135
 
141
136
  context "given an invalid 'from' state" do
142
137
  it "raises an error" do
143
- expect do
144
- machine.transition(from: :a, to: :x)
145
- end.to raise_error(Statesman::InvalidStateError)
138
+ expect { machine.transition(from: :a, to: :x) }.
139
+ to raise_error(Statesman::InvalidStateError)
146
140
  end
147
141
  end
148
142
 
149
143
  context "given an invalid 'to' state" do
150
144
  it "raises an error" do
151
- expect do
152
- machine.transition(from: :x, to: :a)
153
- end.to raise_error(Statesman::InvalidStateError)
145
+ expect { machine.transition(from: :x, to: :a) }.
146
+ to raise_error(Statesman::InvalidStateError)
154
147
  end
155
148
  end
156
149
 
@@ -176,25 +169,22 @@ describe Statesman::Machine do
176
169
 
177
170
  context "with a terminal 'from' state" do
178
171
  it "raises an exception" do
179
- expect do
180
- machine.validate_callback_condition(from: :z, to: :y)
181
- end.to raise_error(Statesman::InvalidTransitionError)
172
+ expect { machine.validate_callback_condition(from: :z, to: :y) }.
173
+ to raise_error(Statesman::InvalidTransitionError)
182
174
  end
183
175
  end
184
176
 
185
177
  context "with an initial 'to' state" do
186
178
  it "raises an exception" do
187
- expect do
188
- machine.validate_callback_condition(from: :y, to: :x)
189
- end.to raise_error(Statesman::InvalidTransitionError)
179
+ expect { machine.validate_callback_condition(from: :y, to: :x) }.
180
+ to raise_error(Statesman::InvalidTransitionError)
190
181
  end
191
182
  end
192
183
 
193
184
  context "with an invalid transition" do
194
185
  it "raises an exception" do
195
- expect do
196
- machine.validate_callback_condition(from: :x, to: :z)
197
- end.to raise_error(Statesman::InvalidTransitionError)
186
+ expect { machine.validate_callback_condition(from: :x, to: :z) }.
187
+ to raise_error(Statesman::InvalidTransitionError)
198
188
  end
199
189
  end
200
190
 
@@ -206,9 +196,8 @@ describe Statesman::Machine do
206
196
 
207
197
  context "with a valid transition" do
208
198
  it "does not raise an exception" do
209
- expect do
210
- machine.validate_callback_condition(from: :x, to: :y)
211
- end.to_not raise_error
199
+ expect { machine.validate_callback_condition(from: :x, to: :y) }.
200
+ to_not raise_error
212
201
  end
213
202
  end
214
203
  end
@@ -227,9 +216,7 @@ describe Statesman::Machine do
227
216
  let(:set_callback) { machine.send(assignment_method, options) {} }
228
217
 
229
218
  shared_examples "fails" do |error_type|
230
- it "raises an exception" do
231
- expect { set_callback }.to raise_error(error_type)
232
- end
219
+ specify { expect { set_callback }.to raise_error(error_type) }
233
220
 
234
221
  it "does not add a callback" do
235
222
  expect do
@@ -243,13 +230,11 @@ describe Statesman::Machine do
243
230
  end
244
231
 
245
232
  shared_examples "adds callback" do
246
- it "does not raise" do
247
- expect { set_callback }.to_not raise_error
248
- end
233
+ specify { expect { set_callback }.to_not raise_error }
249
234
 
250
235
  it "stores callbacks" do
251
- expect { set_callback }.to change(
252
- machine.callbacks[callback_store], :count).by(1)
236
+ expect { set_callback }.
237
+ to change(machine.callbacks[callback_store], :count).by(1)
253
238
  end
254
239
 
255
240
  it "stores callback instances" do
@@ -330,22 +315,22 @@ describe Statesman::Machine do
330
315
 
331
316
  context "transition class" do
332
317
  it "sets a default" do
333
- expect(Statesman.storage_adapter).to receive(:new).once
334
- .with(Statesman::Adapters::MemoryTransition, my_model, anything)
318
+ expect(Statesman.storage_adapter).to receive(:new).once.
319
+ with(Statesman::Adapters::MemoryTransition, my_model, anything)
335
320
  machine.new(my_model)
336
321
  end
337
322
 
338
323
  it "sets the passed class" do
339
324
  my_transition_class = Class.new
340
- expect(Statesman.storage_adapter).to receive(:new).once
341
- .with(my_transition_class, my_model, anything)
325
+ expect(Statesman.storage_adapter).to receive(:new).once.
326
+ with(my_transition_class, my_model, anything)
342
327
  machine.new(my_model, transition_class: my_transition_class)
343
328
  end
344
329
 
345
330
  it "falls back to Memory without transaction_class" do
346
331
  allow(Statesman).to receive(:storage_adapter).and_return(Class.new)
347
- expect(Statesman::Adapters::Memory).to receive(:new).once
348
- .with(Statesman::Adapters::MemoryTransition, my_model, anything)
332
+ expect(Statesman::Adapters::Memory).to receive(:new).once.
333
+ with(Statesman::Adapters::MemoryTransition, my_model, anything)
349
334
  machine.new(my_model)
350
335
  end
351
336
  end
@@ -380,10 +365,8 @@ describe Statesman::Machine do
380
365
  end
381
366
 
382
367
  context "with multiple transitions" do
383
- before do
384
- instance.transition_to!(:y)
385
- instance.transition_to!(:z)
386
- end
368
+ before { instance.transition_to!(:y) }
369
+ before { instance.transition_to!(:z) }
387
370
 
388
371
  it { is_expected.to eq("z") }
389
372
  end
@@ -408,18 +391,12 @@ describe Statesman::Machine do
408
391
  end
409
392
 
410
393
  context "with one possible state" do
411
- before do
412
- instance.transition_to!(:y)
413
- end
414
-
394
+ before { instance.transition_to!(:y) }
415
395
  it { is_expected.to eq(['z']) }
416
396
  end
417
397
 
418
398
  context "with no possible transitions" do
419
- before do
420
- instance.transition_to!(:z)
421
- end
422
-
399
+ before { instance.transition_to!(:z) }
423
400
  it { is_expected.to eq([]) }
424
401
  end
425
402
  end
@@ -429,8 +406,8 @@ describe Statesman::Machine do
429
406
  let(:last_action) { "Whatever" }
430
407
 
431
408
  it "delegates to the storage adapter" do
432
- expect_any_instance_of(Statesman.storage_adapter).to receive(:last).once
433
- .and_return(last_action)
409
+ expect_any_instance_of(Statesman.storage_adapter).to receive(:last).once.
410
+ and_return(last_action)
434
411
  expect(instance.last_transition).to be(last_action)
435
412
  end
436
413
  end
@@ -499,9 +476,8 @@ describe Statesman::Machine do
499
476
 
500
477
  context "when the state cannot be transitioned to" do
501
478
  it "raises an error" do
502
- expect do
503
- instance.transition_to!(:z)
504
- end.to raise_error(Statesman::TransitionFailedError)
479
+ expect { instance.transition_to!(:z) }.
480
+ to raise_error(Statesman::TransitionFailedError)
505
481
  end
506
482
  end
507
483
 
@@ -512,12 +488,11 @@ describe Statesman::Machine do
512
488
  end
513
489
 
514
490
  it "creates a new transition object" do
515
- expect do
516
- instance.transition_to!(:y)
517
- end.to change(instance.history, :count).by(1)
491
+ expect { instance.transition_to!(:y) }.
492
+ to change(instance.history, :count).by(1)
518
493
 
519
- expect(instance.history.first)
520
- .to be_a(Statesman::Adapters::MemoryTransition)
494
+ expect(instance.history.first).
495
+ to be_a(Statesman::Adapters::MemoryTransition)
521
496
  expect(instance.history.first.to_state).to eq("y")
522
497
  end
523
498
 
@@ -532,9 +507,7 @@ describe Statesman::Machine do
532
507
  expect(instance.history.first.metadata).to eq({})
533
508
  end
534
509
 
535
- it "returns true" do
536
- expect(instance.transition_to!(:y)).to be_truthy
537
- end
510
+ specify { expect(instance.transition_to!(:y)).to be_truthy }
538
511
 
539
512
  context "with a guard" do
540
513
  let(:result) { true }
@@ -545,8 +518,8 @@ describe Statesman::Machine do
545
518
  let(:instance) { machine.new(my_model) }
546
519
 
547
520
  it "passes the object to the guard" do
548
- expect(guard_cb).to receive(:call).once
549
- .with(my_model, instance.last_transition, {}).and_return(true)
521
+ expect(guard_cb).to receive(:call).once.
522
+ with(my_model, instance.last_transition, {}).and_return(true)
550
523
  instance.transition_to!(:y)
551
524
  end
552
525
  end
@@ -562,9 +535,8 @@ describe Statesman::Machine do
562
535
  let(:result) { false }
563
536
 
564
537
  it "raises an exception" do
565
- expect do
566
- instance.transition_to!(:y)
567
- end.to raise_error(Statesman::GuardFailedError)
538
+ expect { instance.transition_to!(:y) }.
539
+ to raise_error(Statesman::GuardFailedError)
568
540
  end
569
541
  end
570
542
  end
@@ -578,32 +550,29 @@ describe Statesman::Machine do
578
550
 
579
551
  context "when it is succesful" do
580
552
  before do
581
- expect(instance).to receive(:transition_to!).once
582
- .with(:some_state, metadata).and_return(:some_state)
553
+ expect(instance).to receive(:transition_to!).once.
554
+ with(:some_state, metadata).and_return(:some_state)
583
555
  end
584
556
  it { is_expected.to be(:some_state) }
585
557
  end
586
558
 
587
559
  context "when it is unsuccesful" do
588
560
  before do
589
- allow(instance).to receive(:transition_to!)
590
- .and_raise(Statesman::GuardFailedError)
561
+ allow(instance).to receive(:transition_to!).
562
+ and_raise(Statesman::GuardFailedError)
591
563
  end
592
564
  it { is_expected.to be_falsey }
593
565
  end
594
566
 
595
567
  context "when a non statesman exception is raised" do
596
568
  before do
597
- allow(instance).to receive(:transition_to!)
598
- .and_raise(RuntimeError, 'user defined exception')
569
+ allow(instance).to receive(:transition_to!).
570
+ and_raise(RuntimeError, 'user defined exception')
599
571
  end
600
572
 
601
573
  it "should not rescue the exception" do
602
- expectation = expect do
603
- instance.transition_to(:some_state, metadata)
604
- end
605
-
606
- expectation.to raise_error(RuntimeError, 'user defined exception')
574
+ expect { instance.transition_to(:some_state, metadata) }.
575
+ to raise_error(RuntimeError, 'user defined exception')
607
576
  end
608
577
  end
609
578
  end
@@ -650,13 +619,11 @@ describe Statesman::Machine do
650
619
  end
651
620
 
652
621
  describe "#before_callbacks_for" do
653
- it_behaves_like "a callback filter", :before_transition,
654
- :before
622
+ it_behaves_like "a callback filter", :before_transition, :before
655
623
  end
656
624
 
657
625
  describe "#after_callbacks_for" do
658
- it_behaves_like "a callback filter", :after_transition,
659
- :after
626
+ it_behaves_like "a callback filter", :after_transition, :after
660
627
  end
661
628
 
662
629
  describe "#event" do
@@ -680,9 +647,8 @@ describe Statesman::Machine do
680
647
 
681
648
  context "when the state cannot be transitioned to" do
682
649
  it "raises an error" do
683
- expect do
684
- instance.trigger!(:event_2)
685
- end.to raise_error(Statesman::TransitionFailedError)
650
+ expect { instance.trigger!(:event_2) }.
651
+ to raise_error(Statesman::TransitionFailedError)
686
652
  end
687
653
  end
688
654
 
@@ -693,12 +659,11 @@ describe Statesman::Machine do
693
659
  end
694
660
 
695
661
  it "creates a new transition object" do
696
- expect do
697
- instance.trigger!(:event_1)
698
- end.to change(instance.history, :count).by(1)
662
+ expect { instance.trigger!(:event_1) }.
663
+ to change(instance.history, :count).by(1)
699
664
 
700
- expect(instance.history.first)
701
- .to be_a(Statesman::Adapters::MemoryTransition)
665
+ expect(instance.history.first).
666
+ to be_a(Statesman::Adapters::MemoryTransition)
702
667
  expect(instance.history.first.to_state).to eq("y")
703
668
  end
704
669
 
@@ -728,16 +693,16 @@ describe Statesman::Machine do
728
693
  let(:instance) { machine.new(my_model) }
729
694
 
730
695
  it "passes the object to the guard" do
731
- expect(guard_cb).to receive(:call).once
732
- .with(my_model, instance.last_transition, {}).and_return(true)
696
+ expect(guard_cb).to receive(:call).once.
697
+ with(my_model, instance.last_transition, {}).and_return(true)
733
698
  instance.trigger!(:event_1)
734
699
  end
735
700
  end
736
701
 
737
702
  context "which passes" do
738
703
  it "changes state" do
739
- instance.trigger!(:event_1)
740
- expect(instance.current_state).to eq("y")
704
+ expect { instance.trigger!(:event_1) }.
705
+ to change { instance.current_state }.to("y")
741
706
  end
742
707
  end
743
708
 
@@ -745,14 +710,12 @@ describe Statesman::Machine do
745
710
  let(:result) { false }
746
711
 
747
712
  it "raises an exception" do
748
- expect do
749
- instance.trigger!(:event_1)
750
- end.to raise_error(Statesman::GuardFailedError)
713
+ expect { instance.trigger!(:event_1) }.
714
+ to raise_error(Statesman::GuardFailedError)
751
715
  end
752
716
  end
753
717
  end
754
718
  end
755
-
756
719
  end
757
720
 
758
721
  describe "#available_events" do
@@ -784,5 +747,4 @@ describe Statesman::Machine do
784
747
  expect(instance.available_events).to eq([:event_2, :event_3])
785
748
  end
786
749
  end
787
-
788
750
  end