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