interactor 2.1.1 → 3.0.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/.rspec +3 -0
- data/.travis.yml +10 -2
- data/CHANGELOG.md +31 -0
- data/CONTRIBUTING.md +49 -0
- data/Gemfile +2 -3
- data/README.md +453 -163
- data/interactor.gemspec +6 -7
- data/lib/interactor.rb +22 -26
- data/lib/interactor/context.rb +19 -8
- data/lib/interactor/error.rb +10 -0
- data/lib/interactor/hooks.rb +53 -0
- data/lib/interactor/organizer.rb +7 -27
- data/spec/integration_spec.rb +967 -0
- data/spec/interactor/context_spec.rb +75 -34
- data/spec/interactor/organizer_spec.rb +16 -169
- data/spec/interactor_spec.rb +0 -2
- data/spec/spec_helper.rb +3 -3
- data/spec/support/lint.rb +65 -99
- metadata +14 -12
- data/spec/support/expect.rb +0 -3
- data/spec/support/random.rb +0 -3
data/interactor.gemspec
CHANGED
@@ -2,19 +2,18 @@
|
|
2
2
|
|
3
3
|
Gem::Specification.new do |spec|
|
4
4
|
spec.name = "interactor"
|
5
|
-
spec.version = "
|
5
|
+
spec.version = "3.0.0"
|
6
6
|
|
7
7
|
spec.author = "Collective Idea"
|
8
8
|
spec.email = "info@collectiveidea.com"
|
9
|
-
spec.description = "Interactor provides a common interface for performing complex interactions
|
9
|
+
spec.description = "Interactor provides a common interface for performing complex user interactions."
|
10
10
|
spec.summary = "Simple interactor implementation"
|
11
11
|
spec.homepage = "https://github.com/collectiveidea/interactor"
|
12
12
|
spec.license = "MIT"
|
13
13
|
|
14
|
-
spec.files
|
15
|
-
spec.test_files
|
16
|
-
spec.require_paths = ["lib"]
|
14
|
+
spec.files = `git ls-files`.split($/)
|
15
|
+
spec.test_files = spec.files.grep(/^spec/)
|
17
16
|
|
18
|
-
spec.add_development_dependency "bundler", "~> 1.
|
19
|
-
spec.add_development_dependency "rake", "~> 10.
|
17
|
+
spec.add_development_dependency "bundler", "~> 1.7"
|
18
|
+
spec.add_development_dependency "rake", "~> 10.3"
|
20
19
|
end
|
data/lib/interactor.rb
CHANGED
@@ -1,54 +1,50 @@
|
|
1
1
|
require "interactor/context"
|
2
|
+
require "interactor/error"
|
3
|
+
require "interactor/hooks"
|
2
4
|
require "interactor/organizer"
|
3
5
|
|
4
6
|
module Interactor
|
5
7
|
def self.included(base)
|
6
8
|
base.class_eval do
|
7
9
|
extend ClassMethods
|
10
|
+
include Hooks
|
8
11
|
|
9
12
|
attr_reader :context
|
10
13
|
end
|
11
14
|
end
|
12
15
|
|
13
16
|
module ClassMethods
|
14
|
-
def
|
15
|
-
new(context).tap
|
16
|
-
|
17
|
-
|
17
|
+
def call(context = {})
|
18
|
+
new(context).tap(&:run).context
|
19
|
+
end
|
20
|
+
|
21
|
+
def call!(context = {})
|
22
|
+
new(context).tap(&:run!).context
|
18
23
|
end
|
19
24
|
end
|
20
25
|
|
21
26
|
def initialize(context = {})
|
22
27
|
@context = Context.build(context)
|
23
|
-
setup
|
24
|
-
end
|
25
|
-
|
26
|
-
def setup
|
27
28
|
end
|
28
29
|
|
29
|
-
def
|
30
|
-
|
31
|
-
|
32
|
-
def rollback
|
30
|
+
def run
|
31
|
+
run!
|
32
|
+
rescue Failure
|
33
33
|
end
|
34
34
|
|
35
|
-
def
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
def fail!(*args)
|
44
|
-
context.fail!(*args)
|
35
|
+
def run!
|
36
|
+
with_hooks do
|
37
|
+
call
|
38
|
+
context.called!(self)
|
39
|
+
end
|
40
|
+
rescue
|
41
|
+
context.rollback!
|
42
|
+
raise
|
45
43
|
end
|
46
44
|
|
47
|
-
def
|
48
|
-
context.fetch(method) { context.fetch(method.to_s) { super } }
|
45
|
+
def call
|
49
46
|
end
|
50
47
|
|
51
|
-
def
|
52
|
-
(context && (context.key?(method) || context.key?(method.to_s))) || super
|
48
|
+
def rollback
|
53
49
|
end
|
54
50
|
end
|
data/lib/interactor/context.rb
CHANGED
@@ -1,13 +1,9 @@
|
|
1
|
-
require "
|
1
|
+
require "ostruct"
|
2
2
|
|
3
3
|
module Interactor
|
4
|
-
class Context <
|
4
|
+
class Context < OpenStruct
|
5
5
|
def self.build(context = {})
|
6
|
-
self === context ? context : new(context
|
7
|
-
end
|
8
|
-
|
9
|
-
def initialize(context = {})
|
10
|
-
super(context)
|
6
|
+
self === context ? context : new(context)
|
11
7
|
end
|
12
8
|
|
13
9
|
def success?
|
@@ -19,8 +15,23 @@ module Interactor
|
|
19
15
|
end
|
20
16
|
|
21
17
|
def fail!(context = {})
|
22
|
-
update(context)
|
18
|
+
modifiable.update(context)
|
23
19
|
@failure = true
|
20
|
+
raise Failure, self
|
21
|
+
end
|
22
|
+
|
23
|
+
def called!(interactor)
|
24
|
+
_called << interactor
|
25
|
+
end
|
26
|
+
|
27
|
+
def rollback!
|
28
|
+
return false if @rolled_back
|
29
|
+
_called.reverse_each(&:rollback)
|
30
|
+
@rolled_back = true
|
31
|
+
end
|
32
|
+
|
33
|
+
def _called
|
34
|
+
@called ||= []
|
24
35
|
end
|
25
36
|
end
|
26
37
|
end
|
@@ -0,0 +1,53 @@
|
|
1
|
+
module Interactor
|
2
|
+
module Hooks
|
3
|
+
def self.included(base)
|
4
|
+
base.class_eval do
|
5
|
+
extend ClassMethods
|
6
|
+
end
|
7
|
+
end
|
8
|
+
|
9
|
+
module ClassMethods
|
10
|
+
def before(*hooks, &block)
|
11
|
+
hooks << block if block
|
12
|
+
hooks.each { |hook| before_hooks.push(hook) }
|
13
|
+
end
|
14
|
+
|
15
|
+
def after(*hooks, &block)
|
16
|
+
hooks << block if block
|
17
|
+
hooks.each { |hook| after_hooks.unshift(hook) }
|
18
|
+
end
|
19
|
+
|
20
|
+
def before_hooks
|
21
|
+
@before_hooks ||= []
|
22
|
+
end
|
23
|
+
|
24
|
+
def after_hooks
|
25
|
+
@after_hooks ||= []
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def with_hooks
|
32
|
+
run_before_hooks
|
33
|
+
yield
|
34
|
+
run_after_hooks
|
35
|
+
end
|
36
|
+
|
37
|
+
def run_before_hooks
|
38
|
+
run_hooks(self.class.before_hooks)
|
39
|
+
end
|
40
|
+
|
41
|
+
def run_after_hooks
|
42
|
+
run_hooks(self.class.after_hooks)
|
43
|
+
end
|
44
|
+
|
45
|
+
def run_hooks(hooks)
|
46
|
+
hooks.each { |hook| run_hook(hook) }
|
47
|
+
end
|
48
|
+
|
49
|
+
def run_hook(hook)
|
50
|
+
hook.is_a?(Symbol) ? send(hook) : instance_eval(&hook)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
data/lib/interactor/organizer.rb
CHANGED
@@ -10,41 +10,21 @@ module Interactor
|
|
10
10
|
end
|
11
11
|
|
12
12
|
module ClassMethods
|
13
|
-
def interactors
|
14
|
-
@
|
13
|
+
def organize(*interactors)
|
14
|
+
@organized = interactors.flatten
|
15
15
|
end
|
16
16
|
|
17
|
-
def
|
18
|
-
@
|
17
|
+
def organized
|
18
|
+
@organized ||= []
|
19
19
|
end
|
20
20
|
end
|
21
21
|
|
22
22
|
module InstanceMethods
|
23
|
-
def
|
24
|
-
self.class.
|
25
|
-
|
26
|
-
|
27
|
-
def perform
|
28
|
-
interactors.each do |interactor|
|
29
|
-
begin
|
30
|
-
instance = interactor.perform(context)
|
31
|
-
rescue
|
32
|
-
rollback
|
33
|
-
raise
|
34
|
-
end
|
35
|
-
|
36
|
-
rollback && break if failure?
|
37
|
-
performed << instance
|
23
|
+
def call
|
24
|
+
self.class.organized.each do |interactor|
|
25
|
+
interactor.call!(context)
|
38
26
|
end
|
39
27
|
end
|
40
|
-
|
41
|
-
def rollback
|
42
|
-
performed.reverse_each(&:rollback)
|
43
|
-
end
|
44
|
-
|
45
|
-
def performed
|
46
|
-
@performed ||= []
|
47
|
-
end
|
48
28
|
end
|
49
29
|
end
|
50
30
|
end
|
@@ -0,0 +1,967 @@
|
|
1
|
+
describe "Integration" do
|
2
|
+
def build_interactor(&block)
|
3
|
+
interactor = Class.new.send(:include, Interactor)
|
4
|
+
interactor.class_eval(&block) if block
|
5
|
+
interactor
|
6
|
+
end
|
7
|
+
|
8
|
+
def build_organizer(options = {}, &block)
|
9
|
+
organizer = Class.new.send(:include, Interactor::Organizer)
|
10
|
+
organizer.organize(options[:organize]) if options[:organize]
|
11
|
+
organizer.class_eval(&block) if block
|
12
|
+
organizer
|
13
|
+
end
|
14
|
+
|
15
|
+
# organizer
|
16
|
+
# ├─ organizer2
|
17
|
+
# │ ├─ interactor2a
|
18
|
+
# │ ├─ interactor2b
|
19
|
+
# │ └─ interactor2c
|
20
|
+
# ├─ interactor3
|
21
|
+
# ├─ organizer4
|
22
|
+
# │ ├─ interactor4a
|
23
|
+
# │ ├─ interactor4b
|
24
|
+
# │ └─ interactor4c
|
25
|
+
# └─ interactor5
|
26
|
+
|
27
|
+
let(:organizer) {
|
28
|
+
build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
|
29
|
+
before do
|
30
|
+
context.steps << :before
|
31
|
+
end
|
32
|
+
|
33
|
+
after do
|
34
|
+
context.steps << :after
|
35
|
+
end
|
36
|
+
end
|
37
|
+
}
|
38
|
+
|
39
|
+
let(:organizer2) {
|
40
|
+
build_organizer(organize: [interactor2a, interactor2b, interactor2c]) do
|
41
|
+
before do
|
42
|
+
context.steps << :before2
|
43
|
+
end
|
44
|
+
|
45
|
+
after do
|
46
|
+
context.steps << :after2
|
47
|
+
end
|
48
|
+
end
|
49
|
+
}
|
50
|
+
|
51
|
+
let(:interactor2a) {
|
52
|
+
build_interactor do
|
53
|
+
before do
|
54
|
+
context.steps << :before2a
|
55
|
+
end
|
56
|
+
|
57
|
+
after do
|
58
|
+
context.steps << :after2a
|
59
|
+
end
|
60
|
+
|
61
|
+
def call
|
62
|
+
context.steps << :call2a
|
63
|
+
end
|
64
|
+
|
65
|
+
def rollback
|
66
|
+
context.steps << :rollback2a
|
67
|
+
end
|
68
|
+
end
|
69
|
+
}
|
70
|
+
|
71
|
+
let(:interactor2b) {
|
72
|
+
build_interactor do
|
73
|
+
before do
|
74
|
+
context.steps << :before2b
|
75
|
+
end
|
76
|
+
|
77
|
+
after do
|
78
|
+
context.steps << :after2b
|
79
|
+
end
|
80
|
+
|
81
|
+
def call
|
82
|
+
context.steps << :call2b
|
83
|
+
end
|
84
|
+
|
85
|
+
def rollback
|
86
|
+
context.steps << :rollback2b
|
87
|
+
end
|
88
|
+
end
|
89
|
+
}
|
90
|
+
|
91
|
+
let(:interactor2c) {
|
92
|
+
build_interactor do
|
93
|
+
before do
|
94
|
+
context.steps << :before2c
|
95
|
+
end
|
96
|
+
|
97
|
+
after do
|
98
|
+
context.steps << :after2c
|
99
|
+
end
|
100
|
+
|
101
|
+
def call
|
102
|
+
context.steps << :call2c
|
103
|
+
end
|
104
|
+
|
105
|
+
def rollback
|
106
|
+
context.steps << :rollback2c
|
107
|
+
end
|
108
|
+
end
|
109
|
+
}
|
110
|
+
|
111
|
+
let(:interactor3) {
|
112
|
+
build_interactor do
|
113
|
+
before do
|
114
|
+
context.steps << :before3
|
115
|
+
end
|
116
|
+
|
117
|
+
after do
|
118
|
+
context.steps << :after3
|
119
|
+
end
|
120
|
+
|
121
|
+
def call
|
122
|
+
context.steps << :call3
|
123
|
+
end
|
124
|
+
|
125
|
+
def rollback
|
126
|
+
context.steps << :rollback3
|
127
|
+
end
|
128
|
+
end
|
129
|
+
}
|
130
|
+
|
131
|
+
let(:organizer4) {
|
132
|
+
build_organizer(organize: [interactor4a, interactor4b, interactor4c]) do
|
133
|
+
before do
|
134
|
+
context.steps << :before4
|
135
|
+
end
|
136
|
+
|
137
|
+
after do
|
138
|
+
context.steps << :after4
|
139
|
+
end
|
140
|
+
end
|
141
|
+
}
|
142
|
+
|
143
|
+
let(:interactor4a) {
|
144
|
+
build_interactor do
|
145
|
+
before do
|
146
|
+
context.steps << :before4a
|
147
|
+
end
|
148
|
+
|
149
|
+
after do
|
150
|
+
context.steps << :after4a
|
151
|
+
end
|
152
|
+
|
153
|
+
def call
|
154
|
+
context.steps << :call4a
|
155
|
+
end
|
156
|
+
|
157
|
+
def rollback
|
158
|
+
context.steps << :rollback4a
|
159
|
+
end
|
160
|
+
end
|
161
|
+
}
|
162
|
+
|
163
|
+
let(:interactor4b) {
|
164
|
+
build_interactor do
|
165
|
+
before do
|
166
|
+
context.steps << :before4b
|
167
|
+
end
|
168
|
+
|
169
|
+
after do
|
170
|
+
context.steps << :after4b
|
171
|
+
end
|
172
|
+
|
173
|
+
def call
|
174
|
+
context.steps << :call4b
|
175
|
+
end
|
176
|
+
|
177
|
+
def rollback
|
178
|
+
context.steps << :rollback4b
|
179
|
+
end
|
180
|
+
end
|
181
|
+
}
|
182
|
+
|
183
|
+
let(:interactor4c) {
|
184
|
+
build_interactor do
|
185
|
+
before do
|
186
|
+
context.steps << :before4c
|
187
|
+
end
|
188
|
+
|
189
|
+
after do
|
190
|
+
context.steps << :after4c
|
191
|
+
end
|
192
|
+
|
193
|
+
def call
|
194
|
+
context.steps << :call4c
|
195
|
+
end
|
196
|
+
|
197
|
+
def rollback
|
198
|
+
context.steps << :rollback4c
|
199
|
+
end
|
200
|
+
end
|
201
|
+
}
|
202
|
+
|
203
|
+
let(:interactor5) {
|
204
|
+
build_interactor do
|
205
|
+
before do
|
206
|
+
context.steps << :before5
|
207
|
+
end
|
208
|
+
|
209
|
+
after do
|
210
|
+
context.steps << :after5
|
211
|
+
end
|
212
|
+
|
213
|
+
def call
|
214
|
+
context.steps << :call5
|
215
|
+
end
|
216
|
+
|
217
|
+
def rollback
|
218
|
+
context.steps << :rollback5
|
219
|
+
end
|
220
|
+
end
|
221
|
+
}
|
222
|
+
|
223
|
+
let(:context) { Interactor::Context.build(steps: []) }
|
224
|
+
|
225
|
+
context "when successful" do
|
226
|
+
it "calls and runs hooks in the proper sequence" do
|
227
|
+
expect {
|
228
|
+
organizer.call(context)
|
229
|
+
}.to change {
|
230
|
+
context.steps
|
231
|
+
}.from([]).to([
|
232
|
+
:before,
|
233
|
+
:before2,
|
234
|
+
:before2a, :call2a, :after2a,
|
235
|
+
:before2b, :call2b, :after2b,
|
236
|
+
:before2c, :call2c, :after2c,
|
237
|
+
:after2,
|
238
|
+
:before3, :call3, :after3,
|
239
|
+
:before4,
|
240
|
+
:before4a, :call4a, :after4a,
|
241
|
+
:before4b, :call4b, :after4b,
|
242
|
+
:before4c, :call4c, :after4c,
|
243
|
+
:after4,
|
244
|
+
:before5, :call5, :after5,
|
245
|
+
:after
|
246
|
+
])
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
context "when a before hook fails" do
|
251
|
+
let(:organizer) {
|
252
|
+
build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
|
253
|
+
before do
|
254
|
+
context.fail!
|
255
|
+
context.steps << :before
|
256
|
+
end
|
257
|
+
|
258
|
+
after do
|
259
|
+
context.steps << :after
|
260
|
+
end
|
261
|
+
end
|
262
|
+
}
|
263
|
+
|
264
|
+
it "aborts" do
|
265
|
+
expect {
|
266
|
+
organizer.call(context)
|
267
|
+
}.not_to change {
|
268
|
+
context.steps
|
269
|
+
}
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
context "when a before hook errors" do
|
274
|
+
let(:organizer) {
|
275
|
+
build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
|
276
|
+
before do
|
277
|
+
raise "foo"
|
278
|
+
context.steps << :before
|
279
|
+
end
|
280
|
+
|
281
|
+
after do
|
282
|
+
context.steps << :after
|
283
|
+
end
|
284
|
+
end
|
285
|
+
}
|
286
|
+
|
287
|
+
it "aborts" do
|
288
|
+
expect {
|
289
|
+
organizer.call(context) rescue nil
|
290
|
+
}.not_to change {
|
291
|
+
context.steps
|
292
|
+
}
|
293
|
+
end
|
294
|
+
|
295
|
+
it "raises the error" do
|
296
|
+
expect {
|
297
|
+
organizer.call(context)
|
298
|
+
}.to raise_error("foo")
|
299
|
+
end
|
300
|
+
end
|
301
|
+
|
302
|
+
context "when an after hook fails" do
|
303
|
+
let(:organizer) {
|
304
|
+
build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
|
305
|
+
before do
|
306
|
+
context.steps << :before
|
307
|
+
end
|
308
|
+
|
309
|
+
after do
|
310
|
+
context.fail!
|
311
|
+
context.steps << :after
|
312
|
+
end
|
313
|
+
end
|
314
|
+
}
|
315
|
+
|
316
|
+
it "rolls back successfully called interactors" do
|
317
|
+
expect {
|
318
|
+
organizer.call(context)
|
319
|
+
}.to change {
|
320
|
+
context.steps
|
321
|
+
}.from([]).to([
|
322
|
+
:before,
|
323
|
+
:before2,
|
324
|
+
:before2a, :call2a, :after2a,
|
325
|
+
:before2b, :call2b, :after2b,
|
326
|
+
:before2c, :call2c, :after2c,
|
327
|
+
:after2,
|
328
|
+
:before3, :call3, :after3,
|
329
|
+
:before4,
|
330
|
+
:before4a, :call4a, :after4a,
|
331
|
+
:before4b, :call4b, :after4b,
|
332
|
+
:before4c, :call4c, :after4c,
|
333
|
+
:after4,
|
334
|
+
:before5, :call5, :after5,
|
335
|
+
:rollback5,
|
336
|
+
:rollback4c,
|
337
|
+
:rollback4b,
|
338
|
+
:rollback4a,
|
339
|
+
:rollback3,
|
340
|
+
:rollback2c,
|
341
|
+
:rollback2b,
|
342
|
+
:rollback2a
|
343
|
+
])
|
344
|
+
end
|
345
|
+
end
|
346
|
+
|
347
|
+
context "when an after hook errors" do
|
348
|
+
let(:organizer) {
|
349
|
+
build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
|
350
|
+
before do
|
351
|
+
context.steps << :before
|
352
|
+
end
|
353
|
+
|
354
|
+
after do
|
355
|
+
raise "foo"
|
356
|
+
context.steps << :after
|
357
|
+
end
|
358
|
+
end
|
359
|
+
}
|
360
|
+
|
361
|
+
it "aborts" do
|
362
|
+
expect {
|
363
|
+
organizer.call(context) rescue nil
|
364
|
+
}.to change {
|
365
|
+
context.steps
|
366
|
+
}.from([]).to([
|
367
|
+
:before,
|
368
|
+
:before2,
|
369
|
+
:before2a, :call2a, :after2a,
|
370
|
+
:before2b, :call2b, :after2b,
|
371
|
+
:before2c, :call2c, :after2c,
|
372
|
+
:after2,
|
373
|
+
:before3, :call3, :after3,
|
374
|
+
:before4,
|
375
|
+
:before4a, :call4a, :after4a,
|
376
|
+
:before4b, :call4b, :after4b,
|
377
|
+
:before4c, :call4c, :after4c,
|
378
|
+
:after4,
|
379
|
+
:before5, :call5, :after5,
|
380
|
+
:rollback5,
|
381
|
+
:rollback4c,
|
382
|
+
:rollback4b,
|
383
|
+
:rollback4a,
|
384
|
+
:rollback3,
|
385
|
+
:rollback2c,
|
386
|
+
:rollback2b,
|
387
|
+
:rollback2a
|
388
|
+
])
|
389
|
+
end
|
390
|
+
|
391
|
+
it "raises the error" do
|
392
|
+
expect {
|
393
|
+
organizer.call(context)
|
394
|
+
}.to raise_error("foo")
|
395
|
+
end
|
396
|
+
end
|
397
|
+
|
398
|
+
context "when a nested before hook fails" do
|
399
|
+
let(:interactor3) {
|
400
|
+
build_interactor do
|
401
|
+
before do
|
402
|
+
context.fail!
|
403
|
+
context.steps << :before3
|
404
|
+
end
|
405
|
+
|
406
|
+
after do
|
407
|
+
context.steps << :after3
|
408
|
+
end
|
409
|
+
|
410
|
+
def call
|
411
|
+
context.steps << :call3
|
412
|
+
end
|
413
|
+
|
414
|
+
def rollback
|
415
|
+
context.steps << :rollback3
|
416
|
+
end
|
417
|
+
end
|
418
|
+
}
|
419
|
+
|
420
|
+
it "rolls back successfully called interactors" do
|
421
|
+
expect {
|
422
|
+
organizer.call(context)
|
423
|
+
}.to change {
|
424
|
+
context.steps
|
425
|
+
}.from([]).to([
|
426
|
+
:before,
|
427
|
+
:before2,
|
428
|
+
:before2a, :call2a, :after2a,
|
429
|
+
:before2b, :call2b, :after2b,
|
430
|
+
:before2c, :call2c, :after2c,
|
431
|
+
:after2,
|
432
|
+
:rollback2c,
|
433
|
+
:rollback2b,
|
434
|
+
:rollback2a
|
435
|
+
])
|
436
|
+
end
|
437
|
+
end
|
438
|
+
|
439
|
+
context "when a nested before hook errors" do
|
440
|
+
let(:interactor3) {
|
441
|
+
build_interactor do
|
442
|
+
before do
|
443
|
+
raise "foo"
|
444
|
+
context.steps << :before3
|
445
|
+
end
|
446
|
+
|
447
|
+
after do
|
448
|
+
context.steps << :after3
|
449
|
+
end
|
450
|
+
|
451
|
+
def call
|
452
|
+
context.steps << :call3
|
453
|
+
end
|
454
|
+
|
455
|
+
def rollback
|
456
|
+
context.steps << :rollback3
|
457
|
+
end
|
458
|
+
end
|
459
|
+
}
|
460
|
+
|
461
|
+
it "rolls back successfully called interactors" do
|
462
|
+
expect {
|
463
|
+
organizer.call(context) rescue nil
|
464
|
+
}.to change {
|
465
|
+
context.steps
|
466
|
+
}.from([]).to([
|
467
|
+
:before,
|
468
|
+
:before2,
|
469
|
+
:before2a, :call2a, :after2a,
|
470
|
+
:before2b, :call2b, :after2b,
|
471
|
+
:before2c, :call2c, :after2c,
|
472
|
+
:after2,
|
473
|
+
:rollback2c,
|
474
|
+
:rollback2b,
|
475
|
+
:rollback2a
|
476
|
+
])
|
477
|
+
end
|
478
|
+
|
479
|
+
it "raises the error" do
|
480
|
+
expect {
|
481
|
+
organizer.call(context)
|
482
|
+
}.to raise_error("foo")
|
483
|
+
end
|
484
|
+
end
|
485
|
+
|
486
|
+
context "when a nested call fails" do
|
487
|
+
let(:interactor3) {
|
488
|
+
build_interactor do
|
489
|
+
before do
|
490
|
+
context.steps << :before3
|
491
|
+
end
|
492
|
+
|
493
|
+
after do
|
494
|
+
context.steps << :after3
|
495
|
+
end
|
496
|
+
|
497
|
+
def call
|
498
|
+
context.fail!
|
499
|
+
context.steps << :call3
|
500
|
+
end
|
501
|
+
|
502
|
+
def rollback
|
503
|
+
context.steps << :rollback3
|
504
|
+
end
|
505
|
+
end
|
506
|
+
}
|
507
|
+
|
508
|
+
it "rolls back successfully called interactors" do
|
509
|
+
expect {
|
510
|
+
organizer.call(context)
|
511
|
+
}.to change {
|
512
|
+
context.steps
|
513
|
+
}.from([]).to([
|
514
|
+
:before,
|
515
|
+
:before2,
|
516
|
+
:before2a, :call2a, :after2a,
|
517
|
+
:before2b, :call2b, :after2b,
|
518
|
+
:before2c, :call2c, :after2c,
|
519
|
+
:after2,
|
520
|
+
:before3,
|
521
|
+
:rollback2c,
|
522
|
+
:rollback2b,
|
523
|
+
:rollback2a
|
524
|
+
])
|
525
|
+
end
|
526
|
+
end
|
527
|
+
|
528
|
+
context "when a nested call errors" do
|
529
|
+
let(:interactor3) {
|
530
|
+
build_interactor do
|
531
|
+
before do
|
532
|
+
context.steps << :before3
|
533
|
+
end
|
534
|
+
|
535
|
+
after do
|
536
|
+
context.steps << :after3
|
537
|
+
end
|
538
|
+
|
539
|
+
def call
|
540
|
+
raise "foo"
|
541
|
+
context.steps << :call3
|
542
|
+
end
|
543
|
+
|
544
|
+
def rollback
|
545
|
+
context.steps << :rollback3
|
546
|
+
end
|
547
|
+
end
|
548
|
+
}
|
549
|
+
|
550
|
+
it "rolls back successfully called interactors" do
|
551
|
+
expect {
|
552
|
+
organizer.call(context) rescue nil
|
553
|
+
}.to change {
|
554
|
+
context.steps
|
555
|
+
}.from([]).to([
|
556
|
+
:before,
|
557
|
+
:before2,
|
558
|
+
:before2a, :call2a, :after2a,
|
559
|
+
:before2b, :call2b, :after2b,
|
560
|
+
:before2c, :call2c, :after2c,
|
561
|
+
:after2,
|
562
|
+
:before3,
|
563
|
+
:rollback2c,
|
564
|
+
:rollback2b,
|
565
|
+
:rollback2a
|
566
|
+
])
|
567
|
+
end
|
568
|
+
|
569
|
+
it "raises the error" do
|
570
|
+
expect {
|
571
|
+
organizer.call(context)
|
572
|
+
}.to raise_error("foo")
|
573
|
+
end
|
574
|
+
end
|
575
|
+
|
576
|
+
context "when a nested after hook fails" do
|
577
|
+
let(:interactor3) {
|
578
|
+
build_interactor do
|
579
|
+
before do
|
580
|
+
context.steps << :before3
|
581
|
+
end
|
582
|
+
|
583
|
+
after do
|
584
|
+
context.fail!
|
585
|
+
context.steps << :after3
|
586
|
+
end
|
587
|
+
|
588
|
+
def call
|
589
|
+
context.steps << :call3
|
590
|
+
end
|
591
|
+
|
592
|
+
def rollback
|
593
|
+
context.steps << :rollback3
|
594
|
+
end
|
595
|
+
end
|
596
|
+
}
|
597
|
+
|
598
|
+
it "rolls back successfully called interactors and the failed interactor" do
|
599
|
+
expect {
|
600
|
+
organizer.call(context)
|
601
|
+
}.to change {
|
602
|
+
context.steps
|
603
|
+
}.from([]).to([
|
604
|
+
:before,
|
605
|
+
:before2,
|
606
|
+
:before2a, :call2a, :after2a,
|
607
|
+
:before2b, :call2b, :after2b,
|
608
|
+
:before2c, :call2c, :after2c,
|
609
|
+
:after2,
|
610
|
+
:before3, :call3,
|
611
|
+
:rollback3,
|
612
|
+
:rollback2c,
|
613
|
+
:rollback2b,
|
614
|
+
:rollback2a
|
615
|
+
])
|
616
|
+
end
|
617
|
+
end
|
618
|
+
|
619
|
+
context "when a nested after hook errors" do
|
620
|
+
let(:interactor3) {
|
621
|
+
build_interactor do
|
622
|
+
before do
|
623
|
+
context.steps << :before3
|
624
|
+
end
|
625
|
+
|
626
|
+
after do
|
627
|
+
raise "foo"
|
628
|
+
context.steps << :after3
|
629
|
+
end
|
630
|
+
|
631
|
+
def call
|
632
|
+
context.steps << :call3
|
633
|
+
end
|
634
|
+
|
635
|
+
def rollback
|
636
|
+
context.steps << :rollback3
|
637
|
+
end
|
638
|
+
end
|
639
|
+
}
|
640
|
+
|
641
|
+
it "rolls back successfully called interactors and the failed interactor" do
|
642
|
+
expect {
|
643
|
+
organizer.call(context) rescue nil
|
644
|
+
}.to change {
|
645
|
+
context.steps
|
646
|
+
}.from([]).to([
|
647
|
+
:before,
|
648
|
+
:before2,
|
649
|
+
:before2a, :call2a, :after2a,
|
650
|
+
:before2b, :call2b, :after2b,
|
651
|
+
:before2c, :call2c, :after2c,
|
652
|
+
:after2,
|
653
|
+
:before3, :call3,
|
654
|
+
:rollback3,
|
655
|
+
:rollback2c,
|
656
|
+
:rollback2b,
|
657
|
+
:rollback2a
|
658
|
+
])
|
659
|
+
end
|
660
|
+
|
661
|
+
it "raises the error" do
|
662
|
+
expect {
|
663
|
+
organizer.call(context)
|
664
|
+
}.to raise_error("foo")
|
665
|
+
end
|
666
|
+
end
|
667
|
+
|
668
|
+
context "when a deeply nested before hook fails" do
|
669
|
+
let(:interactor4b) {
|
670
|
+
build_interactor do
|
671
|
+
before do
|
672
|
+
context.fail!
|
673
|
+
context.steps << :before4b
|
674
|
+
end
|
675
|
+
|
676
|
+
after do
|
677
|
+
context.steps << :after4b
|
678
|
+
end
|
679
|
+
|
680
|
+
def call
|
681
|
+
context.steps << :call4b
|
682
|
+
end
|
683
|
+
|
684
|
+
def rollback
|
685
|
+
context.steps << :rollback4b
|
686
|
+
end
|
687
|
+
end
|
688
|
+
}
|
689
|
+
|
690
|
+
it "rolls back successfully called interactors" do
|
691
|
+
expect {
|
692
|
+
organizer.call(context)
|
693
|
+
}.to change {
|
694
|
+
context.steps
|
695
|
+
}.from([]).to([
|
696
|
+
:before,
|
697
|
+
:before2,
|
698
|
+
:before2a, :call2a, :after2a,
|
699
|
+
:before2b, :call2b, :after2b,
|
700
|
+
:before2c, :call2c, :after2c,
|
701
|
+
:after2,
|
702
|
+
:before3, :call3, :after3,
|
703
|
+
:before4,
|
704
|
+
:before4a, :call4a, :after4a,
|
705
|
+
:rollback4a,
|
706
|
+
:rollback3,
|
707
|
+
:rollback2c,
|
708
|
+
:rollback2b,
|
709
|
+
:rollback2a
|
710
|
+
])
|
711
|
+
end
|
712
|
+
end
|
713
|
+
|
714
|
+
context "when a deeply nested before hook errors" do
|
715
|
+
let(:interactor4b) {
|
716
|
+
build_interactor do
|
717
|
+
before do
|
718
|
+
raise "foo"
|
719
|
+
context.steps << :before4b
|
720
|
+
end
|
721
|
+
|
722
|
+
after do
|
723
|
+
context.steps << :after4b
|
724
|
+
end
|
725
|
+
|
726
|
+
def call
|
727
|
+
context.steps << :call4b
|
728
|
+
end
|
729
|
+
|
730
|
+
def rollback
|
731
|
+
context.steps << :rollback4b
|
732
|
+
end
|
733
|
+
end
|
734
|
+
}
|
735
|
+
|
736
|
+
it "rolls back successfully called interactors" do
|
737
|
+
expect {
|
738
|
+
organizer.call(context) rescue nil
|
739
|
+
}.to change {
|
740
|
+
context.steps
|
741
|
+
}.from([]).to([
|
742
|
+
:before,
|
743
|
+
:before2,
|
744
|
+
:before2a, :call2a, :after2a,
|
745
|
+
:before2b, :call2b, :after2b,
|
746
|
+
:before2c, :call2c, :after2c,
|
747
|
+
:after2,
|
748
|
+
:before3, :call3, :after3,
|
749
|
+
:before4,
|
750
|
+
:before4a, :call4a, :after4a,
|
751
|
+
:rollback4a,
|
752
|
+
:rollback3,
|
753
|
+
:rollback2c,
|
754
|
+
:rollback2b,
|
755
|
+
:rollback2a
|
756
|
+
])
|
757
|
+
end
|
758
|
+
|
759
|
+
it "raises the error" do
|
760
|
+
expect {
|
761
|
+
organizer.call(context)
|
762
|
+
}.to raise_error("foo")
|
763
|
+
end
|
764
|
+
end
|
765
|
+
|
766
|
+
context "when a deeply nested call fails" do
|
767
|
+
let(:interactor4b) {
|
768
|
+
build_interactor do
|
769
|
+
before do
|
770
|
+
context.steps << :before4b
|
771
|
+
end
|
772
|
+
|
773
|
+
after do
|
774
|
+
context.steps << :after4b
|
775
|
+
end
|
776
|
+
|
777
|
+
def call
|
778
|
+
context.fail!
|
779
|
+
context.steps << :call4b
|
780
|
+
end
|
781
|
+
|
782
|
+
def rollback
|
783
|
+
context.steps << :rollback4b
|
784
|
+
end
|
785
|
+
end
|
786
|
+
}
|
787
|
+
|
788
|
+
it "rolls back successfully called interactors" do
|
789
|
+
expect {
|
790
|
+
organizer.call(context)
|
791
|
+
}.to change {
|
792
|
+
context.steps
|
793
|
+
}.from([]).to([
|
794
|
+
:before,
|
795
|
+
:before2,
|
796
|
+
:before2a, :call2a, :after2a,
|
797
|
+
:before2b, :call2b, :after2b,
|
798
|
+
:before2c, :call2c, :after2c,
|
799
|
+
:after2,
|
800
|
+
:before3, :call3, :after3,
|
801
|
+
:before4,
|
802
|
+
:before4a, :call4a, :after4a,
|
803
|
+
:before4b,
|
804
|
+
:rollback4a,
|
805
|
+
:rollback3,
|
806
|
+
:rollback2c,
|
807
|
+
:rollback2b,
|
808
|
+
:rollback2a
|
809
|
+
])
|
810
|
+
end
|
811
|
+
end
|
812
|
+
|
813
|
+
context "when a deeply nested call errors" do
|
814
|
+
let(:interactor4b) {
|
815
|
+
build_interactor do
|
816
|
+
before do
|
817
|
+
context.steps << :before4b
|
818
|
+
end
|
819
|
+
|
820
|
+
after do
|
821
|
+
context.steps << :after4b
|
822
|
+
end
|
823
|
+
|
824
|
+
def call
|
825
|
+
raise "foo"
|
826
|
+
context.steps << :call4b
|
827
|
+
end
|
828
|
+
|
829
|
+
def rollback
|
830
|
+
context.steps << :rollback4b
|
831
|
+
end
|
832
|
+
end
|
833
|
+
}
|
834
|
+
|
835
|
+
it "rolls back successfully called interactors" do
|
836
|
+
expect {
|
837
|
+
organizer.call(context) rescue nil
|
838
|
+
}.to change {
|
839
|
+
context.steps
|
840
|
+
}.from([]).to([
|
841
|
+
:before,
|
842
|
+
:before2,
|
843
|
+
:before2a, :call2a, :after2a,
|
844
|
+
:before2b, :call2b, :after2b,
|
845
|
+
:before2c, :call2c, :after2c,
|
846
|
+
:after2,
|
847
|
+
:before3, :call3, :after3,
|
848
|
+
:before4,
|
849
|
+
:before4a, :call4a, :after4a,
|
850
|
+
:before4b,
|
851
|
+
:rollback4a,
|
852
|
+
:rollback3,
|
853
|
+
:rollback2c,
|
854
|
+
:rollback2b,
|
855
|
+
:rollback2a
|
856
|
+
])
|
857
|
+
end
|
858
|
+
|
859
|
+
it "raises the error" do
|
860
|
+
expect {
|
861
|
+
organizer.call(context)
|
862
|
+
}.to raise_error("foo")
|
863
|
+
end
|
864
|
+
end
|
865
|
+
|
866
|
+
context "when a deeply nested after hook fails" do
|
867
|
+
let(:interactor4b) {
|
868
|
+
build_interactor do
|
869
|
+
before do
|
870
|
+
context.steps << :before4b
|
871
|
+
end
|
872
|
+
|
873
|
+
after do
|
874
|
+
context.fail!
|
875
|
+
context.steps << :after4b
|
876
|
+
end
|
877
|
+
|
878
|
+
def call
|
879
|
+
context.steps << :call4b
|
880
|
+
end
|
881
|
+
|
882
|
+
def rollback
|
883
|
+
context.steps << :rollback4b
|
884
|
+
end
|
885
|
+
end
|
886
|
+
}
|
887
|
+
|
888
|
+
it "rolls back successfully called interactors and the failed interactor" do
|
889
|
+
expect {
|
890
|
+
organizer.call(context)
|
891
|
+
}.to change {
|
892
|
+
context.steps
|
893
|
+
}.from([]).to([
|
894
|
+
:before,
|
895
|
+
:before2,
|
896
|
+
:before2a, :call2a, :after2a,
|
897
|
+
:before2b, :call2b, :after2b,
|
898
|
+
:before2c, :call2c, :after2c,
|
899
|
+
:after2,
|
900
|
+
:before3, :call3, :after3,
|
901
|
+
:before4,
|
902
|
+
:before4a, :call4a, :after4a,
|
903
|
+
:before4b, :call4b,
|
904
|
+
:rollback4b,
|
905
|
+
:rollback4a,
|
906
|
+
:rollback3,
|
907
|
+
:rollback2c,
|
908
|
+
:rollback2b,
|
909
|
+
:rollback2a
|
910
|
+
])
|
911
|
+
end
|
912
|
+
end
|
913
|
+
|
914
|
+
context "when a deeply nested after hook errors" do
|
915
|
+
let(:interactor4b) {
|
916
|
+
build_interactor do
|
917
|
+
before do
|
918
|
+
context.steps << :before4b
|
919
|
+
end
|
920
|
+
|
921
|
+
after do
|
922
|
+
raise "foo"
|
923
|
+
context.steps << :after4b
|
924
|
+
end
|
925
|
+
|
926
|
+
def call
|
927
|
+
context.steps << :call4b
|
928
|
+
end
|
929
|
+
|
930
|
+
def rollback
|
931
|
+
context.steps << :rollback4b
|
932
|
+
end
|
933
|
+
end
|
934
|
+
}
|
935
|
+
|
936
|
+
it "rolls back successfully called interactors and the failed interactor" do
|
937
|
+
expect {
|
938
|
+
organizer.call(context) rescue nil
|
939
|
+
}.to change {
|
940
|
+
context.steps
|
941
|
+
}.from([]).to([
|
942
|
+
:before,
|
943
|
+
:before2,
|
944
|
+
:before2a, :call2a, :after2a,
|
945
|
+
:before2b, :call2b, :after2b,
|
946
|
+
:before2c, :call2c, :after2c,
|
947
|
+
:after2,
|
948
|
+
:before3, :call3, :after3,
|
949
|
+
:before4,
|
950
|
+
:before4a, :call4a, :after4a,
|
951
|
+
:before4b, :call4b,
|
952
|
+
:rollback4b,
|
953
|
+
:rollback4a,
|
954
|
+
:rollback3,
|
955
|
+
:rollback2c,
|
956
|
+
:rollback2b,
|
957
|
+
:rollback2a
|
958
|
+
])
|
959
|
+
end
|
960
|
+
|
961
|
+
it "raises the error" do
|
962
|
+
expect {
|
963
|
+
organizer.call(context)
|
964
|
+
}.to raise_error("foo")
|
965
|
+
end
|
966
|
+
end
|
967
|
+
end
|