functional_interactor 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
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