functional_interactor 0.0.1

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.
data/Rakefile ADDED
@@ -0,0 +1,6 @@
1
+ require "bundler/gem_tasks"
2
+ require "rspec/core/rake_task"
3
+
4
+ RSpec::Core::RakeTask.new(:spec)
5
+
6
+ task default: :spec
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ Gem::Specification.new do |spec|
4
+ spec.name = "functional_interactor"
5
+ spec.version = "0.0.1"
6
+
7
+ spec.author = "Ho-Sheng Hsiao"
8
+ spec.email = "hosh@legal.io"
9
+ spec.description = "Functional Interactor using Kase protocol and composition operators"
10
+ spec.summary = "Functional Interactor, composable, higher-order interactors. Complete rewrite of collectiveideas/interactor"
11
+ spec.homepage = "https://github.com/hosh/functional_interactor"
12
+ spec.license = "MIT"
13
+
14
+ spec.files = `git ls-files`.split($/)
15
+ spec.test_files = spec.files.grep(/^spec/)
16
+
17
+ spec.add_dependency 'activesupport', '~>4.2'
18
+ #spec.add_dependency 'hosh-kase'
19
+ spec.add_development_dependency "bundler", "~> 1.7"
20
+ spec.add_development_dependency "rake", "~> 10.3"
21
+ end
@@ -0,0 +1,38 @@
1
+ require 'active_support/concern'
2
+ require 'interactors'
3
+
4
+ # Include this to support interactor interface
5
+ module FunctionalInteractor
6
+ extend ActiveSupport::Concern
7
+
8
+ included do
9
+ attr_reader :context # Probably don't need this anymore, just pass it into #call
10
+ alias_method :|, :compose
11
+ end
12
+
13
+ # | aliases to compose, so you can do something like:
14
+ # (CreateOrder | ChargeCard.new(token: params[:token]) | SendThankYou).call
15
+ def compose(interactor)
16
+ Interactors::Sequence.new.compose(self).compose(interactor)
17
+ end
18
+
19
+ alias_method :|, :compose
20
+
21
+ def call(context)
22
+ [:ok, context]
23
+ end
24
+
25
+ class_methods do
26
+ # | aliases to compose, so you can do something like:
27
+ # (CreateOrder | ChargeCard.new(token: params[:token]) | SendThankYou).call
28
+ def compose(interactor)
29
+ Interactors::Sequence.new.compose(self).compose(interactor)
30
+ end
31
+
32
+ alias_method :|, :compose
33
+
34
+ def call(context = {})
35
+ new.call(context)
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,12 @@
1
+ require 'functional_interactor'
2
+
3
+ module Interactors
4
+ autoload :Sequence, 'interactors/sequence'
5
+ autoload :Anonymous, 'interactors/anonymous'
6
+ autoload :Simple, 'interactors/simple'
7
+
8
+ # Helper
9
+ def self.new(&blk)
10
+ Interactors::Anonymous.new(&blk)
11
+ end
12
+ end
@@ -0,0 +1,20 @@
1
+ require 'interactor'
2
+
3
+ module Interactors
4
+ # Anonymous interactors
5
+ # Does two things:
6
+ # - passes context to the proc
7
+ # - honors #compose interface
8
+ class Anonymous
9
+ include FunctionalInteractor
10
+ attr_reader :block
11
+
12
+ def initialize(&blk)
13
+ @block = blk
14
+ end
15
+
16
+ def call(context = {})
17
+ block.call(context)
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,28 @@
1
+ require 'interactor'
2
+
3
+ module Interactors
4
+ # An Interactor that is a sequence of Interactors
5
+ class Sequence
6
+ include FunctionalInteractor
7
+ include Kase
8
+
9
+ def interactions
10
+ @__interactions ||= []
11
+ end
12
+
13
+ def compose(interactor)
14
+ interactions << interactor
15
+ self
16
+ end
17
+
18
+ def call(context = {})
19
+ interactions.each do |interactor|
20
+ results = interactor.call(context)
21
+ next if results[0] == :ok
22
+ return results if results[0] == :error
23
+ raise ArgumentError, "Return value from interactor must be [:ok, context] or [:error, ...]"
24
+ end
25
+ [:ok, context]
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,35 @@
1
+ require 'interactor'
2
+
3
+ module Interactors
4
+ # Anonymous interactors
5
+ # Does two things:
6
+ # - passes context to the proc
7
+ # - honors #compose interface
8
+ # - Only return [:error, ... ] if exception is raised
9
+ # - otherwise, always return [:ok, context]
10
+ class Simple
11
+ include FunctionalInteractor
12
+ attr_reader :block
13
+
14
+ def initialize(&blk)
15
+ @block = blk
16
+ end
17
+
18
+ def call(context = {})
19
+ handle_error do
20
+ block.call(context)
21
+ end
22
+ end
23
+
24
+ # This is meant to be overridable. Maybe you
25
+ # want to use something else, such as capturing
26
+ # network errors, or wrap around specific third-party
27
+ # libraries.
28
+ def handle_error
29
+ yield
30
+ [:ok, context]
31
+ rescue Exception => e
32
+ [:error, e]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,1741 @@
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
+ around do |interactor|
30
+ context.steps << :around_before
31
+ interactor.call
32
+ context.steps << :around_after
33
+ end
34
+
35
+ before do
36
+ context.steps << :before
37
+ end
38
+
39
+ after do
40
+ context.steps << :after
41
+ end
42
+ end
43
+ }
44
+
45
+ let(:organizer2) {
46
+ build_organizer(organize: [interactor2a, interactor2b, interactor2c]) do
47
+ around do |interactor|
48
+ context.steps << :around_before2
49
+ interactor.call
50
+ context.steps << :around_after2
51
+ end
52
+
53
+ before do
54
+ context.steps << :before2
55
+ end
56
+
57
+ after do
58
+ context.steps << :after2
59
+ end
60
+ end
61
+ }
62
+
63
+ let(:interactor2a) {
64
+ build_interactor do
65
+ around do |interactor|
66
+ context.steps << :around_before2a
67
+ interactor.call
68
+ context.steps << :around_after2a
69
+ end
70
+
71
+ before do
72
+ context.steps << :before2a
73
+ end
74
+
75
+ after do
76
+ context.steps << :after2a
77
+ end
78
+
79
+ def call
80
+ context.steps << :call2a
81
+ end
82
+
83
+ def rollback
84
+ context.steps << :rollback2a
85
+ end
86
+ end
87
+ }
88
+
89
+ let(:interactor2b) {
90
+ build_interactor do
91
+ around do |interactor|
92
+ context.steps << :around_before2b
93
+ interactor.call
94
+ context.steps << :around_after2b
95
+ end
96
+
97
+ before do
98
+ context.steps << :before2b
99
+ end
100
+
101
+ after do
102
+ context.steps << :after2b
103
+ end
104
+
105
+ def call
106
+ context.steps << :call2b
107
+ end
108
+
109
+ def rollback
110
+ context.steps << :rollback2b
111
+ end
112
+ end
113
+ }
114
+
115
+ let(:interactor2c) {
116
+ build_interactor do
117
+ around do |interactor|
118
+ context.steps << :around_before2c
119
+ interactor.call
120
+ context.steps << :around_after2c
121
+ end
122
+
123
+ before do
124
+ context.steps << :before2c
125
+ end
126
+
127
+ after do
128
+ context.steps << :after2c
129
+ end
130
+
131
+ def call
132
+ context.steps << :call2c
133
+ end
134
+
135
+ def rollback
136
+ context.steps << :rollback2c
137
+ end
138
+ end
139
+ }
140
+
141
+ let(:interactor3) {
142
+ build_interactor do
143
+ around do |interactor|
144
+ context.steps << :around_before3
145
+ interactor.call
146
+ context.steps << :around_after3
147
+ end
148
+
149
+ before do
150
+ context.steps << :before3
151
+ end
152
+
153
+ after do
154
+ context.steps << :after3
155
+ end
156
+
157
+ def call
158
+ context.steps << :call3
159
+ end
160
+
161
+ def rollback
162
+ context.steps << :rollback3
163
+ end
164
+ end
165
+ }
166
+
167
+ let(:organizer4) {
168
+ build_organizer(organize: [interactor4a, interactor4b, interactor4c]) do
169
+ around do |interactor|
170
+ context.steps << :around_before4
171
+ interactor.call
172
+ context.steps << :around_after4
173
+ end
174
+
175
+ before do
176
+ context.steps << :before4
177
+ end
178
+
179
+ after do
180
+ context.steps << :after4
181
+ end
182
+ end
183
+ }
184
+
185
+ let(:interactor4a) {
186
+ build_interactor do
187
+ around do |interactor|
188
+ context.steps << :around_before4a
189
+ interactor.call
190
+ context.steps << :around_after4a
191
+ end
192
+
193
+ before do
194
+ context.steps << :before4a
195
+ end
196
+
197
+ after do
198
+ context.steps << :after4a
199
+ end
200
+
201
+ def call
202
+ context.steps << :call4a
203
+ end
204
+
205
+ def rollback
206
+ context.steps << :rollback4a
207
+ end
208
+ end
209
+ }
210
+
211
+ let(:interactor4b) {
212
+ build_interactor do
213
+ around do |interactor|
214
+ context.steps << :around_before4b
215
+ interactor.call
216
+ context.steps << :around_after4b
217
+ end
218
+
219
+ before do
220
+ context.steps << :before4b
221
+ end
222
+
223
+ after do
224
+ context.steps << :after4b
225
+ end
226
+
227
+ def call
228
+ context.steps << :call4b
229
+ end
230
+
231
+ def rollback
232
+ context.steps << :rollback4b
233
+ end
234
+ end
235
+ }
236
+
237
+ let(:interactor4c) {
238
+ build_interactor do
239
+ around do |interactor|
240
+ context.steps << :around_before4c
241
+ interactor.call
242
+ context.steps << :around_after4c
243
+ end
244
+
245
+ before do
246
+ context.steps << :before4c
247
+ end
248
+
249
+ after do
250
+ context.steps << :after4c
251
+ end
252
+
253
+ def call
254
+ context.steps << :call4c
255
+ end
256
+
257
+ def rollback
258
+ context.steps << :rollback4c
259
+ end
260
+ end
261
+ }
262
+
263
+ let(:interactor5) {
264
+ build_interactor do
265
+ around do |interactor|
266
+ context.steps << :around_before5
267
+ interactor.call
268
+ context.steps << :around_after5
269
+ end
270
+
271
+ before do
272
+ context.steps << :before5
273
+ end
274
+
275
+ after do
276
+ context.steps << :after5
277
+ end
278
+
279
+ def call
280
+ context.steps << :call5
281
+ end
282
+
283
+ def rollback
284
+ context.steps << :rollback5
285
+ end
286
+ end
287
+ }
288
+
289
+ let(:context) { Interactor::Context.new(steps: []) }
290
+
291
+ context "when successful" do
292
+ it "calls and runs hooks in the proper sequence" do
293
+ expect {
294
+ organizer.call(context)
295
+ }.to change {
296
+ context.steps
297
+ }.from([]).to([
298
+ :around_before, :before,
299
+ :around_before2, :before2,
300
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
301
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
302
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
303
+ :after2, :around_after2,
304
+ :around_before3, :before3, :call3, :after3, :around_after3,
305
+ :around_before4, :before4,
306
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
307
+ :around_before4b, :before4b, :call4b, :after4b, :around_after4b,
308
+ :around_before4c, :before4c, :call4c, :after4c, :around_after4c,
309
+ :after4, :around_after4,
310
+ :around_before5, :before5, :call5, :after5, :around_after5,
311
+ :after, :around_after
312
+ ])
313
+ end
314
+ end
315
+
316
+ context "when an around hook fails early" do
317
+ let(:organizer) {
318
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
319
+ around do |interactor|
320
+ context.fail!
321
+ context.steps << :around_before
322
+ interactor.call
323
+ context.steps << :around_after
324
+ end
325
+
326
+ before do
327
+ context.fail!
328
+ context.steps << :before
329
+ end
330
+
331
+ after do
332
+ context.steps << :after
333
+ end
334
+ end
335
+ }
336
+
337
+ it "aborts" do
338
+ expect {
339
+ organizer.call(context)
340
+ }.not_to change {
341
+ context.steps
342
+ }
343
+ end
344
+ end
345
+
346
+ context "when an around hook errors early" do
347
+ let(:organizer) {
348
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
349
+ around do |interactor|
350
+ raise "foo"
351
+ context.steps << :around_before
352
+ interactor.call
353
+ context.steps << :around_after
354
+ end
355
+
356
+ before do
357
+ context.fail!
358
+ context.steps << :before
359
+ end
360
+
361
+ after do
362
+ context.steps << :after
363
+ end
364
+ end
365
+ }
366
+
367
+ it "aborts" do
368
+ expect {
369
+ organizer.call(context) rescue nil
370
+ }.not_to change {
371
+ context.steps
372
+ }
373
+ end
374
+
375
+ it "raises the error" do
376
+ expect {
377
+ organizer.call(context)
378
+ }.to raise_error("foo")
379
+ end
380
+ end
381
+
382
+ context "when a before hook fails" do
383
+ let(:organizer) {
384
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
385
+ around do |interactor|
386
+ context.steps << :around_before
387
+ interactor.call
388
+ context.steps << :around_after
389
+ end
390
+
391
+ before do
392
+ context.fail!
393
+ context.steps << :before
394
+ end
395
+
396
+ after do
397
+ context.steps << :after
398
+ end
399
+ end
400
+ }
401
+
402
+ it "aborts" do
403
+ expect {
404
+ organizer.call(context)
405
+ }.to change {
406
+ context.steps
407
+ }.from([]).to([
408
+ :around_before
409
+ ])
410
+ end
411
+ end
412
+
413
+ context "when a before hook errors" do
414
+ let(:organizer) {
415
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
416
+ around do |interactor|
417
+ context.steps << :around_before
418
+ interactor.call
419
+ context.steps << :around_after
420
+ end
421
+
422
+ before do
423
+ raise "foo"
424
+ context.steps << :before
425
+ end
426
+
427
+ after do
428
+ context.steps << :after
429
+ end
430
+ end
431
+ }
432
+
433
+ it "aborts" do
434
+ expect {
435
+ organizer.call(context) rescue nil
436
+ }.to change {
437
+ context.steps
438
+ }.from([]).to([
439
+ :around_before
440
+ ])
441
+ end
442
+
443
+ it "raises the error" do
444
+ expect {
445
+ organizer.call(context)
446
+ }.to raise_error("foo")
447
+ end
448
+ end
449
+
450
+ context "when an after hook fails" do
451
+ let(:organizer) {
452
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
453
+ around do |interactor|
454
+ context.steps << :around_before
455
+ interactor.call
456
+ context.steps << :around_after
457
+ end
458
+
459
+ before do
460
+ context.steps << :before
461
+ end
462
+
463
+ after do
464
+ context.fail!
465
+ context.steps << :after
466
+ end
467
+ end
468
+ }
469
+
470
+ it "rolls back successfully called interactors and the failed interactor" do
471
+ expect {
472
+ organizer.call(context)
473
+ }.to change {
474
+ context.steps
475
+ }.from([]).to([
476
+ :around_before, :before,
477
+ :around_before2, :before2,
478
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
479
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
480
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
481
+ :after2, :around_after2,
482
+ :around_before3, :before3, :call3, :after3, :around_after3,
483
+ :around_before4, :before4,
484
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
485
+ :around_before4b, :before4b, :call4b, :after4b, :around_after4b,
486
+ :around_before4c, :before4c, :call4c, :after4c, :around_after4c,
487
+ :after4, :around_after4,
488
+ :around_before5, :before5, :call5, :after5, :around_after5,
489
+ :rollback5,
490
+ :rollback4c,
491
+ :rollback4b,
492
+ :rollback4a,
493
+ :rollback3,
494
+ :rollback2c,
495
+ :rollback2b,
496
+ :rollback2a
497
+ ])
498
+ end
499
+ end
500
+
501
+ context "when an after hook errors" do
502
+ let(:organizer) {
503
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
504
+ around do |interactor|
505
+ context.steps << :around_before
506
+ interactor.call
507
+ context.steps << :around_after
508
+ end
509
+
510
+ before do
511
+ context.steps << :before
512
+ end
513
+
514
+ after do
515
+ raise "foo"
516
+ context.steps << :after
517
+ end
518
+ end
519
+ }
520
+
521
+ it "rolls back successfully called interactors and the failed interactor" do
522
+ expect {
523
+ organizer.call(context) rescue nil
524
+ }.to change {
525
+ context.steps
526
+ }.from([]).to([
527
+ :around_before, :before,
528
+ :around_before2, :before2,
529
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
530
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
531
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
532
+ :after2, :around_after2,
533
+ :around_before3, :before3, :call3, :after3, :around_after3,
534
+ :around_before4, :before4,
535
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
536
+ :around_before4b, :before4b, :call4b, :after4b, :around_after4b,
537
+ :around_before4c, :before4c, :call4c, :after4c, :around_after4c,
538
+ :after4, :around_after4,
539
+ :around_before5, :before5, :call5, :after5, :around_after5,
540
+ :rollback5,
541
+ :rollback4c,
542
+ :rollback4b,
543
+ :rollback4a,
544
+ :rollback3,
545
+ :rollback2c,
546
+ :rollback2b,
547
+ :rollback2a
548
+ ])
549
+ end
550
+
551
+ it "raises the error" do
552
+ expect {
553
+ organizer.call(context)
554
+ }.to raise_error("foo")
555
+ end
556
+ end
557
+
558
+ context "when an around hook fails late" do
559
+ let(:organizer) {
560
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
561
+ around do |interactor|
562
+ context.steps << :around_before
563
+ interactor.call
564
+ context.fail!
565
+ context.steps << :around_after
566
+ end
567
+
568
+ before do
569
+ context.steps << :before
570
+ end
571
+
572
+ after do
573
+ context.steps << :after
574
+ end
575
+ end
576
+ }
577
+
578
+ it "rolls back successfully called interactors and the failed interactor" do
579
+ expect {
580
+ organizer.call(context)
581
+ }.to change {
582
+ context.steps
583
+ }.from([]).to([
584
+ :around_before, :before,
585
+ :around_before2, :before2,
586
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
587
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
588
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
589
+ :after2, :around_after2,
590
+ :around_before3, :before3, :call3, :after3, :around_after3,
591
+ :around_before4, :before4,
592
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
593
+ :around_before4b, :before4b, :call4b, :after4b, :around_after4b,
594
+ :around_before4c, :before4c, :call4c, :after4c, :around_after4c,
595
+ :after4, :around_after4,
596
+ :around_before5, :before5, :call5, :after5, :around_after5,
597
+ :after,
598
+ :rollback5,
599
+ :rollback4c,
600
+ :rollback4b,
601
+ :rollback4a,
602
+ :rollback3,
603
+ :rollback2c,
604
+ :rollback2b,
605
+ :rollback2a
606
+ ])
607
+ end
608
+ end
609
+
610
+ context "when an around hook errors late" do
611
+ let(:organizer) {
612
+ build_organizer(organize: [organizer2, interactor3, organizer4, interactor5]) do
613
+ around do |interactor|
614
+ context.steps << :around_before
615
+ interactor.call
616
+ raise "foo"
617
+ context.steps << :around_after
618
+ end
619
+
620
+ before do
621
+ context.steps << :before
622
+ end
623
+
624
+ after do
625
+ context.steps << :after
626
+ end
627
+ end
628
+ }
629
+
630
+ it "rolls back successfully called interactors and the failed interactor" do
631
+ expect {
632
+ organizer.call(context) rescue nil
633
+ }.to change {
634
+ context.steps
635
+ }.from([]).to([
636
+ :around_before, :before,
637
+ :around_before2, :before2,
638
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
639
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
640
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
641
+ :after2, :around_after2,
642
+ :around_before3, :before3, :call3, :after3, :around_after3,
643
+ :around_before4, :before4,
644
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
645
+ :around_before4b, :before4b, :call4b, :after4b, :around_after4b,
646
+ :around_before4c, :before4c, :call4c, :after4c, :around_after4c,
647
+ :after4, :around_after4,
648
+ :around_before5, :before5, :call5, :after5, :around_after5,
649
+ :after,
650
+ :rollback5,
651
+ :rollback4c,
652
+ :rollback4b,
653
+ :rollback4a,
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 nested around hook fails early" do
669
+ let(:interactor3) {
670
+ build_interactor do
671
+ around do |interactor|
672
+ context.fail!
673
+ context.steps << :around_before3
674
+ interactor.call
675
+ context.steps << :around_after3
676
+ end
677
+
678
+ before do
679
+ context.steps << :before3
680
+ end
681
+
682
+ after do
683
+ context.steps << :after3
684
+ end
685
+
686
+ def call
687
+ context.steps << :call3
688
+ end
689
+
690
+ def rollback
691
+ context.steps << :rollback3
692
+ end
693
+ end
694
+ }
695
+
696
+ it "rolls back successfully called interactors" do
697
+ expect {
698
+ organizer.call(context)
699
+ }.to change {
700
+ context.steps
701
+ }.from([]).to([
702
+ :around_before, :before,
703
+ :around_before2, :before2,
704
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
705
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
706
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
707
+ :after2, :around_after2,
708
+ :rollback2c,
709
+ :rollback2b,
710
+ :rollback2a
711
+ ])
712
+ end
713
+ end
714
+
715
+ context "when a nested around hook errors early" do
716
+ let(:interactor3) {
717
+ build_interactor do
718
+ around do |interactor|
719
+ raise "foo"
720
+ context.steps << :around_before3
721
+ interactor.call
722
+ context.steps << :around_after3
723
+ end
724
+
725
+ before do
726
+ context.steps << :before3
727
+ end
728
+
729
+ after do
730
+ context.steps << :after3
731
+ end
732
+
733
+ def call
734
+ context.steps << :call3
735
+ end
736
+
737
+ def rollback
738
+ context.steps << :rollback3
739
+ end
740
+ end
741
+ }
742
+
743
+ it "rolls back successfully called interactors" do
744
+ expect {
745
+ organizer.call(context) rescue nil
746
+ }.to change {
747
+ context.steps
748
+ }.from([]).to([
749
+ :around_before, :before,
750
+ :around_before2, :before2,
751
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
752
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
753
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
754
+ :after2, :around_after2,
755
+ :rollback2c,
756
+ :rollback2b,
757
+ :rollback2a
758
+ ])
759
+ end
760
+
761
+ it "raises the error" do
762
+ expect {
763
+ organizer.call(context)
764
+ }.to raise_error("foo")
765
+ end
766
+ end
767
+
768
+ context "when a nested before hook fails" do
769
+ let(:interactor3) {
770
+ build_interactor do
771
+ around do |interactor|
772
+ context.steps << :around_before3
773
+ interactor.call
774
+ context.steps << :around_after3
775
+ end
776
+
777
+ before do
778
+ context.fail!
779
+ context.steps << :before3
780
+ end
781
+
782
+ after do
783
+ context.steps << :after3
784
+ end
785
+
786
+ def call
787
+ context.steps << :call3
788
+ end
789
+
790
+ def rollback
791
+ context.steps << :rollback3
792
+ end
793
+ end
794
+ }
795
+
796
+ it "rolls back successfully called interactors" do
797
+ expect {
798
+ organizer.call(context)
799
+ }.to change {
800
+ context.steps
801
+ }.from([]).to([
802
+ :around_before, :before,
803
+ :around_before2, :before2,
804
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
805
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
806
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
807
+ :after2, :around_after2,
808
+ :around_before3,
809
+ :rollback2c,
810
+ :rollback2b,
811
+ :rollback2a
812
+ ])
813
+ end
814
+ end
815
+
816
+ context "when a nested before hook errors" do
817
+ let(:interactor3) {
818
+ build_interactor do
819
+ around do |interactor|
820
+ context.steps << :around_before3
821
+ interactor.call
822
+ context.steps << :around_after3
823
+ end
824
+
825
+ before do
826
+ raise "foo"
827
+ context.steps << :before3
828
+ end
829
+
830
+ after do
831
+ context.steps << :after3
832
+ end
833
+
834
+ def call
835
+ context.steps << :call3
836
+ end
837
+
838
+ def rollback
839
+ context.steps << :rollback3
840
+ end
841
+ end
842
+ }
843
+
844
+ it "rolls back successfully called interactors" do
845
+ expect {
846
+ organizer.call(context) rescue nil
847
+ }.to change {
848
+ context.steps
849
+ }.from([]).to([
850
+ :around_before, :before,
851
+ :around_before2, :before2,
852
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
853
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
854
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
855
+ :after2, :around_after2,
856
+ :around_before3,
857
+ :rollback2c,
858
+ :rollback2b,
859
+ :rollback2a
860
+ ])
861
+ end
862
+
863
+ it "raises the error" do
864
+ expect {
865
+ organizer.call(context)
866
+ }.to raise_error("foo")
867
+ end
868
+ end
869
+
870
+ context "when a nested call fails" do
871
+ let(:interactor3) {
872
+ build_interactor do
873
+ around do |interactor|
874
+ context.steps << :around_before3
875
+ interactor.call
876
+ context.steps << :around_after3
877
+ end
878
+
879
+ before do
880
+ context.steps << :before3
881
+ end
882
+
883
+ after do
884
+ context.steps << :after3
885
+ end
886
+
887
+ def call
888
+ context.fail!
889
+ context.steps << :call3
890
+ end
891
+
892
+ def rollback
893
+ context.steps << :rollback3
894
+ end
895
+ end
896
+ }
897
+
898
+ it "rolls back successfully called interactors" do
899
+ expect {
900
+ organizer.call(context)
901
+ }.to change {
902
+ context.steps
903
+ }.from([]).to([
904
+ :around_before, :before,
905
+ :around_before2, :before2,
906
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
907
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
908
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
909
+ :after2, :around_after2,
910
+ :around_before3, :before3,
911
+ :rollback2c,
912
+ :rollback2b,
913
+ :rollback2a
914
+ ])
915
+ end
916
+ end
917
+
918
+ context "when a nested call errors" do
919
+ let(:interactor3) {
920
+ build_interactor do
921
+ around do |interactor|
922
+ context.steps << :around_before3
923
+ interactor.call
924
+ context.steps << :around_after3
925
+ end
926
+
927
+ before do
928
+ context.steps << :before3
929
+ end
930
+
931
+ after do
932
+ context.steps << :after3
933
+ end
934
+
935
+ def call
936
+ raise "foo"
937
+ context.steps << :call3
938
+ end
939
+
940
+ def rollback
941
+ context.steps << :rollback3
942
+ end
943
+ end
944
+ }
945
+
946
+ it "rolls back successfully called interactors" do
947
+ expect {
948
+ organizer.call(context) rescue nil
949
+ }.to change {
950
+ context.steps
951
+ }.from([]).to([
952
+ :around_before, :before,
953
+ :around_before2, :before2,
954
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
955
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
956
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
957
+ :after2, :around_after2,
958
+ :around_before3, :before3,
959
+ :rollback2c,
960
+ :rollback2b,
961
+ :rollback2a
962
+ ])
963
+ end
964
+
965
+ it "raises the error" do
966
+ expect {
967
+ organizer.call(context)
968
+ }.to raise_error("foo")
969
+ end
970
+ end
971
+
972
+ context "when a nested after hook fails" do
973
+ let(:interactor3) {
974
+ build_interactor do
975
+ around do |interactor|
976
+ context.steps << :around_before3
977
+ interactor.call
978
+ context.steps << :around_after3
979
+ end
980
+
981
+ before do
982
+ context.steps << :before3
983
+ end
984
+
985
+ after do
986
+ context.fail!
987
+ context.steps << :after3
988
+ end
989
+
990
+ def call
991
+ context.steps << :call3
992
+ end
993
+
994
+ def rollback
995
+ context.steps << :rollback3
996
+ end
997
+ end
998
+ }
999
+
1000
+ it "rolls back successfully called interactors and the failed interactor" do
1001
+ expect {
1002
+ organizer.call(context)
1003
+ }.to change {
1004
+ context.steps
1005
+ }.from([]).to([
1006
+ :around_before, :before,
1007
+ :around_before2, :before2,
1008
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1009
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1010
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1011
+ :after2, :around_after2,
1012
+ :around_before3, :before3, :call3,
1013
+ :rollback3,
1014
+ :rollback2c,
1015
+ :rollback2b,
1016
+ :rollback2a
1017
+ ])
1018
+ end
1019
+ end
1020
+
1021
+ context "when a nested after hook errors" do
1022
+ let(:interactor3) {
1023
+ build_interactor do
1024
+ around do |interactor|
1025
+ context.steps << :around_before3
1026
+ interactor.call
1027
+ context.steps << :around_after3
1028
+ end
1029
+
1030
+ before do
1031
+ context.steps << :before3
1032
+ end
1033
+
1034
+ after do
1035
+ raise "foo"
1036
+ context.steps << :after3
1037
+ end
1038
+
1039
+ def call
1040
+ context.steps << :call3
1041
+ end
1042
+
1043
+ def rollback
1044
+ context.steps << :rollback3
1045
+ end
1046
+ end
1047
+ }
1048
+
1049
+ it "rolls back successfully called interactors and the failed interactor" do
1050
+ expect {
1051
+ organizer.call(context) rescue nil
1052
+ }.to change {
1053
+ context.steps
1054
+ }.from([]).to([
1055
+ :around_before, :before,
1056
+ :around_before2, :before2,
1057
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1058
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1059
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1060
+ :after2, :around_after2,
1061
+ :around_before3, :before3, :call3,
1062
+ :rollback3,
1063
+ :rollback2c,
1064
+ :rollback2b,
1065
+ :rollback2a
1066
+ ])
1067
+ end
1068
+
1069
+ it "raises the error" do
1070
+ expect {
1071
+ organizer.call(context)
1072
+ }.to raise_error("foo")
1073
+ end
1074
+ end
1075
+
1076
+ context "when a nested around hook fails late" do
1077
+ let(:interactor3) {
1078
+ build_interactor do
1079
+ around do |interactor|
1080
+ context.steps << :around_before3
1081
+ interactor.call
1082
+ context.fail!
1083
+ context.steps << :around_after3
1084
+ end
1085
+
1086
+ before do
1087
+ context.steps << :before3
1088
+ end
1089
+
1090
+ after do
1091
+ context.steps << :after3
1092
+ end
1093
+
1094
+ def call
1095
+ context.steps << :call3
1096
+ end
1097
+
1098
+ def rollback
1099
+ context.steps << :rollback3
1100
+ end
1101
+ end
1102
+ }
1103
+
1104
+ it "rolls back successfully called interactors and the failed interactor" do
1105
+ expect {
1106
+ organizer.call(context)
1107
+ }.to change {
1108
+ context.steps
1109
+ }.from([]).to([
1110
+ :around_before, :before,
1111
+ :around_before2, :before2,
1112
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1113
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1114
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1115
+ :after2, :around_after2,
1116
+ :around_before3, :before3, :call3, :after3,
1117
+ :rollback3,
1118
+ :rollback2c,
1119
+ :rollback2b,
1120
+ :rollback2a
1121
+ ])
1122
+ end
1123
+ end
1124
+
1125
+ context "when a nested around hook errors late" do
1126
+ let(:interactor3) {
1127
+ build_interactor do
1128
+ around do |interactor|
1129
+ context.steps << :around_before3
1130
+ interactor.call
1131
+ raise "foo"
1132
+ context.steps << :around_after3
1133
+ end
1134
+
1135
+ before do
1136
+ context.steps << :before3
1137
+ end
1138
+
1139
+ after do
1140
+ context.steps << :after3
1141
+ end
1142
+
1143
+ def call
1144
+ context.steps << :call3
1145
+ end
1146
+
1147
+ def rollback
1148
+ context.steps << :rollback3
1149
+ end
1150
+ end
1151
+ }
1152
+
1153
+ it "rolls back successfully called interactors and the failed interactor" do
1154
+ expect {
1155
+ organizer.call(context) rescue nil
1156
+ }.to change {
1157
+ context.steps
1158
+ }.from([]).to([
1159
+ :around_before, :before,
1160
+ :around_before2, :before2,
1161
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1162
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1163
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1164
+ :after2, :around_after2,
1165
+ :around_before3, :before3, :call3, :after3,
1166
+ :rollback3,
1167
+ :rollback2c,
1168
+ :rollback2b,
1169
+ :rollback2a
1170
+ ])
1171
+ end
1172
+
1173
+ it "raises the error" do
1174
+ expect {
1175
+ organizer.call(context)
1176
+ }.to raise_error("foo")
1177
+ end
1178
+ end
1179
+
1180
+ context "when a deeply nested around hook fails early" do
1181
+ let(:interactor4b) {
1182
+ build_interactor do
1183
+ around do |interactor|
1184
+ context.fail!
1185
+ context.steps << :around_before4b
1186
+ interactor.call
1187
+ context.steps << :around_after4b
1188
+ end
1189
+
1190
+ before do
1191
+ context.steps << :before4b
1192
+ end
1193
+
1194
+ after do
1195
+ context.steps << :after4b
1196
+ end
1197
+
1198
+ def call
1199
+ context.steps << :call4b
1200
+ end
1201
+
1202
+ def rollback
1203
+ context.steps << :rollback4b
1204
+ end
1205
+ end
1206
+ }
1207
+
1208
+ it "rolls back successfully called interactors" do
1209
+ expect {
1210
+ organizer.call(context)
1211
+ }.to change {
1212
+ context.steps
1213
+ }.from([]).to([
1214
+ :around_before, :before,
1215
+ :around_before2, :before2,
1216
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1217
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1218
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1219
+ :after2, :around_after2,
1220
+ :around_before3, :before3, :call3, :after3, :around_after3,
1221
+ :around_before4, :before4,
1222
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1223
+ :rollback4a,
1224
+ :rollback3,
1225
+ :rollback2c,
1226
+ :rollback2b,
1227
+ :rollback2a
1228
+ ])
1229
+ end
1230
+ end
1231
+
1232
+ context "when a deeply nested around hook errors early" do
1233
+ let(:interactor4b) {
1234
+ build_interactor do
1235
+ around do |interactor|
1236
+ raise "foo"
1237
+ context.steps << :around_before4b
1238
+ interactor.call
1239
+ context.steps << :around_after4b
1240
+ end
1241
+
1242
+ before do
1243
+ context.steps << :before4b
1244
+ end
1245
+
1246
+ after do
1247
+ context.steps << :after4b
1248
+ end
1249
+
1250
+ def call
1251
+ context.steps << :call4b
1252
+ end
1253
+
1254
+ def rollback
1255
+ context.steps << :rollback4b
1256
+ end
1257
+ end
1258
+ }
1259
+
1260
+ it "rolls back successfully called interactors" do
1261
+ expect {
1262
+ organizer.call(context) rescue nil
1263
+ }.to change {
1264
+ context.steps
1265
+ }.from([]).to([
1266
+ :around_before, :before,
1267
+ :around_before2, :before2,
1268
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1269
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1270
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1271
+ :after2, :around_after2,
1272
+ :around_before3, :before3, :call3, :after3, :around_after3,
1273
+ :around_before4, :before4,
1274
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1275
+ :rollback4a,
1276
+ :rollback3,
1277
+ :rollback2c,
1278
+ :rollback2b,
1279
+ :rollback2a
1280
+ ])
1281
+ end
1282
+
1283
+ it "raises the error" do
1284
+ expect {
1285
+ organizer.call(context)
1286
+ }.to raise_error("foo")
1287
+ end
1288
+ end
1289
+
1290
+ context "when a deeply nested before hook fails" do
1291
+ let(:interactor4b) {
1292
+ build_interactor do
1293
+ around do |interactor|
1294
+ context.steps << :around_before4b
1295
+ interactor.call
1296
+ context.steps << :around_after4b
1297
+ end
1298
+
1299
+ before do
1300
+ context.fail!
1301
+ context.steps << :before4b
1302
+ end
1303
+
1304
+ after do
1305
+ context.steps << :after4b
1306
+ end
1307
+
1308
+ def call
1309
+ context.steps << :call4b
1310
+ end
1311
+
1312
+ def rollback
1313
+ context.steps << :rollback4b
1314
+ end
1315
+ end
1316
+ }
1317
+
1318
+ it "rolls back successfully called interactors" do
1319
+ expect {
1320
+ organizer.call(context)
1321
+ }.to change {
1322
+ context.steps
1323
+ }.from([]).to([
1324
+ :around_before, :before,
1325
+ :around_before2, :before2,
1326
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1327
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1328
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1329
+ :after2, :around_after2,
1330
+ :around_before3, :before3, :call3, :after3, :around_after3,
1331
+ :around_before4, :before4,
1332
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1333
+ :around_before4b,
1334
+ :rollback4a,
1335
+ :rollback3,
1336
+ :rollback2c,
1337
+ :rollback2b,
1338
+ :rollback2a
1339
+ ])
1340
+ end
1341
+ end
1342
+
1343
+ context "when a deeply nested before hook errors" do
1344
+ let(:interactor4b) {
1345
+ build_interactor do
1346
+ around do |interactor|
1347
+ context.steps << :around_before4b
1348
+ interactor.call
1349
+ context.steps << :around_after4b
1350
+ end
1351
+
1352
+ before do
1353
+ raise "foo"
1354
+ context.steps << :before4b
1355
+ end
1356
+
1357
+ after do
1358
+ context.steps << :after4b
1359
+ end
1360
+
1361
+ def call
1362
+ context.steps << :call4b
1363
+ end
1364
+
1365
+ def rollback
1366
+ context.steps << :rollback4b
1367
+ end
1368
+ end
1369
+ }
1370
+
1371
+ it "rolls back successfully called interactors" do
1372
+ expect {
1373
+ organizer.call(context) rescue nil
1374
+ }.to change {
1375
+ context.steps
1376
+ }.from([]).to([
1377
+ :around_before, :before,
1378
+ :around_before2, :before2,
1379
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1380
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1381
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1382
+ :after2, :around_after2,
1383
+ :around_before3, :before3, :call3, :after3, :around_after3,
1384
+ :around_before4, :before4,
1385
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1386
+ :around_before4b,
1387
+ :rollback4a,
1388
+ :rollback3,
1389
+ :rollback2c,
1390
+ :rollback2b,
1391
+ :rollback2a
1392
+ ])
1393
+ end
1394
+
1395
+ it "raises the error" do
1396
+ expect {
1397
+ organizer.call(context)
1398
+ }.to raise_error("foo")
1399
+ end
1400
+ end
1401
+
1402
+ context "when a deeply nested call fails" do
1403
+ let(:interactor4b) {
1404
+ build_interactor do
1405
+ around do |interactor|
1406
+ context.steps << :around_before4b
1407
+ interactor.call
1408
+ context.steps << :around_after4b
1409
+ end
1410
+
1411
+ before do
1412
+ context.steps << :before4b
1413
+ end
1414
+
1415
+ after do
1416
+ context.steps << :after4b
1417
+ end
1418
+
1419
+ def call
1420
+ context.fail!
1421
+ context.steps << :call4b
1422
+ end
1423
+
1424
+ def rollback
1425
+ context.steps << :rollback4b
1426
+ end
1427
+ end
1428
+ }
1429
+
1430
+ it "rolls back successfully called interactors" do
1431
+ expect {
1432
+ organizer.call(context)
1433
+ }.to change {
1434
+ context.steps
1435
+ }.from([]).to([
1436
+ :around_before, :before,
1437
+ :around_before2, :before2,
1438
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1439
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1440
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1441
+ :after2, :around_after2,
1442
+ :around_before3, :before3, :call3, :after3, :around_after3,
1443
+ :around_before4, :before4,
1444
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1445
+ :around_before4b, :before4b,
1446
+ :rollback4a,
1447
+ :rollback3,
1448
+ :rollback2c,
1449
+ :rollback2b,
1450
+ :rollback2a
1451
+ ])
1452
+ end
1453
+ end
1454
+
1455
+ context "when a deeply nested call errors" do
1456
+ let(:interactor4b) {
1457
+ build_interactor do
1458
+ around do |interactor|
1459
+ context.steps << :around_before4b
1460
+ interactor.call
1461
+ context.steps << :around_after4b
1462
+ end
1463
+
1464
+ before do
1465
+ context.steps << :before4b
1466
+ end
1467
+
1468
+ after do
1469
+ context.steps << :after4b
1470
+ end
1471
+
1472
+ def call
1473
+ raise "foo"
1474
+ context.steps << :call4b
1475
+ end
1476
+
1477
+ def rollback
1478
+ context.steps << :rollback4b
1479
+ end
1480
+ end
1481
+ }
1482
+
1483
+ it "rolls back successfully called interactors" do
1484
+ expect {
1485
+ organizer.call(context) rescue nil
1486
+ }.to change {
1487
+ context.steps
1488
+ }.from([]).to([
1489
+ :around_before, :before,
1490
+ :around_before2, :before2,
1491
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1492
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1493
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1494
+ :after2, :around_after2,
1495
+ :around_before3, :before3, :call3, :after3, :around_after3,
1496
+ :around_before4, :before4,
1497
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1498
+ :around_before4b, :before4b,
1499
+ :rollback4a,
1500
+ :rollback3,
1501
+ :rollback2c,
1502
+ :rollback2b,
1503
+ :rollback2a
1504
+ ])
1505
+ end
1506
+
1507
+ it "raises the error" do
1508
+ expect {
1509
+ organizer.call(context)
1510
+ }.to raise_error("foo")
1511
+ end
1512
+ end
1513
+
1514
+ context "when a deeply nested after hook fails" do
1515
+ let(:interactor4b) {
1516
+ build_interactor do
1517
+ around do |interactor|
1518
+ context.steps << :around_before4b
1519
+ interactor.call
1520
+ context.steps << :around_after4b
1521
+ end
1522
+
1523
+ before do
1524
+ context.steps << :before4b
1525
+ end
1526
+
1527
+ after do
1528
+ context.fail!
1529
+ context.steps << :after4b
1530
+ end
1531
+
1532
+ def call
1533
+ context.steps << :call4b
1534
+ end
1535
+
1536
+ def rollback
1537
+ context.steps << :rollback4b
1538
+ end
1539
+ end
1540
+ }
1541
+
1542
+ it "rolls back successfully called interactors and the failed interactor" do
1543
+ expect {
1544
+ organizer.call(context)
1545
+ }.to change {
1546
+ context.steps
1547
+ }.from([]).to([
1548
+ :around_before, :before,
1549
+ :around_before2, :before2,
1550
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1551
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1552
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1553
+ :after2, :around_after2,
1554
+ :around_before3, :before3, :call3, :after3, :around_after3,
1555
+ :around_before4, :before4,
1556
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1557
+ :around_before4b, :before4b, :call4b,
1558
+ :rollback4b,
1559
+ :rollback4a,
1560
+ :rollback3,
1561
+ :rollback2c,
1562
+ :rollback2b,
1563
+ :rollback2a
1564
+ ])
1565
+ end
1566
+ end
1567
+
1568
+ context "when a deeply nested after hook errors" do
1569
+ let(:interactor4b) {
1570
+ build_interactor do
1571
+ around do |interactor|
1572
+ context.steps << :around_before4b
1573
+ interactor.call
1574
+ context.steps << :around_after4b
1575
+ end
1576
+
1577
+ before do
1578
+ context.steps << :before4b
1579
+ end
1580
+
1581
+ after do
1582
+ raise "foo"
1583
+ context.steps << :after4b
1584
+ end
1585
+
1586
+ def call
1587
+ context.steps << :call4b
1588
+ end
1589
+
1590
+ def rollback
1591
+ context.steps << :rollback4b
1592
+ end
1593
+ end
1594
+ }
1595
+
1596
+ it "rolls back successfully called interactors and the failed interactor" do
1597
+ expect {
1598
+ organizer.call(context) rescue nil
1599
+ }.to change {
1600
+ context.steps
1601
+ }.from([]).to([
1602
+ :around_before, :before,
1603
+ :around_before2, :before2,
1604
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1605
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1606
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1607
+ :after2, :around_after2,
1608
+ :around_before3, :before3, :call3, :after3, :around_after3,
1609
+ :around_before4, :before4,
1610
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1611
+ :around_before4b, :before4b, :call4b,
1612
+ :rollback4b,
1613
+ :rollback4a,
1614
+ :rollback3,
1615
+ :rollback2c,
1616
+ :rollback2b,
1617
+ :rollback2a
1618
+ ])
1619
+ end
1620
+
1621
+ it "raises the error" do
1622
+ expect {
1623
+ organizer.call(context)
1624
+ }.to raise_error("foo")
1625
+ end
1626
+ end
1627
+
1628
+ context "when a deeply nested around hook fails late" do
1629
+ let(:interactor4b) {
1630
+ build_interactor do
1631
+ around do |interactor|
1632
+ context.steps << :around_before4b
1633
+ interactor.call
1634
+ context.fail!
1635
+ context.steps << :around_after4b
1636
+ end
1637
+
1638
+ before do
1639
+ context.steps << :before4b
1640
+ end
1641
+
1642
+ after do
1643
+ context.steps << :after4b
1644
+ end
1645
+
1646
+ def call
1647
+ context.steps << :call4b
1648
+ end
1649
+
1650
+ def rollback
1651
+ context.steps << :rollback4b
1652
+ end
1653
+ end
1654
+ }
1655
+
1656
+ it "rolls back successfully called interactors and the failed interactor" do
1657
+ expect {
1658
+ organizer.call(context)
1659
+ }.to change {
1660
+ context.steps
1661
+ }.from([]).to([
1662
+ :around_before, :before,
1663
+ :around_before2, :before2,
1664
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1665
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1666
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1667
+ :after2, :around_after2,
1668
+ :around_before3, :before3, :call3, :after3, :around_after3,
1669
+ :around_before4, :before4,
1670
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1671
+ :around_before4b, :before4b, :call4b, :after4b,
1672
+ :rollback4b,
1673
+ :rollback4a,
1674
+ :rollback3,
1675
+ :rollback2c,
1676
+ :rollback2b,
1677
+ :rollback2a
1678
+ ])
1679
+ end
1680
+ end
1681
+
1682
+ context "when a deeply nested around hook errors late" do
1683
+ let(:interactor4b) {
1684
+ build_interactor do
1685
+ around do |interactor|
1686
+ context.steps << :around_before4b
1687
+ interactor.call
1688
+ raise "foo"
1689
+ context.steps << :around_after4b
1690
+ end
1691
+
1692
+ before do
1693
+ context.steps << :before4b
1694
+ end
1695
+
1696
+ after do
1697
+ context.steps << :after4b
1698
+ end
1699
+
1700
+ def call
1701
+ context.steps << :call4b
1702
+ end
1703
+
1704
+ def rollback
1705
+ context.steps << :rollback4b
1706
+ end
1707
+ end
1708
+ }
1709
+
1710
+ it "rolls back successfully called interactors and the failed interactor" do
1711
+ expect {
1712
+ organizer.call(context) rescue nil
1713
+ }.to change {
1714
+ context.steps
1715
+ }.from([]).to([
1716
+ :around_before, :before,
1717
+ :around_before2, :before2,
1718
+ :around_before2a, :before2a, :call2a, :after2a, :around_after2a,
1719
+ :around_before2b, :before2b, :call2b, :after2b, :around_after2b,
1720
+ :around_before2c, :before2c, :call2c, :after2c, :around_after2c,
1721
+ :after2, :around_after2,
1722
+ :around_before3, :before3, :call3, :after3, :around_after3,
1723
+ :around_before4, :before4,
1724
+ :around_before4a, :before4a, :call4a, :after4a, :around_after4a,
1725
+ :around_before4b, :before4b, :call4b, :after4b,
1726
+ :rollback4b,
1727
+ :rollback4a,
1728
+ :rollback3,
1729
+ :rollback2c,
1730
+ :rollback2b,
1731
+ :rollback2a
1732
+ ])
1733
+ end
1734
+
1735
+ it "raises the error" do
1736
+ expect {
1737
+ organizer.call(context)
1738
+ }.to raise_error("foo")
1739
+ end
1740
+ end
1741
+ end