activeinteractor 1.1.6 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -1
- data/lib/active_interactor/interactor/callbacks.rb +18 -0
- data/lib/active_interactor/organizer/callbacks.rb +123 -1
- data/lib/active_interactor/organizer/interactor_interface.rb +33 -1
- data/lib/active_interactor/organizer/perform.rb +15 -4
- data/lib/active_interactor/version.rb +2 -2
- data/spec/integration/an_interactor_with_deferred_after_callbacks.rb +32 -0
- data/spec/integration/an_organizer_containing_organizer_with_after_callbacks_deferred_spec.rb +125 -0
- data/spec/integration/an_organizer_with_after_callbacks_deferred_spec.rb +154 -0
- data/spec/integration/an_organizer_with_all_perform_callbacks.rb +112 -0
- metadata +55 -47
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7d574fdd7c5e1d8666f8d61c4b6acd9aca316ca1789aa84950233f151fe4f9ca
|
4
|
+
data.tar.gz: 9589d5a2a8e04681d30bcda448d8459007b941d38f5756b12ed1ae2fee478d12
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 99401e868682e3fad2f702da4bf38e711e8637584210622fc70e0970f4600d8713da3ce2539019bea231953e88257ea4b9d62db026f9a90ce6aa8c9461d76c1e
|
7
|
+
data.tar.gz: 9a81aff115c7351de89fa45689a7fc2e3b225ad15ad9a437acfa18dc2ff58839491447f77b8593c9c8098d71058d681323caed1054fbbdc518f4ea5bd705989e
|
data/CHANGELOG.md
CHANGED
@@ -7,6 +7,15 @@ and this project adheres to [Semantic Versioning].
|
|
7
7
|
|
8
8
|
## [Unreleased]
|
9
9
|
|
10
|
+
## [v1.2.0] - 2022-09-08
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- `ActiveInteractor::Base.defer_after_callbacks_when_organized`
|
15
|
+
- `ActiveInteractor::Organizer::Base.after_all_perform`
|
16
|
+
- `ActiveInteractor::Organizer::Base.around_all_perform`
|
17
|
+
- `ActiveInteractor::Organizer::Base.before_all_perform`
|
18
|
+
|
10
19
|
## [v1.1.6] - 2022-04-25
|
11
20
|
|
12
21
|
### Changed
|
@@ -249,7 +258,8 @@ and this project adheres to [Semantic Versioning].
|
|
249
258
|
|
250
259
|
<!-- versions -->
|
251
260
|
|
252
|
-
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.
|
261
|
+
[Unreleased]: https://github.com/aaronmallen/activeinteractor/compare/v1.2.0...HEAD
|
262
|
+
[v1.2.0]: https://github.com/aaronmallen/activeinteractor/compare/v1.1.6...v1.2.0
|
253
263
|
[v1.1.6]: https://github.com/aaronmallen/activeinteractor/compare/v1.1.4...v1.1.6
|
254
264
|
[v1.1.4]: https://github.com/aaronmallen/activeinteractor/compare/v1.1.3...v1.1.4
|
255
265
|
[v1.1.3]: https://github.com/aaronmallen/activeinteractor/compare/v1.1.2...v1.1.3
|
@@ -249,6 +249,24 @@ module ActiveInteractor
|
|
249
249
|
set_callback(:rollback, :before, *filters, &block)
|
250
250
|
end
|
251
251
|
|
252
|
+
# Set {.after_callbacks_deferred_when_organized} to `true`
|
253
|
+
#
|
254
|
+
# @since v1.2.0
|
255
|
+
#
|
256
|
+
# @example a basic {Base organizer} set to defer 'after' callbacks when organized
|
257
|
+
# class MyOrganizer < ActiveInteractor::Organizer::Base
|
258
|
+
# defer_after_callbacks_when_organized
|
259
|
+
# end
|
260
|
+
def defer_after_callbacks_when_organized
|
261
|
+
self.after_callbacks_deferred_when_organized = true
|
262
|
+
end
|
263
|
+
|
264
|
+
def self.extended(base)
|
265
|
+
base.class_eval do
|
266
|
+
class_attribute :after_callbacks_deferred_when_organized, instance_writer: false, default: false
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
252
270
|
private
|
253
271
|
|
254
272
|
def normalize_options(options)
|
@@ -141,11 +141,133 @@ module ActiveInteractor
|
|
141
141
|
def before_each_perform(*filters, &block)
|
142
142
|
set_callback(:each_perform, :before, *filters, &block)
|
143
143
|
end
|
144
|
+
|
145
|
+
# Define a callback to call after all {Organizer::Organize::ClassMethods#organized organized}
|
146
|
+
# {ActiveInteractor::Base interactors'} {Interactor::Perform#perform #perform} methods have been called.
|
147
|
+
#
|
148
|
+
# @since v1.2.0
|
149
|
+
#
|
150
|
+
# @example
|
151
|
+
# class MyInteractor1 < ActiveInteractor::Base
|
152
|
+
# def perform
|
153
|
+
# puts 'MyInteractor1'
|
154
|
+
# end
|
155
|
+
# end
|
156
|
+
#
|
157
|
+
# class MyInteractor2 < ActiveInteractor::Base
|
158
|
+
# def perform
|
159
|
+
# puts 'MyInteractor2'
|
160
|
+
# end
|
161
|
+
# end
|
162
|
+
#
|
163
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
164
|
+
# after_all_perform :print_done
|
165
|
+
#
|
166
|
+
# organized MyInteractor1, MyInteractor2
|
167
|
+
#
|
168
|
+
# private
|
169
|
+
#
|
170
|
+
# def print_done
|
171
|
+
# puts 'Done'
|
172
|
+
# end
|
173
|
+
# end
|
174
|
+
#
|
175
|
+
# MyOrganizer.perform
|
176
|
+
# "MyInteractor1"
|
177
|
+
# "MyInteractor2"
|
178
|
+
# "Done"
|
179
|
+
# #=> <MyOrganizer::Context>
|
180
|
+
def after_all_perform(*filters, &block)
|
181
|
+
set_callback(:all_perform, :after, *filters, &block)
|
182
|
+
end
|
183
|
+
|
184
|
+
# Define a callback to call around all {Organizer::Organize::ClassMethods#organized organized}
|
185
|
+
# {ActiveInteractor::Base interactors'} {Interactor::Perform#perform #perform} method calls.
|
186
|
+
#
|
187
|
+
# @since v1.2.0
|
188
|
+
#
|
189
|
+
# @example
|
190
|
+
# class MyInteractor1 < ActiveInteractor::Base
|
191
|
+
# def perform
|
192
|
+
# puts 'MyInteractor1'
|
193
|
+
# sleep(1)
|
194
|
+
# end
|
195
|
+
# end
|
196
|
+
#
|
197
|
+
# class MyInteractor2 < ActiveInteractor::Base
|
198
|
+
# def perform
|
199
|
+
# puts 'MyInteractor2'
|
200
|
+
# sleep(1)
|
201
|
+
# end
|
202
|
+
# end
|
203
|
+
#
|
204
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
205
|
+
# around_all_perform :print_time
|
206
|
+
#
|
207
|
+
# organized MyInteractor1, MyInteractor2
|
208
|
+
#
|
209
|
+
# private
|
210
|
+
#
|
211
|
+
# def print_time
|
212
|
+
# puts Time.now.utc
|
213
|
+
# yield
|
214
|
+
# puts Time.now.utc
|
215
|
+
# end
|
216
|
+
# end
|
217
|
+
#
|
218
|
+
# MyOrganizer.perform
|
219
|
+
# "2019-04-01 00:00:00 UTC"
|
220
|
+
# "MyInteractor1"
|
221
|
+
# "MyInteractor2"
|
222
|
+
# "2019-04-01 00:00:02 UTC"
|
223
|
+
# #=> <MyOrganizer::Context>
|
224
|
+
def around_all_perform(*filters, &block)
|
225
|
+
set_callback(:all_perform, :around, *filters, &block)
|
226
|
+
end
|
227
|
+
|
228
|
+
# Define a callback to call before all {Organizer::Organize::ClassMethods#organized organized}
|
229
|
+
# {ActiveInteractor::Base interactors'} {Interactor::Perform#perform #perform} methods have been called.
|
230
|
+
#
|
231
|
+
# @since v1.2.0
|
232
|
+
#
|
233
|
+
# @example
|
234
|
+
# class MyInteractor1 < ActiveInteractor::Base
|
235
|
+
# def perform
|
236
|
+
# puts 'MyInteractor1'
|
237
|
+
# end
|
238
|
+
# end
|
239
|
+
#
|
240
|
+
# class MyInteractor2 < ActiveInteractor::Base
|
241
|
+
# def perform
|
242
|
+
# puts 'MyInteractor2'
|
243
|
+
# end
|
244
|
+
# end
|
245
|
+
#
|
246
|
+
# class MyOrganizer < ActiveInteractor::Organizer
|
247
|
+
# before_all_perform :print_starting
|
248
|
+
#
|
249
|
+
# organized MyInteractor1, MyInteractor2
|
250
|
+
#
|
251
|
+
# private
|
252
|
+
#
|
253
|
+
# def print_starting
|
254
|
+
# puts 'Starting'
|
255
|
+
# end
|
256
|
+
# end
|
257
|
+
#
|
258
|
+
# MyOrganizer.perform
|
259
|
+
# "Starting"
|
260
|
+
# "MyInteractor1"
|
261
|
+
# "MyInteractor2"
|
262
|
+
# #=> <MyOrganizer::Context>
|
263
|
+
def before_all_perform(*filters, &block)
|
264
|
+
set_callback(:all_perform, :before, *filters, &block)
|
265
|
+
end
|
144
266
|
end
|
145
267
|
|
146
268
|
def self.included(base)
|
147
269
|
base.class_eval do
|
148
|
-
define_callbacks :each_perform
|
270
|
+
define_callbacks :each_perform, :all_perform
|
149
271
|
end
|
150
272
|
end
|
151
273
|
end
|
@@ -33,8 +33,14 @@ module ActiveInteractor
|
|
33
33
|
#
|
34
34
|
# @return [Hash{Symbol=>*}] {Interactor::Perform::Options} for the {ActiveInteractor::Base interactor}
|
35
35
|
# {Interactor::Perform#perform #perform}
|
36
|
+
#
|
37
|
+
# @!attribute [r] deferred_after_perform_callbacks
|
38
|
+
# Deffered callbacks for the interactor_class
|
39
|
+
# @since 1.2.0
|
40
|
+
#
|
41
|
+
# @return [Hash{Symbol=>*}] the interactor callbacks
|
36
42
|
class InteractorInterface
|
37
|
-
attr_reader :filters, :callbacks, :interactor_class, :perform_options
|
43
|
+
attr_reader :filters, :callbacks, :interactor_class, :perform_options, :deferred_after_perform_callbacks
|
38
44
|
|
39
45
|
# Keywords for conditional filters
|
40
46
|
# @return [Array<Symbol>]
|
@@ -52,6 +58,7 @@ module ActiveInteractor
|
|
52
58
|
@filters = options.select { |key, _value| CONDITIONAL_FILTERS.include?(key) }
|
53
59
|
@callbacks = options.select { |key, _value| CALLBACKS.include?(key) }
|
54
60
|
@perform_options = options.reject { |key, _value| CONDITIONAL_FILTERS.include?(key) || CALLBACKS.include?(key) }
|
61
|
+
init_deferred_after_perform_callbacks
|
55
62
|
end
|
56
63
|
|
57
64
|
# Call the {#interactor_class} {Interactor::Perform::ClassMethods#perform .perform} or
|
@@ -69,6 +76,8 @@ module ActiveInteractor
|
|
69
76
|
return if check_conditionals(target, :if) == false
|
70
77
|
return if check_conditionals(target, :unless) == true
|
71
78
|
|
79
|
+
skip_deferred_after_perform_callbacks
|
80
|
+
|
72
81
|
method = fail_on_error ? :perform! : :perform
|
73
82
|
options = self.perform_options.merge(perform_options)
|
74
83
|
interactor_class.send(method, context, options)
|
@@ -78,8 +87,31 @@ module ActiveInteractor
|
|
78
87
|
resolve_option(target, callbacks[callback])
|
79
88
|
end
|
80
89
|
|
90
|
+
def execute_deferred_after_perform_callbacks(context)
|
91
|
+
return unless deferred_after_perform_callbacks.present?
|
92
|
+
|
93
|
+
interactor = interactor_class.new(context)
|
94
|
+
env = ActiveSupport::Callbacks::Filters::Environment.new(interactor, false, nil)
|
95
|
+
deferred_after_perform_callbacks.compile.invoke_after(env)
|
96
|
+
interactor.send(:context)
|
97
|
+
end
|
98
|
+
|
81
99
|
private
|
82
100
|
|
101
|
+
def init_deferred_after_perform_callbacks
|
102
|
+
after_callbacks_deferred = interactor_class.present? &&
|
103
|
+
interactor_class.after_callbacks_deferred_when_organized
|
104
|
+
@deferred_after_perform_callbacks = after_callbacks_deferred ? interactor_class._perform_callbacks : nil
|
105
|
+
end
|
106
|
+
|
107
|
+
def skip_deferred_after_perform_callbacks
|
108
|
+
return unless deferred_after_perform_callbacks.present?
|
109
|
+
|
110
|
+
deferred_after_perform_callbacks.each do |callback|
|
111
|
+
interactor_class.skip_callback(:perform, :after, callback.filter, raise: false)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
83
115
|
def check_conditionals(target, filter)
|
84
116
|
resolve_option(target, filters[filter])
|
85
117
|
end
|
@@ -46,11 +46,14 @@ module ActiveInteractor
|
|
46
46
|
# {Interactor::Perform#perform #perform}. An {Base organizer} is expected not to define its own
|
47
47
|
# {Interactor::Perform#perform #perform} method in favor of this default implementation.
|
48
48
|
def perform
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
49
|
+
run_callbacks :all_perform do
|
50
|
+
if self.class.parallel
|
51
|
+
perform_in_parallel
|
52
|
+
else
|
53
|
+
perform_in_order
|
54
|
+
end
|
53
55
|
end
|
56
|
+
run_after_perform_callbacks_on_interactors if context.success?
|
54
57
|
end
|
55
58
|
|
56
59
|
private
|
@@ -97,6 +100,14 @@ module ActiveInteractor
|
|
97
100
|
end
|
98
101
|
merge_contexts(results.map(&:value))
|
99
102
|
end
|
103
|
+
|
104
|
+
def run_after_perform_callbacks_on_interactors
|
105
|
+
self.class.organized.each do |interface|
|
106
|
+
next unless interface.interactor_class.after_callbacks_deferred_when_organized
|
107
|
+
|
108
|
+
context.merge!(interface.execute_deferred_after_perform_callbacks(context))
|
109
|
+
end
|
110
|
+
end
|
100
111
|
end
|
101
112
|
end
|
102
113
|
end
|
@@ -12,11 +12,11 @@ module ActiveInteractor
|
|
12
12
|
|
13
13
|
# The ActiveInterctor minor version number
|
14
14
|
# @return [Integer] The ActiveInteractor minor version number
|
15
|
-
MINOR =
|
15
|
+
MINOR = 2
|
16
16
|
|
17
17
|
# The ActiveInterctor patch version number
|
18
18
|
# @return [Integer] The ActiveInteractor patch version number
|
19
|
-
PATCH =
|
19
|
+
PATCH = 0
|
20
20
|
|
21
21
|
# The ActiveInterctor pre-release version
|
22
22
|
# @return [String | nil] The ActiveInteractor pre-release version
|
@@ -0,0 +1,32 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'An interactor with deferred after callbacks', type: :integration do
|
6
|
+
let!(:interactor_with_config) do
|
7
|
+
build_interactor('InteractorWithConfig') do
|
8
|
+
defer_after_callbacks_when_organized
|
9
|
+
|
10
|
+
def perform
|
11
|
+
context.test_field_1 = 'test'
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
let!(:interactor_without_config) do
|
17
|
+
build_interactor('InteractorWithoutConfig') do
|
18
|
+
|
19
|
+
def perform
|
20
|
+
context.test_field_2 = 'test'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'is expected to have true for InteractorWithConfig#after_callbacks_deferred_when_organized' do
|
26
|
+
expect(InteractorWithConfig).to have_attributes(after_callbacks_deferred_when_organized: true)
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'is expected to have false for InteractorWithoutConfig#after_callbacks_deferred_when_organized' do
|
30
|
+
expect(InteractorWithoutConfig).to have_attributes(after_callbacks_deferred_when_organized: false)
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,125 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'An organizer containing an organizer with after callbacks deferred', type: :integration do
|
6
|
+
let!(:test_interactor_1) do
|
7
|
+
build_interactor('TestInteractor1') do
|
8
|
+
defer_after_callbacks_when_organized
|
9
|
+
|
10
|
+
after_perform do
|
11
|
+
context.after_perform_1a = context.after_perform_1b + 1
|
12
|
+
end
|
13
|
+
|
14
|
+
after_perform do
|
15
|
+
context.after_perform_1b = context.after_perform_2 + 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform
|
19
|
+
context.perform_1 = 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let!(:test_interactor_2) do
|
25
|
+
build_interactor('TestInteractor2') do
|
26
|
+
after_perform do
|
27
|
+
context.after_perform_2 = context.perform_2 + 1
|
28
|
+
end
|
29
|
+
|
30
|
+
def perform
|
31
|
+
context.perform_2 = context.after_perform_3a + 1
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
let!(:test_interactor_3) do
|
37
|
+
build_interactor('TestInteractor3') do
|
38
|
+
defer_after_callbacks_when_organized
|
39
|
+
|
40
|
+
after_perform do
|
41
|
+
context.after_perform_3a = context.after_perform_3b + 1
|
42
|
+
end
|
43
|
+
|
44
|
+
after_perform do
|
45
|
+
context.after_perform_3b = context.after_perform_4a + 1
|
46
|
+
end
|
47
|
+
|
48
|
+
def perform
|
49
|
+
context.perform_3 = context.perform_1 + 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
let!(:test_interactor_4) do
|
55
|
+
build_interactor('TestInteractor4') do
|
56
|
+
after_perform do
|
57
|
+
context.after_perform_4a = context.after_perform_4b + 1
|
58
|
+
end
|
59
|
+
|
60
|
+
after_perform do
|
61
|
+
context.after_perform_4b = context.perform_4 + 1
|
62
|
+
end
|
63
|
+
|
64
|
+
def perform
|
65
|
+
context.perform_4 = context.perform_3 + 1
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
let!(:test_sub_organizer_5) do
|
71
|
+
build_organizer('TestSubOrganizer5') do
|
72
|
+
defer_after_callbacks_when_organized
|
73
|
+
|
74
|
+
after_perform do
|
75
|
+
context.after_perform_5a = context.after_perform_5b + 1
|
76
|
+
end
|
77
|
+
|
78
|
+
after_perform do
|
79
|
+
context.after_perform_5b = context.after_perform_1a + 1
|
80
|
+
end
|
81
|
+
|
82
|
+
organize TestInteractor3, TestInteractor4
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
let(:interactor_class) do
|
87
|
+
build_organizer do
|
88
|
+
organize TestInteractor1, TestSubOrganizer5, TestInteractor2
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
include_examples 'a class with interactor methods'
|
93
|
+
include_examples 'a class with interactor callback methods'
|
94
|
+
include_examples 'a class with interactor context methods'
|
95
|
+
include_examples 'a class with organizer callback methods'
|
96
|
+
|
97
|
+
describe '.context_class' do
|
98
|
+
subject { interactor_class.context_class }
|
99
|
+
|
100
|
+
it { is_expected.to eq TestOrganizer::Context }
|
101
|
+
it { is_expected.to be < ActiveInteractor::Context::Base }
|
102
|
+
end
|
103
|
+
|
104
|
+
describe '.perform' do
|
105
|
+
subject { interactor_class.perform }
|
106
|
+
|
107
|
+
it { is_expected.to be_a interactor_class.context_class }
|
108
|
+
it { is_expected.to be_successful }
|
109
|
+
it { is_expected.to have_attributes(
|
110
|
+
perform_1: 1,
|
111
|
+
perform_3: 2,
|
112
|
+
perform_4: 3,
|
113
|
+
after_perform_4b: 4,
|
114
|
+
after_perform_4a: 5,
|
115
|
+
after_perform_3b: 6,
|
116
|
+
after_perform_3a: 7,
|
117
|
+
perform_2: 8,
|
118
|
+
after_perform_2: 9,
|
119
|
+
after_perform_1b: 10,
|
120
|
+
after_perform_1a: 11,
|
121
|
+
after_perform_5b: 12,
|
122
|
+
after_perform_5a: 13,
|
123
|
+
) }
|
124
|
+
end
|
125
|
+
end
|
@@ -0,0 +1,154 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'An organizer with after callbacks deferred', type: :integration do
|
6
|
+
let!(:test_interactor_1) do
|
7
|
+
build_interactor('TestInteractor1') do
|
8
|
+
defer_after_callbacks_when_organized
|
9
|
+
|
10
|
+
after_perform do
|
11
|
+
context.after_perform_1a = context.after_perform_1b + 1
|
12
|
+
end
|
13
|
+
|
14
|
+
after_perform do
|
15
|
+
context.after_perform_1b = context.after_perform_3a + 1
|
16
|
+
end
|
17
|
+
|
18
|
+
def perform
|
19
|
+
context.perform_1 = 1
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
let!(:test_interactor_2) do
|
25
|
+
build_interactor('TestInteractor2') do
|
26
|
+
defer_after_callbacks_when_organized
|
27
|
+
|
28
|
+
after_perform do
|
29
|
+
context.after_perform_2 = context.after_perform_1a + 1
|
30
|
+
end
|
31
|
+
|
32
|
+
def perform
|
33
|
+
context.perform_2 = context.perform_1 + 1
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
let!(:test_interactor_3) do
|
39
|
+
build_interactor('TestInteractor3') do
|
40
|
+
after_perform do
|
41
|
+
context.after_perform_3a = context.after_perform_3b + 1
|
42
|
+
end
|
43
|
+
|
44
|
+
after_perform do
|
45
|
+
context.after_perform_3b = context.perform_3 + 1
|
46
|
+
end
|
47
|
+
|
48
|
+
def perform
|
49
|
+
context.perform_3 = context.perform_2 + 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:interactor_class) do
|
55
|
+
build_organizer do
|
56
|
+
organize TestInteractor1, TestInteractor2, TestInteractor3
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
include_examples 'a class with interactor methods'
|
61
|
+
include_examples 'a class with interactor callback methods'
|
62
|
+
include_examples 'a class with interactor context methods'
|
63
|
+
include_examples 'a class with organizer callback methods'
|
64
|
+
|
65
|
+
describe '.context_class' do
|
66
|
+
subject { interactor_class.context_class }
|
67
|
+
|
68
|
+
it { is_expected.to eq TestOrganizer::Context }
|
69
|
+
it { is_expected.to be < ActiveInteractor::Context::Base }
|
70
|
+
end
|
71
|
+
|
72
|
+
describe '.perform' do
|
73
|
+
subject { interactor_class.perform }
|
74
|
+
|
75
|
+
it { is_expected.to be_a interactor_class.context_class }
|
76
|
+
it { is_expected.to be_successful }
|
77
|
+
it { is_expected.to have_attributes(
|
78
|
+
perform_1: 1,
|
79
|
+
perform_2: 2,
|
80
|
+
perform_3: 3,
|
81
|
+
after_perform_3b: 4,
|
82
|
+
after_perform_3a: 5,
|
83
|
+
after_perform_1b: 6,
|
84
|
+
after_perform_1a: 7,
|
85
|
+
after_perform_2: 8,
|
86
|
+
) }
|
87
|
+
|
88
|
+
context 'when last interactor fails' do
|
89
|
+
let!(:failing_interactor) do
|
90
|
+
build_interactor('FailingInteractor') do
|
91
|
+
def perform
|
92
|
+
context.fail!
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
let(:interactor_class) do
|
98
|
+
build_organizer do
|
99
|
+
organize TestInteractor1, TestInteractor2, FailingInteractor
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
subject { interactor_class.perform}
|
104
|
+
|
105
|
+
it { is_expected.to have_attributes(
|
106
|
+
perform_1: 1,
|
107
|
+
perform_2: 2,
|
108
|
+
)}
|
109
|
+
|
110
|
+
it { is_expected.to_not respond_to(
|
111
|
+
:after_perform_1a,
|
112
|
+
:after_perform_1b,
|
113
|
+
)}
|
114
|
+
end
|
115
|
+
|
116
|
+
context 'when after_perform in first interactor fails' do
|
117
|
+
let!(:failing_interactor) do
|
118
|
+
build_interactor('FailingInteractor') do
|
119
|
+
defer_after_callbacks_when_organized
|
120
|
+
|
121
|
+
after_perform do
|
122
|
+
context.fail!
|
123
|
+
end
|
124
|
+
|
125
|
+
def perform
|
126
|
+
context.perform_1 = 1
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
let(:interactor_class) do
|
132
|
+
build_organizer do
|
133
|
+
organize FailingInteractor, TestInteractor2, TestInteractor3
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
subject { interactor_class.perform}
|
138
|
+
|
139
|
+
it { is_expected.to have_attributes(
|
140
|
+
perform_1: 1,
|
141
|
+
perform_2: 2,
|
142
|
+
perform_3: 3,
|
143
|
+
after_perform_3b: 4,
|
144
|
+
after_perform_3a: 5,
|
145
|
+
)}
|
146
|
+
|
147
|
+
it { is_expected.to_not respond_to(
|
148
|
+
:after_perform_1a,
|
149
|
+
:after_perform_1b,
|
150
|
+
:after_perform_2,
|
151
|
+
)}
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
@@ -0,0 +1,112 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'spec_helper'
|
4
|
+
|
5
|
+
RSpec.describe 'An organizer with around all callbacks', type: :integration do
|
6
|
+
let!(:test_interactor_1) do
|
7
|
+
build_interactor('TestInteractor1') do
|
8
|
+
before_perform do
|
9
|
+
context.before_perform_1 = context.around_all_perform_start + 1
|
10
|
+
end
|
11
|
+
|
12
|
+
after_perform do
|
13
|
+
context.after_perform_1 = context.around_perform_1_end + 1
|
14
|
+
end
|
15
|
+
|
16
|
+
around_perform :around
|
17
|
+
def around
|
18
|
+
context.around_perform_1_start = context.before_perform_1 + 1
|
19
|
+
yield
|
20
|
+
context.around_perform_1_end = context.perform_1 + 1
|
21
|
+
end
|
22
|
+
|
23
|
+
def perform
|
24
|
+
context.perform_1 = context.around_perform_1_start + 1
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
let!(:test_interactor_2) do
|
30
|
+
build_interactor('TestInteractor2') do
|
31
|
+
defer_after_callbacks_when_organized
|
32
|
+
|
33
|
+
before_perform do
|
34
|
+
context.before_perform_2 = context.after_perform_1 + 1
|
35
|
+
end
|
36
|
+
|
37
|
+
after_perform do
|
38
|
+
context.after_perform_2 = context.after_all_perform + 1
|
39
|
+
end
|
40
|
+
|
41
|
+
around_perform :around
|
42
|
+
def around
|
43
|
+
context.around_perform_2_start = context.before_perform_2 + 1
|
44
|
+
yield
|
45
|
+
context.around_perform_2_end = context.perform_2 + 1
|
46
|
+
end
|
47
|
+
|
48
|
+
def perform
|
49
|
+
context.perform_2 = context.around_perform_2_start + 1
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
let(:interactor_class) do
|
55
|
+
build_organizer do
|
56
|
+
before_all_perform do
|
57
|
+
context.before_all_perform = 1
|
58
|
+
end
|
59
|
+
|
60
|
+
after_all_perform do
|
61
|
+
context.after_all_perform = context.around_all_perform_end + 1
|
62
|
+
end
|
63
|
+
|
64
|
+
around_all_perform :around_all
|
65
|
+
def around_all
|
66
|
+
context.around_all_perform_start = context.before_all_perform + 1
|
67
|
+
yield
|
68
|
+
context.around_all_perform_end = context.around_perform_2_end + 1
|
69
|
+
end
|
70
|
+
|
71
|
+
organize TestInteractor1, TestInteractor2
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
include_examples 'a class with interactor methods'
|
76
|
+
include_examples 'a class with interactor callback methods'
|
77
|
+
include_examples 'a class with interactor context methods'
|
78
|
+
include_examples 'a class with organizer callback methods'
|
79
|
+
|
80
|
+
describe '.context_class' do
|
81
|
+
subject { interactor_class.context_class }
|
82
|
+
|
83
|
+
it { is_expected.to eq TestOrganizer::Context }
|
84
|
+
it { is_expected.to be < ActiveInteractor::Context::Base }
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '.perform' do
|
88
|
+
subject { interactor_class.perform }
|
89
|
+
|
90
|
+
it { is_expected.to be_a interactor_class.context_class }
|
91
|
+
it { is_expected.to be_successful }
|
92
|
+
it { is_expected.to have_attributes(
|
93
|
+
before_all_perform: 1,
|
94
|
+
around_all_perform_start: 2,
|
95
|
+
|
96
|
+
before_perform_1: 3,
|
97
|
+
around_perform_1_start: 4,
|
98
|
+
perform_1: 5,
|
99
|
+
around_perform_1_end: 6,
|
100
|
+
after_perform_1: 7,
|
101
|
+
|
102
|
+
before_perform_2: 8,
|
103
|
+
around_perform_2_start: 9,
|
104
|
+
perform_2: 10,
|
105
|
+
around_perform_2_end: 11,
|
106
|
+
|
107
|
+
around_all_perform_end: 12,
|
108
|
+
after_all_perform: 13,
|
109
|
+
after_perform_2: 14,
|
110
|
+
) }
|
111
|
+
end
|
112
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: activeinteractor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Aaron Allen
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-
|
11
|
+
date: 2022-09-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activemodel
|
@@ -17,9 +17,9 @@ dependencies:
|
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '4.2'
|
20
|
-
- - "
|
20
|
+
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version:
|
22
|
+
version: '8'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -27,9 +27,9 @@ dependencies:
|
|
27
27
|
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '4.2'
|
30
|
-
- - "
|
30
|
+
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version:
|
32
|
+
version: '8'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: activesupport
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
@@ -37,9 +37,9 @@ dependencies:
|
|
37
37
|
- - ">="
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '4.2'
|
40
|
-
- - "
|
40
|
+
- - "<"
|
41
41
|
- !ruby/object:Gem::Version
|
42
|
-
version:
|
42
|
+
version: '8'
|
43
43
|
type: :runtime
|
44
44
|
prerelease: false
|
45
45
|
version_requirements: !ruby/object:Gem::Requirement
|
@@ -47,23 +47,23 @@ dependencies:
|
|
47
47
|
- - ">="
|
48
48
|
- !ruby/object:Gem::Version
|
49
49
|
version: '4.2'
|
50
|
-
- - "
|
50
|
+
- - "<"
|
51
51
|
- !ruby/object:Gem::Version
|
52
|
-
version:
|
52
|
+
version: '8'
|
53
53
|
- !ruby/object:Gem::Dependency
|
54
54
|
name: bundler
|
55
55
|
requirement: !ruby/object:Gem::Requirement
|
56
56
|
requirements:
|
57
57
|
- - "~>"
|
58
58
|
- !ruby/object:Gem::Version
|
59
|
-
version: '2.
|
59
|
+
version: '2.3'
|
60
60
|
type: :development
|
61
61
|
prerelease: false
|
62
62
|
version_requirements: !ruby/object:Gem::Requirement
|
63
63
|
requirements:
|
64
64
|
- - "~>"
|
65
65
|
- !ruby/object:Gem::Version
|
66
|
-
version: '2.
|
66
|
+
version: '2.3'
|
67
67
|
- !ruby/object:Gem::Dependency
|
68
68
|
name: rake
|
69
69
|
requirement: !ruby/object:Gem::Requirement
|
@@ -84,14 +84,14 @@ dependencies:
|
|
84
84
|
requirements:
|
85
85
|
- - "~>"
|
86
86
|
- !ruby/object:Gem::Version
|
87
|
-
version: '3.
|
87
|
+
version: '3.11'
|
88
88
|
type: :development
|
89
89
|
prerelease: false
|
90
90
|
version_requirements: !ruby/object:Gem::Requirement
|
91
91
|
requirements:
|
92
92
|
- - "~>"
|
93
93
|
- !ruby/object:Gem::Version
|
94
|
-
version: '3.
|
94
|
+
version: '3.11'
|
95
95
|
description: |
|
96
96
|
An implementation of the Command Pattern for Ruby with ActiveModel::Validations inspired by the interactor gem.
|
97
97
|
Rich support for attributes, callbacks, and validations, and thread safe performance methods.
|
@@ -181,11 +181,15 @@ files:
|
|
181
181
|
- spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb
|
182
182
|
- spec/integration/an_interactor_with_before_perform_callbacks_spec.rb
|
183
183
|
- spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb
|
184
|
+
- spec/integration/an_interactor_with_deferred_after_callbacks.rb
|
184
185
|
- spec/integration/an_interactor_with_validations_on_called_spec.rb
|
185
186
|
- spec/integration/an_interactor_with_validations_on_calling_spec.rb
|
186
187
|
- spec/integration/an_interactor_with_validations_spec.rb
|
188
|
+
- spec/integration/an_organizer_containing_organizer_with_after_callbacks_deferred_spec.rb
|
187
189
|
- spec/integration/an_organizer_performing_in_parallel_spec.rb
|
190
|
+
- spec/integration/an_organizer_with_after_callbacks_deferred_spec.rb
|
188
191
|
- spec/integration/an_organizer_with_after_each_callbacks_spec.rb
|
192
|
+
- spec/integration/an_organizer_with_all_perform_callbacks.rb
|
189
193
|
- spec/integration/an_organizer_with_around_each_callbacks_spec.rb
|
190
194
|
- spec/integration/an_organizer_with_before_each_callbacks_spec.rb
|
191
195
|
- spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb
|
@@ -205,10 +209,10 @@ licenses:
|
|
205
209
|
- MIT
|
206
210
|
metadata:
|
207
211
|
bug_tracker_uri: https://github.com/aaronmallen/activeinteractor/issues
|
208
|
-
changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.
|
209
|
-
documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.
|
212
|
+
changelog_uri: https://github.com/aaronmallen/activeinteractor/blob/v1.2.0/CHANGELOG.md
|
213
|
+
documentation_uri: https://www.rubydoc.info/gems/activeinteractor/1.2.0
|
210
214
|
hompage_uri: https://github.com/aaronmallen/activeinteractor
|
211
|
-
source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.
|
215
|
+
source_code_uri: https://github.com/aaronmallen/activeinteractor/tree/v1.2.0
|
212
216
|
wiki_uri: https://github.com/aaronmallen/activeinteractor/wiki
|
213
217
|
post_install_message:
|
214
218
|
rdoc_options: []
|
@@ -230,45 +234,49 @@ signing_key:
|
|
230
234
|
specification_version: 4
|
231
235
|
summary: Ruby interactors with ActiveModel::Validations
|
232
236
|
test_files:
|
233
|
-
- spec/
|
234
|
-
- spec/integration/
|
235
|
-
- spec/integration/
|
236
|
-
- spec/integration/an_interactor_with_before_perform_callbacks_spec.rb
|
237
|
-
- spec/integration/an_organizer_performing_in_parallel_spec.rb
|
237
|
+
- spec/integration/an_interactor_with_deferred_after_callbacks.rb
|
238
|
+
- spec/integration/an_interactor_with_validations_spec.rb
|
239
|
+
- spec/integration/an_organizer_with_after_callbacks_deferred_spec.rb
|
238
240
|
- spec/integration/an_organizer_with_before_each_callbacks_spec.rb
|
239
|
-
- spec/integration/
|
240
|
-
- spec/integration/an_organizer_with_failing_nested_organizer_spec.rb
|
241
|
+
- spec/integration/an_organizer_performing_in_parallel_spec.rb
|
241
242
|
- spec/integration/an_organizer_with_around_each_callbacks_spec.rb
|
242
|
-
- spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb
|
243
|
-
- spec/integration/an_interactor_with_validations_on_called_spec.rb
|
244
|
-
- spec/integration/an_interactor_with_validations_on_calling_spec.rb
|
245
|
-
- spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb
|
246
|
-
- spec/integration/an_interactor_with_after_rollback_callbacks_spec.rb
|
247
|
-
- spec/integration/an_interactor_with_after_context_validation_callbacks_spec.rb
|
248
|
-
- spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb
|
249
|
-
- spec/integration/a_failing_interactor_spec.rb
|
250
243
|
- spec/integration/a_basic_interactor_spec.rb
|
251
|
-
- spec/integration/
|
244
|
+
- spec/integration/an_interactor_with_an_existing_context_class_spec.rb
|
245
|
+
- spec/integration/an_interactor_with_validations_on_calling_spec.rb
|
246
|
+
- spec/integration/an_interactor_with_before_perform_callbacks_spec.rb
|
247
|
+
- spec/integration/an_organizer_with_options_callbacks_spec.rb
|
252
248
|
- spec/integration/an_interactor_with_around_perform_callbacks_spec.rb
|
249
|
+
- spec/integration/an_organizer_with_all_perform_callbacks.rb
|
250
|
+
- spec/integration/an_organizer_containing_organizer_with_after_callbacks_deferred_spec.rb
|
251
|
+
- spec/integration/an_interactor_with_after_rollback_callbacks_spec.rb
|
253
252
|
- spec/integration/active_record_integration_spec.rb
|
253
|
+
- spec/integration/an_interactor_with_around_rollback_callbacks_spec.rb
|
254
|
+
- spec/integration/an_interactor_with_after_context_validation_callbacks_spec.rb
|
255
|
+
- spec/integration/an_interactor_with_before_rollback_callbacks_spec.rb
|
256
|
+
- spec/integration/an_interactor_with_validations_on_called_spec.rb
|
254
257
|
- spec/integration/an_interactor_with_after_perform_callbacks_spec.rb
|
258
|
+
- spec/integration/an_organizer_with_conditionally_organized_interactors_spec.rb
|
259
|
+
- spec/integration/an_organizer_with_failing_nested_organizer_spec.rb
|
260
|
+
- spec/integration/a_failing_interactor_spec.rb
|
261
|
+
- spec/integration/an_organizer_with_after_each_callbacks_spec.rb
|
255
262
|
- spec/integration/a_basic_organizer_spec.rb
|
256
|
-
- spec/active_interactor_spec.rb
|
257
|
-
- spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb
|
258
|
-
- spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb
|
259
|
-
- spec/support/shared_examples/a_class_with_interactor_methods_example.rb
|
260
|
-
- spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb
|
261
|
-
- spec/support/shared_examples/a_class_that_extends_active_interactor_models_example.rb
|
262
|
-
- spec/support/spec_helpers.rb
|
263
|
-
- spec/support/coverage.rb
|
264
|
-
- spec/support/helpers/factories.rb
|
265
|
-
- spec/active_interactor/interactor/worker_spec.rb
|
266
|
-
- spec/active_interactor/interactor/perform/options_spec.rb
|
267
|
-
- spec/active_interactor/version_spec.rb
|
268
|
-
- spec/active_interactor/organizer/interactor_interface_spec.rb
|
269
263
|
- spec/active_interactor/organizer/interactor_interface_collection_spec.rb
|
270
264
|
- spec/active_interactor/organizer/base_spec.rb
|
265
|
+
- spec/active_interactor/organizer/interactor_interface_spec.rb
|
271
266
|
- spec/active_interactor/config_spec.rb
|
267
|
+
- spec/active_interactor/base_spec.rb
|
272
268
|
- spec/active_interactor/context/base_spec.rb
|
273
269
|
- spec/active_interactor/error_spec.rb
|
274
|
-
- spec/active_interactor/
|
270
|
+
- spec/active_interactor/interactor/worker_spec.rb
|
271
|
+
- spec/active_interactor/interactor/perform/options_spec.rb
|
272
|
+
- spec/active_interactor/version_spec.rb
|
273
|
+
- spec/support/helpers/factories.rb
|
274
|
+
- spec/support/spec_helpers.rb
|
275
|
+
- spec/support/shared_examples/a_class_that_extends_active_interactor_models_example.rb
|
276
|
+
- spec/support/shared_examples/a_class_with_interactor_context_methods_example.rb
|
277
|
+
- spec/support/shared_examples/a_class_with_interactor_callback_methods_example.rb
|
278
|
+
- spec/support/shared_examples/a_class_with_interactor_methods_example.rb
|
279
|
+
- spec/support/shared_examples/a_class_with_organizer_callback_methods_example.rb
|
280
|
+
- spec/support/coverage.rb
|
281
|
+
- spec/active_interactor_spec.rb
|
282
|
+
- spec/spec_helper.rb
|