statesman 7.4.0 → 12.1.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 (49) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +7 -0
  3. data/.github/workflows/tests.yml +112 -0
  4. data/.gitignore +65 -15
  5. data/.rspec +1 -0
  6. data/.rubocop.yml +14 -1
  7. data/.rubocop_todo.yml +37 -28
  8. data/.ruby-version +1 -0
  9. data/CHANGELOG.md +262 -41
  10. data/CONTRIBUTING.md +23 -4
  11. data/Gemfile +4 -6
  12. data/README.md +243 -43
  13. data/docs/COMPATIBILITY.md +2 -2
  14. data/lib/generators/statesman/active_record_transition_generator.rb +1 -1
  15. data/lib/generators/statesman/generator_helpers.rb +12 -4
  16. data/lib/statesman/adapters/active_record.rb +84 -55
  17. data/lib/statesman/adapters/active_record_queries.rb +19 -7
  18. data/lib/statesman/adapters/active_record_transition.rb +5 -1
  19. data/lib/statesman/adapters/memory.rb +5 -1
  20. data/lib/statesman/adapters/type_safe_active_record_queries.rb +21 -0
  21. data/lib/statesman/callback.rb +2 -2
  22. data/lib/statesman/config.rb +3 -10
  23. data/lib/statesman/exceptions.rb +13 -7
  24. data/lib/statesman/guard.rb +1 -1
  25. data/lib/statesman/machine.rb +68 -0
  26. data/lib/statesman/version.rb +1 -1
  27. data/lib/statesman.rb +5 -5
  28. data/lib/tasks/statesman.rake +5 -5
  29. data/spec/generators/statesman/active_record_transition_generator_spec.rb +7 -1
  30. data/spec/generators/statesman/migration_generator_spec.rb +5 -1
  31. data/spec/spec_helper.rb +44 -7
  32. data/spec/statesman/adapters/active_record_queries_spec.rb +34 -12
  33. data/spec/statesman/adapters/active_record_spec.rb +176 -51
  34. data/spec/statesman/adapters/active_record_transition_spec.rb +5 -2
  35. data/spec/statesman/adapters/memory_spec.rb +0 -1
  36. data/spec/statesman/adapters/memory_transition_spec.rb +0 -1
  37. data/spec/statesman/adapters/shared_examples.rb +3 -4
  38. data/spec/statesman/adapters/type_safe_active_record_queries_spec.rb +206 -0
  39. data/spec/statesman/callback_spec.rb +0 -2
  40. data/spec/statesman/config_spec.rb +0 -2
  41. data/spec/statesman/exceptions_spec.rb +17 -4
  42. data/spec/statesman/guard_spec.rb +0 -2
  43. data/spec/statesman/machine_spec.rb +252 -15
  44. data/spec/statesman/utils_spec.rb +0 -2
  45. data/spec/support/active_record.rb +156 -24
  46. data/spec/support/exactly_query_databases.rb +35 -0
  47. data/statesman.gemspec +9 -10
  48. metadata +32 -59
  49. data/.circleci/config.yml +0 -187
@@ -0,0 +1,206 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe Statesman::Adapters::TypeSafeActiveRecordQueries, :active_record do
4
+ def configure(klass, transition_class)
5
+ klass.send(:extend, described_class)
6
+ klass.configure_state_machine(
7
+ transition_class: transition_class,
8
+ initial_state: :initial,
9
+ )
10
+ end
11
+
12
+ before do
13
+ prepare_model_table
14
+ prepare_transitions_table
15
+ prepare_other_model_table
16
+ prepare_other_transitions_table
17
+
18
+ Statesman.configure do
19
+ storage_adapter(Statesman::Adapters::ActiveRecord)
20
+ end
21
+ end
22
+
23
+ after { Statesman.configure { storage_adapter(Statesman::Adapters::Memory) } }
24
+
25
+ let!(:model) do
26
+ model = MyActiveRecordModel.create
27
+ model.state_machine.transition_to(:succeeded)
28
+ model
29
+ end
30
+
31
+ let!(:other_model) do
32
+ model = MyActiveRecordModel.create
33
+ model.state_machine.transition_to(:failed)
34
+ model
35
+ end
36
+
37
+ let!(:initial_state_model) { MyActiveRecordModel.create }
38
+
39
+ let!(:returned_to_initial_model) do
40
+ model = MyActiveRecordModel.create
41
+ model.state_machine.transition_to(:failed)
42
+ model.state_machine.transition_to(:initial)
43
+ model
44
+ end
45
+
46
+ shared_examples "testing methods" do
47
+ before do
48
+ configure(MyActiveRecordModel, MyActiveRecordModelTransition)
49
+ configure(OtherActiveRecordModel, OtherActiveRecordModelTransition)
50
+
51
+ MyActiveRecordModel.send(:has_one, :other_active_record_model)
52
+ OtherActiveRecordModel.send(:belongs_to, :my_active_record_model)
53
+ end
54
+
55
+ describe ".in_state" do
56
+ context "given a single state" do
57
+ subject { MyActiveRecordModel.in_state(:succeeded) }
58
+
59
+ it { is_expected.to include model }
60
+ it { is_expected.to_not include other_model }
61
+ end
62
+
63
+ context "given multiple states" do
64
+ subject { MyActiveRecordModel.in_state(:succeeded, :failed) }
65
+
66
+ it { is_expected.to include model }
67
+ it { is_expected.to include other_model }
68
+ end
69
+
70
+ context "given the initial state" do
71
+ subject { MyActiveRecordModel.in_state(:initial) }
72
+
73
+ it { is_expected.to include initial_state_model }
74
+ it { is_expected.to include returned_to_initial_model }
75
+ end
76
+
77
+ context "given an array of states" do
78
+ subject { MyActiveRecordModel.in_state(%i[succeeded failed]) }
79
+
80
+ it { is_expected.to include model }
81
+ it { is_expected.to include other_model }
82
+ end
83
+
84
+ context "merging two queries" do
85
+ subject do
86
+ MyActiveRecordModel.in_state(:succeeded).
87
+ joins(:other_active_record_model).
88
+ merge(OtherActiveRecordModel.in_state(:initial))
89
+ end
90
+
91
+ it { is_expected.to be_empty }
92
+ end
93
+ end
94
+
95
+ describe ".not_in_state" do
96
+ context "given a single state" do
97
+ subject { MyActiveRecordModel.not_in_state(:failed) }
98
+
99
+ it { is_expected.to include model }
100
+ it { is_expected.to_not include other_model }
101
+ end
102
+
103
+ context "given multiple states" do
104
+ subject(:not_in_state) { MyActiveRecordModel.not_in_state(:succeeded, :failed) }
105
+
106
+ it do
107
+ expect(not_in_state).to contain_exactly(initial_state_model,
108
+ returned_to_initial_model)
109
+ end
110
+ end
111
+
112
+ context "given an array of states" do
113
+ subject(:not_in_state) { MyActiveRecordModel.not_in_state(%i[succeeded failed]) }
114
+
115
+ it do
116
+ expect(not_in_state).to contain_exactly(initial_state_model,
117
+ returned_to_initial_model)
118
+ end
119
+ end
120
+ end
121
+
122
+ context "with a custom name for the transition association" do
123
+ before do
124
+ # Switch to using OtherActiveRecordModelTransition, so the existing
125
+ # relation with MyActiveRecordModelTransition doesn't interfere with
126
+ # this spec.
127
+ MyActiveRecordModel.send(:has_many,
128
+ :custom_name,
129
+ class_name: "OtherActiveRecordModelTransition")
130
+
131
+ MyActiveRecordModel.class_eval do
132
+ def self.transition_class
133
+ OtherActiveRecordModelTransition
134
+ end
135
+ end
136
+ end
137
+
138
+ describe ".in_state" do
139
+ subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
140
+
141
+ specify { expect { query }.to_not raise_error }
142
+ end
143
+ end
144
+
145
+ context "with a custom primary key for the model" do
146
+ before do
147
+ # Switch to using OtherActiveRecordModelTransition, so the existing
148
+ # relation with MyActiveRecordModelTransition doesn't interfere with
149
+ # this spec.
150
+ # Configure the relationship to use a different primary key,
151
+ MyActiveRecordModel.send(:has_many,
152
+ :custom_name,
153
+ class_name: "OtherActiveRecordModelTransition",
154
+ primary_key: :external_id)
155
+
156
+ MyActiveRecordModel.class_eval do
157
+ def self.transition_class
158
+ OtherActiveRecordModelTransition
159
+ end
160
+ end
161
+ end
162
+
163
+ describe ".in_state" do
164
+ subject(:query) { MyActiveRecordModel.in_state(:succeeded) }
165
+
166
+ specify { expect { query }.to_not raise_error }
167
+ end
168
+ end
169
+
170
+ context "after_commit transactional integrity" do
171
+ before do
172
+ MyStateMachine.class_eval do
173
+ cattr_accessor(:after_commit_callback_executed) { false }
174
+
175
+ after_transition(from: :initial, to: :succeeded, after_commit: true) do
176
+ # This leaks state in a testable way if transactional integrity is broken.
177
+ MyStateMachine.after_commit_callback_executed = true
178
+ end
179
+ end
180
+ end
181
+
182
+ after do
183
+ MyStateMachine.class_eval do
184
+ callbacks[:after_commit] = []
185
+ end
186
+ end
187
+
188
+ let!(:model) do
189
+ MyActiveRecordModel.create
190
+ end
191
+
192
+ it do
193
+ expect do
194
+ ActiveRecord::Base.transaction do
195
+ model.state_machine.transition_to!(:succeeded)
196
+ raise ActiveRecord::Rollback
197
+ end
198
+ end.to_not change(MyStateMachine, :after_commit_callback_executed)
199
+ end
200
+ end
201
+ end
202
+
203
+ context "using configuration method" do
204
+ include_examples "testing methods"
205
+ end
206
+ end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Statesman::Callback do
6
4
  let(:cb_lambda) { -> {} }
7
5
  let(:callback) do
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Statesman::Config do
6
4
  let(:instance) { described_class.new }
7
5
 
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
- describe Statesman do
3
+ describe "Exceptions" do
6
4
  describe "InvalidStateError" do
7
5
  subject(:error) { Statesman::InvalidStateError.new }
8
6
 
9
7
  its(:message) { is_expected.to eq("Statesman::InvalidStateError") }
8
+
10
9
  its "string matches its message" do
11
10
  expect(error.to_s).to eq(error.message)
12
11
  end
@@ -16,6 +15,7 @@ describe Statesman do
16
15
  subject(:error) { Statesman::InvalidTransitionError.new }
17
16
 
18
17
  its(:message) { is_expected.to eq("Statesman::InvalidTransitionError") }
18
+
19
19
  its "string matches its message" do
20
20
  expect(error.to_s).to eq(error.message)
21
21
  end
@@ -25,6 +25,7 @@ describe Statesman do
25
25
  subject(:error) { Statesman::InvalidTransitionError.new }
26
26
 
27
27
  its(:message) { is_expected.to eq("Statesman::InvalidTransitionError") }
28
+
28
29
  its "string matches its message" do
29
30
  expect(error.to_s).to eq(error.message)
30
31
  end
@@ -34,6 +35,7 @@ describe Statesman do
34
35
  subject(:error) { Statesman::TransitionConflictError.new }
35
36
 
36
37
  its(:message) { is_expected.to eq("Statesman::TransitionConflictError") }
38
+
37
39
  its "string matches its message" do
38
40
  expect(error.to_s).to eq(error.message)
39
41
  end
@@ -43,6 +45,7 @@ describe Statesman do
43
45
  subject(:error) { Statesman::MissingTransitionAssociation.new }
44
46
 
45
47
  its(:message) { is_expected.to eq("Statesman::MissingTransitionAssociation") }
48
+
46
49
  its "string matches its message" do
47
50
  expect(error.to_s).to eq(error.message)
48
51
  end
@@ -52,17 +55,25 @@ describe Statesman do
52
55
  subject(:error) { Statesman::TransitionFailedError.new("from", "to") }
53
56
 
54
57
  its(:message) { is_expected.to eq("Cannot transition from 'from' to 'to'") }
58
+
55
59
  its "string matches its message" do
56
60
  expect(error.to_s).to eq(error.message)
57
61
  end
58
62
  end
59
63
 
60
64
  describe "GuardFailedError" do
61
- subject(:error) { Statesman::GuardFailedError.new("from", "to") }
65
+ subject(:error) { Statesman::GuardFailedError.new("from", "to", callback) }
66
+
67
+ let(:callback) { -> { "hello" } }
62
68
 
63
69
  its(:message) do
64
70
  is_expected.to eq("Guard on transition from: 'from' to 'to' returned false")
65
71
  end
72
+
73
+ its(:backtrace) do
74
+ is_expected.to eq([callback.source_location.join(":")])
75
+ end
76
+
66
77
  its "string matches its message" do
67
78
  expect(error.to_s).to eq(error.message)
68
79
  end
@@ -72,6 +83,7 @@ describe Statesman do
72
83
  subject(:error) { Statesman::UnserializedMetadataError.new("foo") }
73
84
 
74
85
  its(:message) { is_expected.to match(/foo#metadata is not serialized/) }
86
+
75
87
  its "string matches its message" do
76
88
  expect(error.to_s).to eq(error.message)
77
89
  end
@@ -81,6 +93,7 @@ describe Statesman do
81
93
  subject(:error) { Statesman::IncompatibleSerializationError.new("foo") }
82
94
 
83
95
  its(:message) { is_expected.to match(/foo#metadata column type cannot be json/) }
96
+
84
97
  its "string matches its message" do
85
98
  expect(error.to_s).to eq(error.message)
86
99
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Statesman::Guard do
6
4
  let(:callback) { -> {} }
7
5
  let(:guard) { described_class.new(from: nil, to: nil, callback: callback) }
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Statesman::Machine do
6
4
  let(:machine) { Class.new { include Statesman::Machine } }
7
5
  let(:my_model) { Class.new { attr_accessor :current_state }.new }
@@ -27,6 +25,112 @@ describe Statesman::Machine do
27
25
  end
28
26
  end
29
27
 
28
+ describe ".remove_state" do
29
+ subject(:remove_state) { machine.remove_state(:x) }
30
+
31
+ before do
32
+ machine.class_eval do
33
+ state :x
34
+ state :y
35
+ state :z
36
+ end
37
+ end
38
+
39
+ it "removes the state" do
40
+ expect { remove_state }.
41
+ to change(machine, :states).
42
+ from(match_array(%w[x y z])).
43
+ to(%w[y z])
44
+ end
45
+
46
+ context "with a transition from the removed state" do
47
+ before { machine.transition from: :x, to: :y }
48
+
49
+ it "removes the transition" do
50
+ expect { remove_state }.
51
+ to change(machine, :successors).
52
+ from({ "x" => ["y"] }).
53
+ to({})
54
+ end
55
+
56
+ context "with multiple transitions" do
57
+ before { machine.transition from: :x, to: :z }
58
+
59
+ it "removes all transitions" do
60
+ expect { remove_state }.
61
+ to change(machine, :successors).
62
+ from({ "x" => %w[y z] }).
63
+ to({})
64
+ end
65
+ end
66
+ end
67
+
68
+ context "with a transition to the removed state" do
69
+ before { machine.transition from: :y, to: :x }
70
+
71
+ it "removes the transition" do
72
+ expect { remove_state }.
73
+ to change(machine, :successors).
74
+ from({ "y" => ["x"] }).
75
+ to({})
76
+ end
77
+
78
+ context "with multiple transitions" do
79
+ before { machine.transition from: :z, to: :x }
80
+
81
+ it "removes all transitions" do
82
+ expect { remove_state }.
83
+ to change(machine, :successors).
84
+ from({ "y" => ["x"], "z" => ["x"] }).
85
+ to({})
86
+ end
87
+ end
88
+ end
89
+
90
+ context "with a callback from the removed state" do
91
+ before do
92
+ machine.class_eval do
93
+ transition from: :x, to: :y
94
+ transition from: :x, to: :z
95
+ guard_transition(from: :x) { return false }
96
+ guard_transition(from: :x, to: :z) { return true }
97
+ end
98
+ end
99
+
100
+ let(:guards) do
101
+ [having_attributes(from: "x", to: []), having_attributes(from: "x", to: ["z"])]
102
+ end
103
+
104
+ it "removes the guard" do
105
+ expect { remove_state }.
106
+ to change(machine, :callbacks).
107
+ from(a_hash_including(guards: match_array(guards))).
108
+ to(a_hash_including(guards: []))
109
+ end
110
+ end
111
+
112
+ context "with a callback to the removed state" do
113
+ before do
114
+ machine.class_eval do
115
+ transition from: :y, to: :x
116
+ guard_transition(to: :x) { return false }
117
+ guard_transition(from: :y, to: :x) { return true }
118
+ end
119
+ end
120
+
121
+ let(:guards) do
122
+ [having_attributes(from: nil, to: ["x"]), having_attributes(from: "y", to: ["x"])]
123
+ end
124
+
125
+ it "removes the guard" do
126
+ expect { remove_state }.
127
+ to change(machine, :callbacks).
128
+ from(a_hash_including(guards: match_array(guards))).
129
+ to(a_hash_including(guards: []))
130
+ end
131
+ end
132
+ end
133
+
30
134
  describe ".retry_conflicts" do
31
135
  subject(:transition_state) do
32
136
  described_class.retry_conflicts(retry_attempts) do
@@ -170,6 +274,42 @@ describe Statesman::Machine do
170
274
  end
171
275
  end
172
276
 
277
+ describe ".remove_transitions" do
278
+ before do
279
+ machine.class_eval do
280
+ state :x
281
+ state :y
282
+ state :z
283
+ transition from: :x, to: :y
284
+ transition from: :x, to: :z
285
+ transition from: :y, to: :z
286
+ end
287
+ end
288
+
289
+ let(:initial_successors) { { "x" => %w[y z], "y" => ["z"] } }
290
+
291
+ it "removes the correct transitions when given a from state" do
292
+ expect { machine.remove_transitions(from: :x) }.
293
+ to change(machine, :successors).
294
+ from(initial_successors).
295
+ to({ "y" => ["z"] })
296
+ end
297
+
298
+ it "removes the correct transitions when given a to state" do
299
+ expect { machine.remove_transitions(to: :z) }.
300
+ to change(machine, :successors).
301
+ from(initial_successors).
302
+ to({ "x" => ["y"] })
303
+ end
304
+
305
+ it "removes the correct transitions when given a from and to state" do
306
+ expect { machine.remove_transitions(from: :x, to: :z) }.
307
+ to change(machine, :successors).
308
+ from(initial_successors).
309
+ to({ "x" => ["y"], "y" => ["z"] })
310
+ end
311
+ end
312
+
173
313
  describe ".validate_callback_condition" do
174
314
  before do
175
315
  machine.class_eval do
@@ -234,11 +374,9 @@ describe Statesman::Machine do
234
374
 
235
375
  it "does not add a callback" do
236
376
  expect do
237
- begin
238
- set_callback
239
- rescue error_type
240
- nil
241
- end
377
+ set_callback
378
+ rescue error_type
379
+ nil
242
380
  end.to_not change(machine.callbacks[callback_store], :count)
243
381
  end
244
382
  end
@@ -340,12 +478,83 @@ describe Statesman::Machine do
340
478
  it_behaves_like "a callback store", :after_guard_failure, :after_guard_failure
341
479
  end
342
480
 
481
+ shared_examples "initial transition is not created" do
482
+ it "doesn't call .create on storage adapter" do
483
+ expect_any_instance_of(Statesman.storage_adapter).to_not receive(:create)
484
+ machine.new(my_model, options)
485
+ end
486
+ end
487
+
488
+ shared_examples "initial transition is created" do
489
+ it "calls .create on storage adapter" do
490
+ expect_any_instance_of(Statesman.storage_adapter).to receive(:create).with(nil, "x")
491
+ machine.new(my_model, options)
492
+ end
493
+
494
+ it "creates a new transition object" do
495
+ instance = machine.new(my_model, options)
496
+
497
+ expect(instance.history.count).to eq(1)
498
+ expect(instance.history.first.to_state).to eq("x")
499
+ end
500
+ end
501
+
343
502
  describe "#initialize" do
344
503
  it "accepts an object to manipulate" do
345
504
  machine_instance = machine.new(my_model)
346
505
  expect(machine_instance.object).to be(my_model)
347
506
  end
348
507
 
508
+ context "initial_transition is not provided" do
509
+ let(:options) { {} }
510
+
511
+ it_behaves_like "initial transition is not created"
512
+ end
513
+
514
+ context "initial_transition is provided" do
515
+ context "initial_transition is true" do
516
+ let(:options) do
517
+ { initial_transition: true,
518
+ transition_class: Statesman::Adapters::MemoryTransition }
519
+ end
520
+
521
+ context "history is empty" do
522
+ context "initial state is defined" do
523
+ before { machine.state(:x, initial: true) }
524
+
525
+ it_behaves_like "initial transition is created"
526
+ end
527
+
528
+ context "initial state is not defined" do
529
+ it_behaves_like "initial transition is not created"
530
+ end
531
+ end
532
+
533
+ context "history is not empty" do
534
+ before do
535
+ allow_any_instance_of(Statesman.storage_adapter).to receive(:history).
536
+ and_return([{}])
537
+ end
538
+
539
+ context "initial state is defined" do
540
+ before { machine.state(:x, initial: true) }
541
+
542
+ it_behaves_like "initial transition is not created"
543
+ end
544
+
545
+ context "initial state is not defined" do
546
+ it_behaves_like "initial transition is not created"
547
+ end
548
+ end
549
+ end
550
+
551
+ context "initial_transition is false" do
552
+ let(:options) { { initial_transition: false } }
553
+
554
+ it_behaves_like "initial transition is not created"
555
+ end
556
+ end
557
+
349
558
  context "transition class" do
350
559
  it "sets a default" do
351
560
  expect(Statesman.storage_adapter).to receive(:new).once.
@@ -537,6 +746,34 @@ describe Statesman::Machine do
537
746
  end
538
747
  end
539
748
 
749
+ describe "#last_transition_to" do
750
+ subject { instance.last_transition_to(:y) }
751
+
752
+ before do
753
+ machine.class_eval do
754
+ state :x, initial: true
755
+ state :y
756
+ state :z
757
+ transition from: :x, to: :y
758
+ transition from: :y, to: :z
759
+ transition from: :z, to: :y
760
+ end
761
+
762
+ instance.transition_to!(:y)
763
+ instance.transition_to!(:z)
764
+ end
765
+
766
+ let(:instance) { machine.new(my_model) }
767
+
768
+ it { is_expected.to have_attributes(to_state: "y") }
769
+
770
+ context "when there are 2 transitions to the state" do
771
+ before { instance.transition_to!(:y) }
772
+
773
+ it { is_expected.to eq(instance.last_transition) }
774
+ end
775
+ end
776
+
540
777
  describe "#can_transition_to?" do
541
778
  subject(:can_transition_to?) { instance.can_transition_to?(new_state, metadata) }
542
779
 
@@ -767,10 +1004,10 @@ describe Statesman::Machine do
767
1004
  it { is_expected.to be(:some_state) }
768
1005
  end
769
1006
 
770
- context "when it is unsuccesful" do
1007
+ context "when it is unsuccessful" do
771
1008
  before do
772
1009
  allow(instance).to receive(:transition_to!).
773
- and_raise(Statesman::GuardFailedError.new(:x, :some_state))
1010
+ and_raise(Statesman::GuardFailedError.new(:x, :some_state, nil))
774
1011
  end
775
1012
 
776
1013
  it { is_expected.to be_falsey }
@@ -808,20 +1045,20 @@ describe Statesman::Machine do
808
1045
  end
809
1046
 
810
1047
  context "with defined callbacks" do
811
- let(:callback_1) { -> { "Hi" } }
812
- let(:callback_2) { -> { "Bye" } }
1048
+ let(:callback_one) { -> { "Hi" } }
1049
+ let(:callback_two) { -> { "Bye" } }
813
1050
 
814
1051
  before do
815
- machine.send(definer, from: :x, to: :y, &callback_1)
816
- machine.send(definer, from: :y, to: :z, &callback_2)
1052
+ machine.send(definer, from: :x, to: :y, &callback_one)
1053
+ machine.send(definer, from: :y, to: :z, &callback_two)
817
1054
  end
818
1055
 
819
1056
  it "contains the relevant callback" do
820
- expect(callbacks.map(&:callback)).to include(callback_1)
1057
+ expect(callbacks.map(&:callback)).to include(callback_one)
821
1058
  end
822
1059
 
823
1060
  it "does not contain the irrelevant callback" do
824
- expect(callbacks.map(&:callback)).to_not include(callback_2)
1061
+ expect(callbacks.map(&:callback)).to_not include(callback_two)
825
1062
  end
826
1063
  end
827
1064
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "spec_helper"
4
-
5
3
  describe Statesman::Utils do
6
4
  describe ".rails_major_version" do
7
5
  subject { described_class.rails_major_version }