statesman 3.4.1 → 3.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (34) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +9 -9
  3. data/.rubocop_todo.yml +67 -2
  4. data/CHANGELOG.md +7 -0
  5. data/Gemfile +0 -4
  6. data/README.md +15 -1
  7. data/lib/generators/statesman/active_record_transition_generator.rb +1 -1
  8. data/lib/generators/statesman/migration_generator.rb +1 -1
  9. data/lib/generators/statesman/mongoid_transition_generator.rb +1 -1
  10. data/lib/generators/statesman/templates/create_migration.rb.erb +3 -3
  11. data/lib/generators/statesman/templates/update_migration.rb.erb +2 -2
  12. data/lib/statesman/adapters/active_record.rb +3 -3
  13. data/lib/statesman/adapters/active_record_queries.rb +7 -7
  14. data/lib/statesman/adapters/memory.rb +2 -2
  15. data/lib/statesman/adapters/mongoid.rb +1 -1
  16. data/lib/statesman/config.rb +0 -1
  17. data/lib/statesman/machine.rb +1 -1
  18. data/lib/statesman/version.rb +1 -1
  19. data/spec/generators/statesman/active_record_transition_generator_spec.rb +14 -9
  20. data/spec/generators/statesman/migration_generator_spec.rb +9 -9
  21. data/spec/generators/statesman/mongoid_transition_generator_spec.rb +7 -5
  22. data/spec/statesman/adapters/active_record_queries_spec.rb +17 -15
  23. data/spec/statesman/adapters/active_record_spec.rb +14 -4
  24. data/spec/statesman/adapters/memory_spec.rb +1 -0
  25. data/spec/statesman/{transition_spec.rb → adapters/memory_transition_spec.rb} +0 -0
  26. data/spec/statesman/adapters/mongoid_spec.rb +5 -1
  27. data/spec/statesman/adapters/shared_examples.rb +18 -9
  28. data/spec/statesman/callback_spec.rb +18 -6
  29. data/spec/statesman/config_spec.rb +6 -3
  30. data/spec/statesman/guard_spec.rb +3 -1
  31. data/spec/statesman/machine_spec.rb +52 -14
  32. data/spec/support/generators_shared_examples.rb +3 -1
  33. data/statesman.gemspec +12 -12
  34. metadata +23 -23
@@ -4,18 +4,20 @@ require "generators/statesman/mongoid_transition_generator"
4
4
 
5
5
  describe Statesman::MongoidTransitionGenerator, type: :generator do
6
6
  describe "the model contains the correct words" do
7
- before { run_generator %w[Yummy::Bacon Yummy::BaconTransition] }
8
7
  subject { file("app/models/yummy/bacon_transition.rb") }
9
8
 
10
- it { is_expected.not_to contain(%r{:yummy/bacon}) }
9
+ before { run_generator %w[Yummy::Bacon Yummy::BaconTransition] }
10
+
11
+ it { is_expected.to_not contain(%r{:yummy/bacon}) }
11
12
  it { is_expected.to contain(/class_name: 'Yummy::Bacon'/) }
12
13
  end
13
14
 
14
15
  describe "the model contains the correct words" do
15
- before { run_generator %w[Bacon BaconTransition] }
16
16
  subject { file("app/models/bacon_transition.rb") }
17
17
 
18
- it { is_expected.not_to contain(/class_name:/) }
19
- it { is_expected.not_to contain(/CreateYummy::Bacon/) }
18
+ before { run_generator %w[Bacon BaconTransition] }
19
+
20
+ it { is_expected.to_not contain(/class_name:/) }
21
+ it { is_expected.to_not contain(/CreateYummy::Bacon/) }
20
22
  end
21
23
  end
@@ -6,14 +6,9 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
6
6
  prepare_transitions_table
7
7
  prepare_other_model_table
8
8
  prepare_other_transitions_table
9
- end
10
9
 
11
- before do
12
10
  Statesman.configure { storage_adapter(Statesman::Adapters::ActiveRecord) }
13
- end
14
- after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } }
15
11
 
16
- before do
17
12
  MyActiveRecordModel.send(:include, Statesman::Adapters::ActiveRecordQueries)
18
13
  MyActiveRecordModel.class_eval do
19
14
  def self.transition_class
@@ -36,9 +31,12 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
36
31
  :initial
37
32
  end
38
33
  end
34
+
35
+ MyActiveRecordModel.send(:has_one, :other_active_record_model)
36
+ OtherActiveRecordModel.send(:belongs_to, :my_active_record_model)
39
37
  end
40
- before { MyActiveRecordModel.send(:has_one, :other_active_record_model) }
41
- before { OtherActiveRecordModel.send(:belongs_to, :my_active_record_model) }
38
+
39
+ after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } }
42
40
 
43
41
  let!(:model) do
44
42
  model = MyActiveRecordModel.create
@@ -66,7 +64,7 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
66
64
  subject { MyActiveRecordModel.in_state(:succeeded) }
67
65
 
68
66
  it { is_expected.to include model }
69
- it { is_expected.not_to include other_model }
67
+ it { is_expected.to_not include other_model }
70
68
  end
71
69
 
72
70
  context "given multiple states" do
@@ -104,23 +102,26 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
104
102
  describe ".not_in_state" do
105
103
  context "given a single state" do
106
104
  subject { MyActiveRecordModel.not_in_state(:failed) }
105
+
107
106
  it { is_expected.to include model }
108
- it { is_expected.not_to include other_model }
107
+ it { is_expected.to_not include other_model }
109
108
  end
110
109
 
111
110
  context "given multiple states" do
112
- subject { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
111
+ subject(:not_in_state) { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
112
+
113
113
  it do
114
- is_expected.to match_array([initial_state_model,
115
- returned_to_initial_model])
114
+ expect(not_in_state).to match_array([initial_state_model,
115
+ returned_to_initial_model])
116
116
  end
117
117
  end
118
118
 
119
119
  context "given an array of states" do
120
- subject { MyActiveRecordModel.not_in_state(%i[succeeded failed]) }
120
+ subject(:not_in_state) { MyActiveRecordModel.not_in_state(%i[succeeded failed]) }
121
+
121
122
  it do
122
- is_expected.to match_array([initial_state_model,
123
- returned_to_initial_model])
123
+ expect(not_in_state).to match_array([initial_state_model,
124
+ returned_to_initial_model])
124
125
  end
125
126
  end
126
127
  end
@@ -143,6 +144,7 @@ describe Statesman::Adapters::ActiveRecordQueries, active_record: true do
143
144
 
144
145
  describe ".in_state" do
145
146
  subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
147
+
146
148
  specify { expect { query }.to_not raise_error }
147
149
  end
148
150
  end
@@ -10,8 +10,10 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
10
10
  end
11
11
 
12
12
  before { MyActiveRecordModelTransition.serialize(:metadata, JSON) }
13
+
13
14
  let(:observer) { double(Statesman::Machine, execute: nil) }
14
15
  let(:model) { MyActiveRecordModel.create(current_state: :pending) }
16
+
15
17
  it_behaves_like "an adapter", described_class, MyActiveRecordModelTransition
16
18
 
17
19
  describe "#initialize" do
@@ -98,13 +100,14 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
98
100
  end
99
101
 
100
102
  describe "#create" do
103
+ subject { -> { create } }
104
+
101
105
  let!(:adapter) do
102
106
  described_class.new(MyActiveRecordModelTransition, model, observer)
103
107
  end
104
108
  let(:from) { :x }
105
109
  let(:to) { :y }
106
110
  let(:create) { adapter.create(from, to) }
107
- subject { -> { create } }
108
111
 
109
112
  context "when there is a race" do
110
113
  it "raises a TransitionConflictError" do
@@ -132,11 +135,13 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
132
135
  ActiveRecord::RecordNotUnique.new("unrelated", nil)
133
136
  end
134
137
  end
138
+
135
139
  it { is_expected.to raise_exception(ActiveRecord::RecordNotUnique) }
136
140
  end
137
141
 
138
142
  context "other errors" do
139
143
  let(:error) { StandardError }
144
+
140
145
  it { is_expected.to raise_exception(StandardError) }
141
146
  end
142
147
  end
@@ -150,6 +155,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
150
155
 
151
156
  context "with a previous transition" do
152
157
  let!(:previous_transition) { adapter.create(from, to) }
158
+
153
159
  its(:most_recent) { is_expected.to eq(true) }
154
160
 
155
161
  it "updates the previous transition's most_recent flag" do
@@ -248,6 +254,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
248
254
  context "with two previous transitions" do
249
255
  let!(:previous_transition) { adapter.create(from, to) }
250
256
  let!(:another_previous_transition) { adapter.create(from, to) }
257
+
251
258
  its(:most_recent) { is_expected.to eq(true) }
252
259
 
253
260
  it "updates the previous transition's most_recent flag" do
@@ -271,12 +278,13 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
271
278
 
272
279
  it "caches the transition" do
273
280
  expect_any_instance_of(MyActiveRecordModel).
274
- to receive(:my_active_record_model_transitions).never
281
+ to_not receive(:my_active_record_model_transitions)
275
282
  adapter.last
276
283
  end
277
284
 
278
285
  context "after then creating a new transition" do
279
286
  before { adapter.create(:y, :z, []) }
287
+
280
288
  it "retrieves the new transition from the database" do
281
289
  expect(adapter.last.to_state).to eq("z")
282
290
  end
@@ -291,7 +299,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
291
299
  alternate_adapter.create(:y, :z, [])
292
300
 
293
301
  expect_any_instance_of(MyActiveRecordModel).
294
- to receive(:my_active_record_model_transitions).never
302
+ to_not receive(:my_active_record_model_transitions)
295
303
  expect(adapter.last.to_state).to eq("y")
296
304
  end
297
305
 
@@ -323,10 +331,11 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
323
331
 
324
332
  context "with a pre-fetched transition history" do
325
333
  before { adapter.create(:x, :y) }
334
+
326
335
  before { model.my_active_record_model_transitions.load_target }
327
336
 
328
337
  it "doesn't query the database" do
329
- expect(MyActiveRecordModelTransition).not_to receive(:connection)
338
+ expect(MyActiveRecordModelTransition).to_not receive(:connection)
330
339
  expect(adapter.last.to_state).to eq("y")
331
340
  end
332
341
  end
@@ -341,6 +350,7 @@ describe Statesman::Adapters::ActiveRecord, active_record: true do
341
350
  before do
342
351
  MyNamespace::MyActiveRecordModelTransition.serialize(:metadata, JSON)
343
352
  end
353
+
344
354
  let(:observer) { double(Statesman::Machine, execute: nil) }
345
355
  let(:model) do
346
356
  MyNamespace::MyActiveRecordModel.create(current_state: :pending)
@@ -4,6 +4,7 @@ require "statesman/adapters/memory_transition"
4
4
 
5
5
  describe Statesman::Adapters::Memory do
6
6
  let(:model) { Class.new { attr_accessor :current_state }.new }
7
+
7
8
  it_behaves_like "an adapter", described_class,
8
9
  Statesman::Adapters::MemoryTransition
9
10
  end
@@ -6,8 +6,10 @@ require "mongoid"
6
6
 
7
7
  describe Statesman::Adapters::Mongoid, mongo: true do
8
8
  after { Mongoid.purge! }
9
+
9
10
  let(:observer) { double(Statesman::Machine, execute: nil) }
10
11
  let(:model) { MyMongoidModel.create(current_state: :pending) }
12
+
11
13
  it_behaves_like "an adapter", described_class, MyMongoidModelTransition
12
14
 
13
15
  describe "#initialize" do
@@ -33,16 +35,18 @@ describe Statesman::Adapters::Mongoid, mongo: true do
33
35
 
34
36
  context "with a previously looked up transition" do
35
37
  before { adapter.create(:x, :y) }
38
+
36
39
  before { adapter.last }
37
40
 
38
41
  it "caches the transition" do
39
42
  expect_any_instance_of(MyMongoidModel).
40
- to receive(:my_mongoid_model_transitions).never
43
+ to_not receive(:my_mongoid_model_transitions)
41
44
  adapter.last
42
45
  end
43
46
 
44
47
  context "and a new transition" do
45
48
  before { adapter.create(:y, :z) }
49
+
46
50
  it "retrieves the new transition from the database" do
47
51
  expect(adapter.last.to_state).to eq("z")
48
52
  end
@@ -13,8 +13,6 @@ require "spec_helper"
13
13
  #
14
14
  # NOTE This line cannot reasonably be shortened.
15
15
  shared_examples_for "an adapter" do |adapter_class, transition_class, options = {}|
16
- # rubocop:enable Metrics/LineLength
17
-
18
16
  let(:observer) { double(Statesman::Machine, execute: nil) }
19
17
  let(:adapter) do
20
18
  adapter_class.new(transition_class,
@@ -23,26 +21,29 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
23
21
 
24
22
  describe "#initialize" do
25
23
  subject { adapter }
24
+
26
25
  its(:transition_class) { is_expected.to be(transition_class) }
27
26
  its(:parent_model) { is_expected.to be(model) }
28
27
  its(:history) { is_expected.to eq([]) }
29
28
  end
30
29
 
31
30
  describe "#create" do
31
+ subject { -> { create } }
32
+
32
33
  let(:from) { :x }
33
34
  let(:to) { :y }
34
35
  let(:there) { :z }
35
36
  let(:create) { adapter.create(from, to) }
36
- subject { -> { create } }
37
37
 
38
38
  it { is_expected.to change(adapter.history, :count).by(1) }
39
39
 
40
40
  context "the new transition" do
41
- subject { create }
41
+ subject(:instance) { create }
42
+
42
43
  it { is_expected.to be_a(transition_class) }
43
44
 
44
- it "should have the initial state" do
45
- expect(subject.to_state.to_sym).to eq(to)
45
+ it "has the initial state" do
46
+ expect(instance.to_state.to_sym).to eq(to)
46
47
  end
47
48
 
48
49
  context "with no previous transition" do
@@ -51,6 +52,7 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
51
52
 
52
53
  context "with a previous transition" do
53
54
  before { adapter.create(from, to) }
55
+
54
56
  its(:sort_key) { is_expected.to be(20) }
55
57
  end
56
58
  end
@@ -87,33 +89,40 @@ shared_examples_for "an adapter" do |adapter_class, transition_class, options =
87
89
  end
88
90
 
89
91
  context "with metadata" do
90
- let(:metadata) { { "some" => "hash" } }
91
92
  subject { adapter.create(from, to, metadata) }
93
+
94
+ let(:metadata) { { "some" => "hash" } }
95
+
92
96
  its(:metadata) { is_expected.to eq(metadata) }
93
97
  end
94
98
  end
95
99
 
96
100
  describe "#history" do
97
101
  subject { adapter.history }
102
+
98
103
  it { is_expected.to eq([]) }
99
104
 
100
105
  context "with transitions" do
101
106
  let!(:transition) { adapter.create(:x, :y) }
107
+
102
108
  it { is_expected.to eq([transition]) }
103
109
 
104
110
  context "sorting" do
105
- let!(:transition2) { adapter.create(:x, :y) }
106
111
  subject { adapter.history }
107
112
 
113
+ let!(:transition2) { adapter.create(:x, :y) }
114
+
108
115
  it { is_expected.to eq(adapter.history.sort_by(&:sort_key)) }
109
116
  end
110
117
  end
111
118
  end
112
119
 
113
120
  describe "#last" do
121
+ subject { adapter.last }
122
+
114
123
  before { adapter.create(:x, :y) }
124
+
115
125
  before { adapter.create(:y, :z) }
116
- subject { adapter.last }
117
126
 
118
127
  it { is_expected.to be_a(transition_class) }
119
128
  specify { expect(adapter.last.to_state.to_sym).to eq(:z) }
@@ -3,7 +3,7 @@ require "spec_helper"
3
3
  describe Statesman::Callback do
4
4
  let(:cb_lambda) { -> {} }
5
5
  let(:callback) do
6
- Statesman::Callback.new(from: nil, to: nil, callback: cb_lambda)
6
+ described_class.new(from: nil, to: nil, callback: cb_lambda)
7
7
  end
8
8
 
9
9
  describe "#initialize" do
@@ -27,21 +27,24 @@ describe Statesman::Callback do
27
27
  end
28
28
 
29
29
  describe "#applies_to" do
30
+ subject { callback.applies_to?(from: from, to: to) }
31
+
30
32
  let(:callback) do
31
- Statesman::Callback.new(from: :x, to: :y, callback: cb_lambda)
33
+ described_class.new(from: :x, to: :y, callback: cb_lambda)
32
34
  end
33
- subject { callback.applies_to?(from: from, to: to) }
34
35
 
35
36
  context "with any from value" do
36
37
  let(:from) { nil }
37
38
 
38
39
  context "and an allowed to value" do
39
40
  let(:to) { :y }
41
+
40
42
  it { is_expected.to be_truthy }
41
43
  end
42
44
 
43
45
  context "and a disallowed to value" do
44
46
  let(:to) { :a }
47
+
45
48
  it { is_expected.to be_falsey }
46
49
  end
47
50
  end
@@ -51,17 +54,19 @@ describe Statesman::Callback do
51
54
 
52
55
  context "and an allowed 'from' value" do
53
56
  let(:from) { :x }
57
+
54
58
  it { is_expected.to be_truthy }
55
59
  end
56
60
 
57
61
  context "and a disallowed 'from' value" do
58
62
  let(:from) { :a }
63
+
59
64
  it { is_expected.to be_falsey }
60
65
  end
61
66
  end
62
67
 
63
68
  context "with any to and any from value on the callback" do
64
- let(:callback) { Statesman::Callback.new(callback: cb_lambda) }
69
+ let(:callback) { described_class.new(callback: cb_lambda) }
65
70
  let(:from) { :x }
66
71
  let(:to) { :y }
67
72
 
@@ -70,37 +75,42 @@ describe Statesman::Callback do
70
75
 
71
76
  context "with any from value on the callback" do
72
77
  let(:callback) do
73
- Statesman::Callback.new(to: %i[y z], callback: cb_lambda)
78
+ described_class.new(to: %i[y z], callback: cb_lambda)
74
79
  end
75
80
  let(:from) { :x }
76
81
 
77
82
  context "and an allowed to value" do
78
83
  let(:to) { :y }
84
+
79
85
  it { is_expected.to be_truthy }
80
86
  end
81
87
 
82
88
  context "and another allowed to value" do
83
89
  let(:to) { :z }
90
+
84
91
  it { is_expected.to be_truthy }
85
92
  end
86
93
 
87
94
  context "and a disallowed to value" do
88
95
  let(:to) { :a }
96
+
89
97
  it { is_expected.to be_falsey }
90
98
  end
91
99
  end
92
100
 
93
101
  context "with any to value on the callback" do
94
- let(:callback) { Statesman::Callback.new(from: :x, callback: cb_lambda) }
102
+ let(:callback) { described_class.new(from: :x, callback: cb_lambda) }
95
103
  let(:to) { :y }
96
104
 
97
105
  context "and an allowed to value" do
98
106
  let(:from) { :x }
107
+
99
108
  it { is_expected.to be_truthy }
100
109
  end
101
110
 
102
111
  context "and a disallowed to value" do
103
112
  let(:from) { :a }
113
+
104
114
  it { is_expected.to be_falsey }
105
115
  end
106
116
  end
@@ -108,12 +118,14 @@ describe Statesman::Callback do
108
118
  context "with allowed 'from' and 'to' values" do
109
119
  let(:from) { :x }
110
120
  let(:to) { :y }
121
+
111
122
  it { is_expected.to be_truthy }
112
123
  end
113
124
 
114
125
  context "with disallowed 'from' and 'to' values" do
115
126
  let(:from) { :a }
116
127
  let(:to) { :b }
128
+
117
129
  it { is_expected.to be_falsey }
118
130
  end
119
131
  end