activeinteractor 1.0.0.beta.3 → 1.0.0.beta.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +26 -1
- data/README.md +28 -4
- data/lib/active_interactor/interactor.rb +25 -7
- data/lib/active_interactor/interactor/perform_options.rb +5 -21
- data/lib/active_interactor/interactor/worker.rb +33 -42
- data/lib/active_interactor/organizer.rb +58 -28
- data/lib/active_interactor/organizer/interactor_interface.rb +66 -0
- data/lib/active_interactor/organizer/interactor_interface_collection.rb +58 -0
- data/lib/active_interactor/version.rb +1 -1
- data/spec/active_interactor/interactor/perform_options_spec.rb +25 -0
- data/spec/active_interactor/interactor/worker_spec.rb +81 -82
- data/spec/active_interactor/organizer/interactor_interface_collection_spec.rb +76 -0
- data/spec/active_interactor/organizer/interactor_interface_spec.rb +162 -0
- data/spec/active_interactor/organizer_spec.rb +36 -32
- data/spec/integration/basic_integration_spec.rb +311 -12
- data/spec/support/shared_examples/a_class_with_interactor_methods_example.rb +4 -4
- metadata +22 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b887e29c2334d776e28d0df4e79ba53b42123d47e4e6f4da6c94a2fa5b38ea78
|
4
|
+
data.tar.gz: e6ca29f29e435b5b73e405c41eccfa6dea8837a7316c3d3143abd97cda241347
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8f766aa0e2c50d7cec5c74def38f7e2ea9d3918354f511d2ec127cf4054c9484638f1cd6f984686e1b12ca09116f53708fd4e5f714620178c4dd73ab745d6ee3
|
7
|
+
data.tar.gz: 2ece11503295a16bfba3860cb8d4ad3653eca4a1399c5b8928b2780884ca81b48b3a6128c9fce11b464cd0bf2928d4f22924a7d2d6a4c4a00e71d9c7603375a2
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,28 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [v1.0.0-beta.4] - 2020-01-14
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- [#114] `ActiveInteractor::Organizer::InteractorInterface`
|
15
|
+
- [#114] `ActiveInteractor::Organizer::InteractorInterfaceCollection`
|
16
|
+
- [#115] `ActiveInteractor::Interactor#options`
|
17
|
+
- [#115] `ActiveInteractor::Interactor#with_options`
|
18
|
+
- [#115] `ActiveInteractor::Interactor::PerformOptions#skip_each_perform_callbacks`
|
19
|
+
|
20
|
+
### Changed
|
21
|
+
|
22
|
+
- [#115] `ActiveInteractor::Interactor::Worker#execute_perform` and `#execute_perform!` no longer accept arguments,
|
23
|
+
use `ActiveInteractor::Interactor#with_options` instead.
|
24
|
+
- [#115] `ActiveInteractor::Organizer` can now skip `each_perform` callbacks with
|
25
|
+
the option `skip_each_perform_callbacks`
|
26
|
+
|
27
|
+
### Removed
|
28
|
+
|
29
|
+
- [#115] `ActiveInteractor::Interactor#execute_rollback`
|
30
|
+
- [#115] `ActiveInteractor::Interactor::Worker#run_callbacks`
|
31
|
+
|
10
32
|
## [v1.0.0-beta.3] - 2020-01-12
|
11
33
|
|
12
34
|
### Added
|
@@ -147,7 +169,8 @@ and this project adheres to [Semantic Versioning].
|
|
147
169
|
|
148
170
|
<!-- versions -->
|
149
171
|
|
150
|
-
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0-beta.
|
172
|
+
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0-beta.4...HEAD
|
173
|
+
[v1.0.0-beta.4]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0-beta.3...v1.0.0-beta.4
|
151
174
|
[v1.0.0-beta.3]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0-beta.2...v1.0.0-beta.3
|
152
175
|
[v1.0.0-beta.2]: https://github.com/aaronmallen/activeinteractor/compare/v1.0.0-beta.1...v1.0.0-beta.2
|
153
176
|
[v1.0.0-beta.1]: https://github.com/aaronmallen/activeinteractor/compare/v0.1.7...v1.0.0-beta.1
|
@@ -181,3 +204,5 @@ and this project adheres to [Semantic Versioning].
|
|
181
204
|
[#105]: https://github.com/aaronmallen/activeinteractor/pull/105
|
182
205
|
[#109]: https://github.com/aaronmallen/activeinteractor/pull/109
|
183
206
|
[#110]: https://github.com/aaronmallen/activeinteractor/pull/110
|
207
|
+
[#114]:https://github.com/aaronmallen/activeinteractor/pull/114
|
208
|
+
[#115]: https://github.com/aaronmallen/activeinteractor/pull/115
|
data/README.md
CHANGED
@@ -11,6 +11,9 @@
|
|
11
11
|
|
12
12
|
Ruby interactors with [ActiveModel::Validations] based on the [interactor][collective_idea_interactors] gem.
|
13
13
|
|
14
|
+
**ActiveInteractor v1.0.0 is currently in beta. For documentation on the current stable version please
|
15
|
+
see [v0.1.7](https://github.com/aaronmallen/activeinteractor/tree/0-1-stable)**
|
16
|
+
|
14
17
|
<!-- TOC -->
|
15
18
|
|
16
19
|
* [Getting Started](#getting-started)
|
@@ -26,7 +29,8 @@ Ruby interactors with [ActiveModel::Validations] based on the [interactor][colle
|
|
26
29
|
* [Kinds of Interactors](#kinds-of-interactors)
|
27
30
|
* [Interactors](#interactors)
|
28
31
|
* [Organizers](#organizers)
|
29
|
-
|
32
|
+
* [Organizing Interactors Conditionally](#organizing-interactors-conditionally)
|
33
|
+
* [Running Interactors In Parallel](#running-interactors-in-parallel)
|
30
34
|
* [Rollback](#rollback)
|
31
35
|
* [Callbacks](#callbacks)
|
32
36
|
* [Validation Callbacks](#validation-callbacks)
|
@@ -46,7 +50,7 @@ Ruby interactors with [ActiveModel::Validations] based on the [interactor][colle
|
|
46
50
|
Add this line to your application's Gemfile:
|
47
51
|
|
48
52
|
```ruby
|
49
|
-
gem 'activeinteractor'
|
53
|
+
gem 'activeinteractor', '~> 1.0.0.beta.3'
|
50
54
|
```
|
51
55
|
|
52
56
|
And then execute:
|
@@ -58,7 +62,7 @@ bundle
|
|
58
62
|
Or install it yourself as:
|
59
63
|
|
60
64
|
```bash
|
61
|
-
gem install activeinteractor
|
65
|
+
gem install activeinteractor --pre
|
62
66
|
```
|
63
67
|
|
64
68
|
## What is an Interactor
|
@@ -422,7 +426,27 @@ end
|
|
422
426
|
The organizer passes its context to the interactors that it organizes, one at a time and in order. Each interactor may
|
423
427
|
change that context before it's passed along to the next interactor.
|
424
428
|
|
425
|
-
|
429
|
+
###### Organizing Interactors Conditionally
|
430
|
+
|
431
|
+
We can also add conditional statements to our organizer by passing a block to the `#organize` method:
|
432
|
+
|
433
|
+
```ruby
|
434
|
+
class PlaceOrder < ActiveInteractor::Organizer
|
435
|
+
organize do
|
436
|
+
add :create_order, if :user_registered?
|
437
|
+
add :charge_card, if: -> { context.order_number }
|
438
|
+
add :send_thank_you, if: -> { context.order_number }
|
439
|
+
end
|
440
|
+
|
441
|
+
private
|
442
|
+
|
443
|
+
def user_registered?
|
444
|
+
context.user&.registered?
|
445
|
+
end
|
446
|
+
end
|
447
|
+
```
|
448
|
+
|
449
|
+
###### Running Interactors In Parallel
|
426
450
|
|
427
451
|
Organizers can be told to run their interactors in parallel with the `#perform_in_parallel` class method. This
|
428
452
|
will run each interactor in parallel with one and other only passing the original context to each organizer.
|
@@ -11,7 +11,7 @@ module ActiveInteractor
|
|
11
11
|
extend ClassMethods
|
12
12
|
include Callbacks
|
13
13
|
include Context
|
14
|
-
delegate :execute_perform, :execute_perform!,
|
14
|
+
delegate :execute_perform, :execute_perform!, to: :worker
|
15
15
|
end
|
16
16
|
end
|
17
17
|
|
@@ -23,10 +23,11 @@ module ActiveInteractor
|
|
23
23
|
# MyInteractor.perform(name: 'Aaron')
|
24
24
|
# #=> <#MyInteractor::Context name='Aaron'>
|
25
25
|
# @param context [Hash|Context::Base] attributes to assign to the interactor context
|
26
|
-
# @param options [
|
26
|
+
# @param options [Hash] execution options for the interactor perform step
|
27
|
+
# see {PerformOptions}
|
27
28
|
# @return [Context::Base] an instance of context.
|
28
|
-
def perform(context = {}, options =
|
29
|
-
new(context).
|
29
|
+
def perform(context = {}, options = {})
|
30
|
+
new(context).with_options(options).execute_perform
|
30
31
|
end
|
31
32
|
|
32
33
|
# Run an interactor context. The {.perform!} method behaves identically to
|
@@ -37,14 +38,22 @@ module ActiveInteractor
|
|
37
38
|
# MyInteractor.perform!(name: 'Aaron')
|
38
39
|
# #=> <#MyInteractor::Context name='Aaron'>
|
39
40
|
# @param context [Hash|Context::Base] attributes to assign to the interactor context
|
40
|
-
# @param options [
|
41
|
+
# @param options [Hash] execution options for the interactor perform step
|
42
|
+
# see {PerformOptions}
|
41
43
|
# @raise [Error::ContextFailure] if the context fails.
|
42
44
|
# @return [Context::Base] an instance of context.
|
43
|
-
def perform!(context = {}, options =
|
44
|
-
new(context).
|
45
|
+
def perform!(context = {}, options = {})
|
46
|
+
new(context).with_options(options).execute_perform!
|
45
47
|
end
|
46
48
|
end
|
47
49
|
|
50
|
+
# Options for invokation of {#perform}
|
51
|
+
# @since 1.0.0
|
52
|
+
# @return [PerformOptions] the options
|
53
|
+
def options
|
54
|
+
@options ||= PerformOptions.new
|
55
|
+
end
|
56
|
+
|
48
57
|
# Invoke an Interactor instance without any hooks, tracking, or rollback
|
49
58
|
# @abstract It is expected that the {#perform} method is overwritten
|
50
59
|
# for each interactor class.
|
@@ -55,6 +64,15 @@ module ActiveInteractor
|
|
55
64
|
# failure is expected to overwrite the {#rollback} method.
|
56
65
|
def rollback; end
|
57
66
|
|
67
|
+
# Set options for invokation of {#perform}
|
68
|
+
# @since 1.0.0
|
69
|
+
# @param options [PerformOptions|Hash] the perform options
|
70
|
+
# @return [Base] the instance of {Base}
|
71
|
+
def with_options(options)
|
72
|
+
@options = options.is_a?(PerformOptions) ? options : PerformOptions.new(options)
|
73
|
+
self
|
74
|
+
end
|
75
|
+
|
58
76
|
private
|
59
77
|
|
60
78
|
def worker
|
@@ -5,6 +5,8 @@ module ActiveInteractor
|
|
5
5
|
# Options object for interactor perform
|
6
6
|
# @author Aaron Allen <hello@aaronmallen.me>
|
7
7
|
# @since 1.0.0
|
8
|
+
# @!attribute [rw] skip_each_perform_callbacks
|
9
|
+
# @return [Boolean] whether or not to skip :each_perform callbacks for an {Organizer}
|
8
10
|
# @!attribute [rw] skip_perform_callbacks
|
9
11
|
# @return [Boolean] whether or not to skip :perform callbacks
|
10
12
|
# @!attribute [rw] skip_rollback
|
@@ -19,27 +21,9 @@ module ActiveInteractor
|
|
19
21
|
# @!attribute [rw] validate_on_called
|
20
22
|
# @return [Boolean] whether or not to run validation on :called
|
21
23
|
class PerformOptions
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
skip_perform_callbacks: false,
|
26
|
-
skip_rollback: false,
|
27
|
-
skip_rollback_callbacks: false,
|
28
|
-
validate: true,
|
29
|
-
validate_on_calling: true,
|
30
|
-
validate_on_called: true
|
31
|
-
}.freeze
|
32
|
-
|
33
|
-
attr_accessor :skip_perform_callbacks, :skip_rollback, :skip_rollback_callbacks,
|
34
|
-
:validate, :validate_on_calling, :validate_on_called
|
35
|
-
|
36
|
-
# @param options [Hash] the attributes for the {PerformOptions}
|
37
|
-
# @return [PerformOptions] a new instance of {PerformOptions}
|
38
|
-
def initialize(options = {})
|
39
|
-
DEFAULTS.dup.merge(options).each do |key, value|
|
40
|
-
instance_variable_set("@#{key}", value)
|
41
|
-
end
|
42
|
-
end
|
24
|
+
include ActiveInteractor::Configurable
|
25
|
+
defaults skip_each_perform_callbacks: false, skip_perform_callbacks: false, skip_rollback: false,
|
26
|
+
skip_rollback_callbacks: false, validate: true, validate_on_calling: true, validate_on_called: true
|
43
27
|
end
|
44
28
|
end
|
45
29
|
end
|
@@ -8,108 +8,99 @@ module ActiveInteractor
|
|
8
8
|
# @author Aaron Allen <hello@aaronmallen.me>
|
9
9
|
# @since 0.0.2
|
10
10
|
class Worker
|
11
|
-
delegate :run_callbacks, to: :interactor
|
12
|
-
|
13
11
|
# @param interactor [Base] an instance of interactor
|
14
12
|
# @return [Worker] a new instance of {Worker}
|
15
13
|
def initialize(interactor)
|
16
|
-
|
14
|
+
options = interactor.options.dup
|
15
|
+
@interactor = interactor.dup.with_options(options)
|
17
16
|
end
|
18
17
|
|
19
18
|
# Calls {#execute_perform!} and rescues {Error::ContextFailure}
|
20
|
-
# @param options [PerformOptions|Hash] execution options for the interactor perform step
|
21
19
|
# @return [Context::Base] an instance of {Context::Base}
|
22
|
-
def execute_perform
|
23
|
-
execute_perform!
|
20
|
+
def execute_perform
|
21
|
+
execute_perform!
|
24
22
|
rescue Error::ContextFailure => e
|
25
23
|
ActiveInteractor.logger.error("ActiveInteractor: #{e}")
|
26
24
|
context
|
27
25
|
end
|
28
26
|
|
29
27
|
# Calls {Interactor#perform} with callbacks and context validation
|
30
|
-
# @param options [PerformOptions|Hash] execution options for the interactor perform step
|
31
28
|
# @raise [Error::ContextFailure] if the context fails
|
32
29
|
# @return [Context::Base] an instance of {Context::Base}
|
33
|
-
def execute_perform!
|
34
|
-
|
35
|
-
execute_context!(options)
|
30
|
+
def execute_perform!
|
31
|
+
execute_context!
|
36
32
|
rescue StandardError => e
|
37
|
-
handle_error(e
|
33
|
+
handle_error(e)
|
38
34
|
end
|
39
35
|
|
40
36
|
# Calls {Interactor#rollback} with callbacks
|
41
37
|
# @return [Boolean] `true` if rolled back successfully or `false` if already
|
42
38
|
# rolled back
|
43
|
-
def execute_rollback
|
44
|
-
|
45
|
-
return if options.skip_rollback
|
39
|
+
def execute_rollback
|
40
|
+
return if interactor.options.skip_rollback
|
46
41
|
|
47
|
-
execute_interactor_rollback!
|
42
|
+
execute_interactor_rollback!
|
48
43
|
end
|
49
44
|
|
50
45
|
private
|
51
46
|
|
52
47
|
attr_reader :context, :interactor
|
53
48
|
|
54
|
-
def execute_context!
|
55
|
-
if options.skip_perform_callbacks
|
56
|
-
execute_context_with_validation_check!
|
49
|
+
def execute_context!
|
50
|
+
if interactor.options.skip_perform_callbacks
|
51
|
+
execute_context_with_validation_check!
|
57
52
|
else
|
58
|
-
execute_context_with_callbacks!
|
53
|
+
execute_context_with_callbacks!
|
59
54
|
end
|
60
55
|
end
|
61
56
|
|
62
|
-
def execute_context_with_callbacks!
|
63
|
-
run_callbacks :perform do
|
64
|
-
execute_context_with_validation_check!
|
57
|
+
def execute_context_with_callbacks!
|
58
|
+
interactor.run_callbacks :perform do
|
59
|
+
execute_context_with_validation_check!
|
65
60
|
@context = interactor.finalize_context!
|
66
61
|
end
|
67
62
|
end
|
68
63
|
|
69
|
-
def execute_context_with_validation!
|
70
|
-
validate_on_calling
|
64
|
+
def execute_context_with_validation!
|
65
|
+
validate_on_calling
|
71
66
|
interactor.perform
|
72
|
-
validate_on_called
|
67
|
+
validate_on_called
|
73
68
|
end
|
74
69
|
|
75
|
-
def execute_context_with_validation_check!
|
76
|
-
return interactor.perform unless options.validate
|
70
|
+
def execute_context_with_validation_check!
|
71
|
+
return interactor.perform unless interactor.options.validate
|
77
72
|
|
78
|
-
execute_context_with_validation!
|
73
|
+
execute_context_with_validation!
|
79
74
|
end
|
80
75
|
|
81
|
-
def execute_interactor_rollback!
|
82
|
-
return interactor.context_rollback! if options.skip_rollback_callbacks
|
76
|
+
def execute_interactor_rollback!
|
77
|
+
return interactor.context_rollback! if interactor.options.skip_rollback_callbacks
|
83
78
|
|
84
|
-
run_callbacks :rollback do
|
79
|
+
interactor.run_callbacks :rollback do
|
85
80
|
interactor.context_rollback!
|
86
81
|
end
|
87
82
|
end
|
88
83
|
|
89
|
-
def handle_error(exception
|
84
|
+
def handle_error(exception)
|
90
85
|
@context = interactor.finalize_context!
|
91
|
-
execute_rollback
|
86
|
+
execute_rollback
|
92
87
|
raise exception
|
93
88
|
end
|
94
89
|
|
95
|
-
def parse_options(options)
|
96
|
-
@options = options.is_a?(PerformOptions) ? options : PerformOptions.new(options)
|
97
|
-
end
|
98
|
-
|
99
90
|
def validate_context(validation_context = nil)
|
100
|
-
run_callbacks :validation do
|
91
|
+
interactor.run_callbacks :validation do
|
101
92
|
interactor.context_valid?(validation_context)
|
102
93
|
end
|
103
94
|
end
|
104
95
|
|
105
|
-
def validate_on_calling
|
106
|
-
return unless options.validate_on_calling
|
96
|
+
def validate_on_calling
|
97
|
+
return unless interactor.options.validate_on_calling
|
107
98
|
|
108
99
|
interactor.context_fail! unless validate_context(:calling)
|
109
100
|
end
|
110
101
|
|
111
|
-
def validate_on_called
|
112
|
-
return unless options.validate_on_called
|
102
|
+
def validate_on_called
|
103
|
+
return unless interactor.options.validate_on_called
|
113
104
|
|
114
105
|
interactor.context_fail! unless validate_context(:called)
|
115
106
|
end
|
@@ -1,16 +1,14 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'active_support/core_ext/class/attribute'
|
4
|
-
|
4
|
+
|
5
|
+
require 'active_interactor/organizer/interactor_interface_collection'
|
5
6
|
|
6
7
|
module ActiveInteractor
|
7
8
|
# A base Organizer class. All organizers should inherit from
|
8
9
|
# {Organizer}.
|
9
10
|
# @author Aaron Allen <hello@aaronmallen.me>
|
10
11
|
# @since 0.0.1
|
11
|
-
# @!attribute [r] organized
|
12
|
-
# @!scope class
|
13
|
-
# @return [Array<Base>] the organized interactors
|
14
12
|
# @!attribute [r] parallel
|
15
13
|
# @since 1.0.0
|
16
14
|
# @!scope class
|
@@ -36,7 +34,6 @@ module ActiveInteractor
|
|
36
34
|
# MyOrganizer.perform
|
37
35
|
# #=> <MyOrganizer::Context interactor1=true interactor2=true>
|
38
36
|
class Organizer < Base
|
39
|
-
class_attribute :organized, instance_writer: false, default: []
|
40
37
|
class_attribute :parallel, instance_writer: false, default: false
|
41
38
|
define_callbacks :each_perform
|
42
39
|
|
@@ -83,7 +80,6 @@ module ActiveInteractor
|
|
83
80
|
|
84
81
|
# Define a callback to call around each organized interactor's
|
85
82
|
# {Base.perform} has been invokation
|
86
|
-
#
|
87
83
|
# @example
|
88
84
|
# class MyInteractor1 < ActiveInteractor::Base
|
89
85
|
# before_perform :print_name
|
@@ -129,7 +125,6 @@ module ActiveInteractor
|
|
129
125
|
|
130
126
|
# Define a callback to call before each organized interactor's
|
131
127
|
# {Base.perform} has been invoked
|
132
|
-
#
|
133
128
|
# @example
|
134
129
|
# class MyInteractor1 < ActiveInteractor::Base
|
135
130
|
# before_perform :print_name
|
@@ -172,21 +167,50 @@ module ActiveInteractor
|
|
172
167
|
# Declare Interactors to be invoked as part of the
|
173
168
|
# organizer's invocation. These interactors are invoked in
|
174
169
|
# the order in which they are declared
|
175
|
-
#
|
176
|
-
#
|
177
|
-
#
|
178
|
-
# organize InteractorOne, InteractorTwo
|
170
|
+
# @example Basic interactor organization
|
171
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
172
|
+
# organize :interactor_one, :interactor_two
|
179
173
|
# end
|
180
|
-
#
|
181
|
-
# class
|
182
|
-
# organize
|
174
|
+
# @example Conditional interactor organization with block
|
175
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
176
|
+
# organize do
|
177
|
+
# add :interactor_one
|
178
|
+
# add :interactor_two, if: -> { context.valid? }
|
179
|
+
# end
|
183
180
|
# end
|
181
|
+
# @example Conditional interactor organization with method
|
182
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
183
|
+
# organize do
|
184
|
+
# add :interactor_one
|
185
|
+
# add :interactor_two, unless: :invalid_context?
|
186
|
+
# end
|
187
|
+
#
|
188
|
+
# private
|
184
189
|
#
|
185
|
-
#
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
+
# def invalid_context?
|
191
|
+
# !context.valid?
|
192
|
+
# end
|
193
|
+
# end
|
194
|
+
# @example Interactor organization with perform options
|
195
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
196
|
+
# organize do
|
197
|
+
# add :interactor_one, validate: false
|
198
|
+
# add :interactor_two, skip_perform_callbacks: true
|
199
|
+
# end
|
200
|
+
# end
|
201
|
+
# @param interactors [Array<Base|Symbol|String>] the interactors to call
|
202
|
+
# @yield [.organized] if block given
|
203
|
+
# @return [InteractorInterfaceCollection] an instance of {InteractorInterfaceCollection}
|
204
|
+
def self.organize(*interactors, &block)
|
205
|
+
organized.concat(interactors) if interactors
|
206
|
+
organized.instance_eval(&block) if block
|
207
|
+
organized
|
208
|
+
end
|
209
|
+
|
210
|
+
# Organized interactors
|
211
|
+
# @return [InteractorInterfaceCollection] an instance of {InteractorInterfaceCollection}
|
212
|
+
def self.organized
|
213
|
+
@organized ||= InteractorInterfaceCollection.new
|
190
214
|
end
|
191
215
|
|
192
216
|
# Run organized interactors in parallel
|
@@ -196,7 +220,7 @@ module ActiveInteractor
|
|
196
220
|
end
|
197
221
|
|
198
222
|
# Invoke the organized interactors. An organizer is
|
199
|
-
# expected not to define its own {
|
223
|
+
# expected not to define its own {Interactor#perform #perform} method
|
200
224
|
# in favor of this default implementation.
|
201
225
|
def perform
|
202
226
|
if self.class.parallel
|
@@ -208,11 +232,16 @@ module ActiveInteractor
|
|
208
232
|
|
209
233
|
private
|
210
234
|
|
211
|
-
def
|
235
|
+
def execute_interactor(interface, fail_on_error = false, perform_options = {})
|
236
|
+
interface.perform(self, context, fail_on_error, perform_options)
|
237
|
+
end
|
238
|
+
|
239
|
+
def execute_interactor_with_callbacks(interface, fail_on_error = false, perform_options = {})
|
240
|
+
args = [interface, fail_on_error, perform_options]
|
241
|
+
return execute_interactor(*args) if options.skip_each_perform_callbacks
|
242
|
+
|
212
243
|
run_callbacks :each_perform do
|
213
|
-
|
214
|
-
method = fail_on_error ? :execute_perform! : :execute_perform
|
215
|
-
instance.send(method, execute_options)
|
244
|
+
execute_interactor(*args)
|
216
245
|
end
|
217
246
|
end
|
218
247
|
|
@@ -222,16 +251,17 @@ module ActiveInteractor
|
|
222
251
|
end
|
223
252
|
|
224
253
|
def perform_in_order
|
225
|
-
self.class.organized.each do |
|
226
|
-
|
254
|
+
self.class.organized.each do |interface|
|
255
|
+
result = execute_interactor_with_callbacks(interface, true)
|
256
|
+
context.merge!(result) if result
|
227
257
|
end
|
228
258
|
rescue Error::ContextFailure => e
|
229
259
|
context.merge!(e.context)
|
230
260
|
end
|
231
261
|
|
232
262
|
def perform_in_parallel
|
233
|
-
results = self.class.organized.map do |
|
234
|
-
Thread.new { execute_interactor_with_callbacks(
|
263
|
+
results = self.class.organized.map do |interface|
|
264
|
+
Thread.new { execute_interactor_with_callbacks(interface, false, skip_rollback: true) }
|
235
265
|
end
|
236
266
|
merge_contexts(results.map(&:value))
|
237
267
|
end
|