interaktor 0.3.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/publish.yml +5 -3
- 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 +12 -1
- data/lib/interaktor/failure.rb +8 -8
- data/lib/interaktor/hooks.rb +68 -2
- 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 +111 -13
- data/spec/interaktor/organizer_spec.rb +58 -90
- data/spec/support/helpers.rb +5 -7
- data/spec/support/lint.rb +33 -60
- metadata +19 -26
- data/.rubocop.yml +0 -245
- data/lib/interaktor/context.rb +0 -116
- data/lib/interaktor/error/disallowed_attribute_assignment_error.rb +0 -9
- data/lib/interaktor/error/option_error.rb +0 -18
- data/lib/interaktor/error/unknown_option_error.rb +0 -5
|
@@ -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,12 +303,100 @@ module Interaktor
|
|
|
303
303
|
expect(hooked.process).to eq([
|
|
304
304
|
:process,
|
|
305
305
|
:after2,
|
|
306
|
-
:after1
|
|
306
|
+
:after1
|
|
307
|
+
])
|
|
308
|
+
end
|
|
309
|
+
end
|
|
310
|
+
|
|
311
|
+
context "with an ensure_hook method" do
|
|
312
|
+
let(:hooked) {
|
|
313
|
+
build_hooked do
|
|
314
|
+
ensure_hook :add_ensure
|
|
315
|
+
|
|
316
|
+
private
|
|
317
|
+
|
|
318
|
+
def add_ensure
|
|
319
|
+
steps << :ensure
|
|
320
|
+
end
|
|
321
|
+
end
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
it "runs the after hook method" do
|
|
325
|
+
expect(hooked.process).to eq([
|
|
326
|
+
:process,
|
|
327
|
+
:ensure
|
|
328
|
+
])
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
context "with an ensure_hook block" do
|
|
333
|
+
let(:hooked) {
|
|
334
|
+
build_hooked do
|
|
335
|
+
ensure_hook do
|
|
336
|
+
steps << :ensure
|
|
337
|
+
end
|
|
338
|
+
end
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
it "runs the after hook block" do
|
|
342
|
+
expect(hooked.process).to eq([
|
|
343
|
+
:process,
|
|
344
|
+
:ensure
|
|
307
345
|
])
|
|
308
346
|
end
|
|
309
347
|
end
|
|
310
348
|
|
|
311
|
-
context "with
|
|
349
|
+
context "with an ensure_hook method and block in one call" do
|
|
350
|
+
let(:hooked) {
|
|
351
|
+
build_hooked do
|
|
352
|
+
ensure_hook :add_ensure1 do
|
|
353
|
+
steps << :ensure2
|
|
354
|
+
end
|
|
355
|
+
|
|
356
|
+
private
|
|
357
|
+
|
|
358
|
+
def add_ensure1
|
|
359
|
+
steps << :ensure1
|
|
360
|
+
end
|
|
361
|
+
end
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
it "runs the ensure_hook method and block in order" do
|
|
365
|
+
expect(hooked.process).to eq([
|
|
366
|
+
:process,
|
|
367
|
+
:ensure1,
|
|
368
|
+
:ensure2
|
|
369
|
+
])
|
|
370
|
+
end
|
|
371
|
+
end
|
|
372
|
+
|
|
373
|
+
context "with an ensure_hook method and block in multiple calls" do
|
|
374
|
+
let(:hooked) {
|
|
375
|
+
build_hooked do
|
|
376
|
+
ensure_hook do
|
|
377
|
+
steps << :ensure1
|
|
378
|
+
end
|
|
379
|
+
|
|
380
|
+
ensure_hook :add_ensure2
|
|
381
|
+
|
|
382
|
+
private
|
|
383
|
+
|
|
384
|
+
def add_ensure2
|
|
385
|
+
steps << :ensure2
|
|
386
|
+
end
|
|
387
|
+
end
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
it "runs the ensure_hook block and method in order" do
|
|
391
|
+
expect(hooked.process).to eq([
|
|
392
|
+
:process,
|
|
393
|
+
:ensure1,
|
|
394
|
+
:ensure2
|
|
395
|
+
])
|
|
396
|
+
end
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
context "with around, before, after and ensure_hook hooks" do
|
|
312
400
|
let(:hooked) {
|
|
313
401
|
build_hooked do
|
|
314
402
|
around do |hooked|
|
|
@@ -338,6 +426,14 @@ module Interaktor
|
|
|
338
426
|
after do
|
|
339
427
|
steps << :after2
|
|
340
428
|
end
|
|
429
|
+
|
|
430
|
+
ensure_hook do
|
|
431
|
+
steps << :ensure1
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
ensure_hook do
|
|
435
|
+
steps << :ensure2
|
|
436
|
+
end
|
|
341
437
|
end
|
|
342
438
|
}
|
|
343
439
|
|
|
@@ -352,6 +448,8 @@ module Interaktor
|
|
|
352
448
|
:after1,
|
|
353
449
|
:around_after2,
|
|
354
450
|
:around_after1,
|
|
451
|
+
:ensure1,
|
|
452
|
+
:ensure2
|
|
355
453
|
])
|
|
356
454
|
end
|
|
357
455
|
end
|