interaktor 0.4.0 → 0.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.
- checksums.yaml +4 -4
- data/.github/workflows/tests.yml +1 -1
- data/.ruby-version +1 -1
- data/.standard.yml +1 -0
- data/Gemfile +2 -5
- data/README.md +25 -4
- data/bin/_guard-core +16 -0
- data/bin/guard +16 -0
- data/bin/rspec +16 -0
- data/bin/standardrb +16 -0
- data/interaktor.gemspec +3 -4
- data/lib/interaktor/callable.rb +63 -76
- data/lib/interaktor/error/invalid_method_for_state_error.rb +10 -0
- data/lib/interaktor/error/organizer_missing_passed_attribute_error.rb +1 -1
- data/lib/interaktor/error/organizer_success_attribute_missing_error.rb +1 -1
- data/lib/interaktor/error/unknown_attribute_error.rb +16 -0
- data/lib/interaktor/failure.rb +8 -8
- data/lib/interaktor/hooks.rb +53 -3
- data/lib/interaktor/interaction.rb +154 -0
- data/lib/interaktor/organizer.rb +9 -1
- data/lib/interaktor.rb +41 -53
- data/spec/integration_spec.rb +1874 -1874
- data/spec/interaktor/context_spec.rb +185 -185
- data/spec/interaktor/hooks_spec.rb +17 -17
- data/spec/interaktor/organizer_spec.rb +58 -90
- data/spec/support/helpers.rb +5 -7
- data/spec/support/lint.rb +33 -60
- metadata +20 -22
- data/.rubocop.yml +0 -245
- data/lib/interaktor/context.rb +0 -116
|
@@ -1,187 +1,187 @@
|
|
|
1
1
|
module Interaktor
|
|
2
|
-
RSpec.describe Context do
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
end
|
|
2
|
+
# RSpec.describe Context do
|
|
3
|
+
# describe ".build" do
|
|
4
|
+
# it "converts the given hash to a context" do
|
|
5
|
+
# context = described_class.build(foo: "bar")
|
|
6
|
+
|
|
7
|
+
# expect(context).to be_a(described_class)
|
|
8
|
+
# expect(context.foo).to eq("bar")
|
|
9
|
+
# end
|
|
10
|
+
|
|
11
|
+
# it "builds an empty context if no hash is given" do
|
|
12
|
+
# context = described_class.build
|
|
13
|
+
|
|
14
|
+
# expect(context).to be_a(described_class)
|
|
15
|
+
# expect(context.send(:table)).to eq({})
|
|
16
|
+
# end
|
|
17
|
+
|
|
18
|
+
# it "doesn't affect the original hash" do
|
|
19
|
+
# hash = {foo: "bar"}
|
|
20
|
+
# context = described_class.build(hash)
|
|
21
|
+
|
|
22
|
+
# expect(context).to be_a(described_class)
|
|
23
|
+
# expect {
|
|
24
|
+
# context.foo = "baz"
|
|
25
|
+
# }.not_to(change {
|
|
26
|
+
# hash[:foo]
|
|
27
|
+
# })
|
|
28
|
+
# end
|
|
29
|
+
|
|
30
|
+
# it "preserves an already built context" do
|
|
31
|
+
# context1 = described_class.build(foo: "bar")
|
|
32
|
+
# context2 = described_class.build(context1)
|
|
33
|
+
|
|
34
|
+
# expect(context2).to be_a(described_class)
|
|
35
|
+
# expect {
|
|
36
|
+
# context2.foo = "baz"
|
|
37
|
+
# }.to change {
|
|
38
|
+
# context1.foo
|
|
39
|
+
# }.from("bar").to("baz")
|
|
40
|
+
# end
|
|
41
|
+
# end
|
|
42
|
+
|
|
43
|
+
# describe "#success?" do
|
|
44
|
+
# let(:context) { described_class.build }
|
|
45
|
+
|
|
46
|
+
# it "is true by default" do
|
|
47
|
+
# expect(context.success?).to eq(true)
|
|
48
|
+
# end
|
|
49
|
+
# end
|
|
50
|
+
|
|
51
|
+
# describe "#failure?" do
|
|
52
|
+
# let(:context) { described_class.build }
|
|
53
|
+
|
|
54
|
+
# it "is false by default" do
|
|
55
|
+
# expect(context.failure?).to eq(false)
|
|
56
|
+
# end
|
|
57
|
+
# end
|
|
58
|
+
|
|
59
|
+
# describe "#fail!" do
|
|
60
|
+
# let(:context) { described_class.build(foo: "bar") }
|
|
61
|
+
|
|
62
|
+
# it "sets success to false" do
|
|
63
|
+
# expect {
|
|
64
|
+
# begin
|
|
65
|
+
# context.fail!
|
|
66
|
+
# rescue
|
|
67
|
+
# nil
|
|
68
|
+
# end
|
|
69
|
+
# }.to change(context, :success?).from(true).to(false)
|
|
70
|
+
# end
|
|
71
|
+
|
|
72
|
+
# it "sets failure to true" do
|
|
73
|
+
# expect {
|
|
74
|
+
# begin
|
|
75
|
+
# context.fail!
|
|
76
|
+
# rescue
|
|
77
|
+
# nil
|
|
78
|
+
# end
|
|
79
|
+
# }.to change(context, :failure?).from(false).to(true)
|
|
80
|
+
# end
|
|
81
|
+
|
|
82
|
+
# it "preserves failure" do
|
|
83
|
+
# begin
|
|
84
|
+
# context.fail!
|
|
85
|
+
# rescue
|
|
86
|
+
# nil
|
|
87
|
+
# end
|
|
88
|
+
|
|
89
|
+
# expect {
|
|
90
|
+
# begin
|
|
91
|
+
# context.fail!
|
|
92
|
+
# rescue
|
|
93
|
+
# nil
|
|
94
|
+
# end
|
|
95
|
+
# }.not_to change(context, :failure?)
|
|
96
|
+
# end
|
|
97
|
+
|
|
98
|
+
# it "preserves the context" do
|
|
99
|
+
# expect {
|
|
100
|
+
# begin
|
|
101
|
+
# context.fail!
|
|
102
|
+
# rescue
|
|
103
|
+
# nil
|
|
104
|
+
# end
|
|
105
|
+
# }.not_to change(context, :foo)
|
|
106
|
+
# end
|
|
107
|
+
|
|
108
|
+
# it "updates the context" do
|
|
109
|
+
# expect {
|
|
110
|
+
# begin
|
|
111
|
+
# context.fail!(foo: "baz")
|
|
112
|
+
# rescue
|
|
113
|
+
# nil
|
|
114
|
+
# end
|
|
115
|
+
# }.to change(context, :foo).from("bar").to("baz")
|
|
116
|
+
# end
|
|
117
|
+
|
|
118
|
+
# it "updates the context with a string key" do
|
|
119
|
+
# expect {
|
|
120
|
+
# begin
|
|
121
|
+
# context.fail!("foo" => "baz")
|
|
122
|
+
# rescue
|
|
123
|
+
# nil
|
|
124
|
+
# end
|
|
125
|
+
# }.to change(context, :foo).from("bar").to("baz")
|
|
126
|
+
# end
|
|
127
|
+
|
|
128
|
+
# it "raises failure" do
|
|
129
|
+
# expect {
|
|
130
|
+
# context.fail!
|
|
131
|
+
# }.to raise_error(Failure)
|
|
132
|
+
# end
|
|
133
|
+
|
|
134
|
+
# it "makes the context available from the failure" do
|
|
135
|
+
# context.fail!
|
|
136
|
+
# rescue Failure => e
|
|
137
|
+
# expect(e.context).to eq(context)
|
|
138
|
+
# end
|
|
139
|
+
# end
|
|
140
|
+
|
|
141
|
+
# describe "#called!" do
|
|
142
|
+
# let(:context) { described_class.build }
|
|
143
|
+
# let(:instance1) { instance_double(Interaktor) }
|
|
144
|
+
# let(:instance2) { instance_double(Interaktor) }
|
|
145
|
+
|
|
146
|
+
# it "appends to the internal list of called instances" do
|
|
147
|
+
# expect {
|
|
148
|
+
# context.called!(instance1)
|
|
149
|
+
# context.called!(instance2)
|
|
150
|
+
# }.to change(context, :_called).from([]).to([instance1, instance2])
|
|
151
|
+
# end
|
|
152
|
+
# end
|
|
153
|
+
|
|
154
|
+
# describe "#rollback!" do
|
|
155
|
+
# let(:context) { described_class.build }
|
|
156
|
+
# let(:instance1) { instance_double(Interaktor) }
|
|
157
|
+
# let(:instance2) { instance_double(Interaktor) }
|
|
158
|
+
|
|
159
|
+
# before do
|
|
160
|
+
# allow(context).to receive(:_called) { [instance1, instance2] }
|
|
161
|
+
# end
|
|
162
|
+
|
|
163
|
+
# it "rolls back each instance in reverse order" do
|
|
164
|
+
# expect(instance2).to receive(:rollback).once.with(no_args).ordered
|
|
165
|
+
# expect(instance1).to receive(:rollback).once.with(no_args).ordered
|
|
166
|
+
|
|
167
|
+
# context.rollback!
|
|
168
|
+
# end
|
|
169
|
+
|
|
170
|
+
# it "ignores subsequent attempts" do
|
|
171
|
+
# expect(instance2).to receive(:rollback).once
|
|
172
|
+
# expect(instance1).to receive(:rollback).once
|
|
173
|
+
|
|
174
|
+
# context.rollback!
|
|
175
|
+
# context.rollback!
|
|
176
|
+
# end
|
|
177
|
+
# end
|
|
178
|
+
|
|
179
|
+
# describe "#_called" do
|
|
180
|
+
# let(:context) { described_class.build }
|
|
181
|
+
|
|
182
|
+
# it "is empty by default" do
|
|
183
|
+
# expect(context._called).to eq([])
|
|
184
|
+
# end
|
|
185
|
+
# end
|
|
186
|
+
# end
|
|
187
187
|
end
|
|
@@ -45,7 +45,7 @@ module Interaktor
|
|
|
45
45
|
expect(hooked.process).to eq([
|
|
46
46
|
:around_before,
|
|
47
47
|
:process,
|
|
48
|
-
:around_after
|
|
48
|
+
:around_after
|
|
49
49
|
])
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -65,7 +65,7 @@ module Interaktor
|
|
|
65
65
|
expect(hooked.process).to eq([
|
|
66
66
|
:around_before,
|
|
67
67
|
:process,
|
|
68
|
-
:around_after
|
|
68
|
+
:around_after
|
|
69
69
|
])
|
|
70
70
|
end
|
|
71
71
|
end
|
|
@@ -95,7 +95,7 @@ module Interaktor
|
|
|
95
95
|
:around_before2,
|
|
96
96
|
:process,
|
|
97
97
|
:around_after2,
|
|
98
|
-
:around_after1
|
|
98
|
+
:around_after1
|
|
99
99
|
])
|
|
100
100
|
end
|
|
101
101
|
end
|
|
@@ -127,7 +127,7 @@ module Interaktor
|
|
|
127
127
|
:around_before2,
|
|
128
128
|
:process,
|
|
129
129
|
:around_after2,
|
|
130
|
-
:around_after1
|
|
130
|
+
:around_after1
|
|
131
131
|
])
|
|
132
132
|
end
|
|
133
133
|
end
|
|
@@ -148,7 +148,7 @@ module Interaktor
|
|
|
148
148
|
it "runs the before hook method" do
|
|
149
149
|
expect(hooked.process).to eq([
|
|
150
150
|
:before,
|
|
151
|
-
:process
|
|
151
|
+
:process
|
|
152
152
|
])
|
|
153
153
|
end
|
|
154
154
|
end
|
|
@@ -165,7 +165,7 @@ module Interaktor
|
|
|
165
165
|
it "runs the before hook block" do
|
|
166
166
|
expect(hooked.process).to eq([
|
|
167
167
|
:before,
|
|
168
|
-
:process
|
|
168
|
+
:process
|
|
169
169
|
])
|
|
170
170
|
end
|
|
171
171
|
end
|
|
@@ -189,7 +189,7 @@ module Interaktor
|
|
|
189
189
|
expect(hooked.process).to eq([
|
|
190
190
|
:before1,
|
|
191
191
|
:before2,
|
|
192
|
-
:process
|
|
192
|
+
:process
|
|
193
193
|
])
|
|
194
194
|
end
|
|
195
195
|
end
|
|
@@ -215,7 +215,7 @@ module Interaktor
|
|
|
215
215
|
expect(hooked.process).to eq([
|
|
216
216
|
:before1,
|
|
217
217
|
:before2,
|
|
218
|
-
:process
|
|
218
|
+
:process
|
|
219
219
|
])
|
|
220
220
|
end
|
|
221
221
|
end
|
|
@@ -236,7 +236,7 @@ module Interaktor
|
|
|
236
236
|
it "runs the after hook method" do
|
|
237
237
|
expect(hooked.process).to eq([
|
|
238
238
|
:process,
|
|
239
|
-
:after
|
|
239
|
+
:after
|
|
240
240
|
])
|
|
241
241
|
end
|
|
242
242
|
end
|
|
@@ -253,7 +253,7 @@ module Interaktor
|
|
|
253
253
|
it "runs the after hook block" do
|
|
254
254
|
expect(hooked.process).to eq([
|
|
255
255
|
:process,
|
|
256
|
-
:after
|
|
256
|
+
:after
|
|
257
257
|
])
|
|
258
258
|
end
|
|
259
259
|
end
|
|
@@ -277,7 +277,7 @@ module Interaktor
|
|
|
277
277
|
expect(hooked.process).to eq([
|
|
278
278
|
:process,
|
|
279
279
|
:after2,
|
|
280
|
-
:after1
|
|
280
|
+
:after1
|
|
281
281
|
])
|
|
282
282
|
end
|
|
283
283
|
end
|
|
@@ -303,7 +303,7 @@ module Interaktor
|
|
|
303
303
|
expect(hooked.process).to eq([
|
|
304
304
|
:process,
|
|
305
305
|
:after2,
|
|
306
|
-
:after1
|
|
306
|
+
:after1
|
|
307
307
|
])
|
|
308
308
|
end
|
|
309
309
|
end
|
|
@@ -324,7 +324,7 @@ module Interaktor
|
|
|
324
324
|
it "runs the after hook method" do
|
|
325
325
|
expect(hooked.process).to eq([
|
|
326
326
|
:process,
|
|
327
|
-
:ensure
|
|
327
|
+
:ensure
|
|
328
328
|
])
|
|
329
329
|
end
|
|
330
330
|
end
|
|
@@ -341,7 +341,7 @@ module Interaktor
|
|
|
341
341
|
it "runs the after hook block" do
|
|
342
342
|
expect(hooked.process).to eq([
|
|
343
343
|
:process,
|
|
344
|
-
:ensure
|
|
344
|
+
:ensure
|
|
345
345
|
])
|
|
346
346
|
end
|
|
347
347
|
end
|
|
@@ -365,7 +365,7 @@ module Interaktor
|
|
|
365
365
|
expect(hooked.process).to eq([
|
|
366
366
|
:process,
|
|
367
367
|
:ensure1,
|
|
368
|
-
:ensure2
|
|
368
|
+
:ensure2
|
|
369
369
|
])
|
|
370
370
|
end
|
|
371
371
|
end
|
|
@@ -391,7 +391,7 @@ module Interaktor
|
|
|
391
391
|
expect(hooked.process).to eq([
|
|
392
392
|
:process,
|
|
393
393
|
:ensure1,
|
|
394
|
-
:ensure2
|
|
394
|
+
:ensure2
|
|
395
395
|
])
|
|
396
396
|
end
|
|
397
397
|
end
|
|
@@ -449,7 +449,7 @@ module Interaktor
|
|
|
449
449
|
:around_after2,
|
|
450
450
|
:around_after1,
|
|
451
451
|
:ensure1,
|
|
452
|
-
:ensure2
|
|
452
|
+
:ensure2
|
|
453
453
|
])
|
|
454
454
|
end
|
|
455
455
|
end
|