ii_interactor 1.2.0 → 2.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/.github/workflows/ci.yml +17 -3
- data/.gitignore +1 -0
- data/CHANGELOG.md +15 -0
- data/README.md +53 -218
- data/bin/console +2 -2
- data/gemfiles/rails60.gemfile +1 -0
- data/gemfiles/rails70.gemfile +5 -0
- data/ii_interactor.gemspec +1 -0
- data/lib/ii_interactor/base.rb +5 -7
- data/lib/ii_interactor/callbacks.rb +19 -0
- data/lib/ii_interactor/coactors.rb +23 -0
- data/lib/ii_interactor/config.rb +1 -0
- data/lib/ii_interactor/context.rb +39 -12
- data/lib/ii_interactor/contextualizer.rb +28 -0
- data/lib/ii_interactor/core.rb +23 -17
- data/lib/ii_interactor/instrumentation.rb +5 -0
- data/lib/ii_interactor/log_subscriber.rb +9 -0
- data/lib/ii_interactor/version.rb +1 -1
- data/lib/ii_interactor.rb +1 -5
- metadata +20 -10
- data/lib/ii_interactor/interaction.rb +0 -43
- data/lib/ii_interactor/loader.rb +0 -19
- data/lib/ii_interactor/lookup.rb +0 -66
- data/lib/ii_interactor/lookups/base.rb +0 -20
- data/lib/ii_interactor/lookups/name.rb +0 -20
- data/lib/ii_interactor/lookups/object.rb +0 -40
- data/lib/ii_interactor/variables.rb +0 -72
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8d41caaf17018a5faf867b26ee15e97c68afbf3126e69ce4a81fc5c0b2394345
|
4
|
+
data.tar.gz: dbe6665d293c2f8c42030592ebdbe7671f57c7737ddd28f50c326539e2635536
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 90c35516d55b89a9e37d56b5b280df3840c96b378ae37cba70d46ad5d5aff694b1c66b2029871028ff72db71293490b232a6796e4e9575eaacbe5d1b353c27f0
|
7
|
+
data.tar.gz: f25a6c2e3923c06d7aac135059979108c207953f0034bea8039ed159b88a4ab8adcfbe3f4019ca6c3b5bcf77e7415bde97c11adabb310c64b3bed4621b8e8e04
|
data/.github/workflows/ci.yml
CHANGED
@@ -4,27 +4,41 @@ on: [push, pull_request]
|
|
4
4
|
|
5
5
|
jobs:
|
6
6
|
test:
|
7
|
-
runs-on: ubuntu-
|
7
|
+
runs-on: ubuntu-20.04
|
8
8
|
strategy:
|
9
9
|
fail-fast: false
|
10
10
|
matrix:
|
11
|
-
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, 3.0]
|
12
|
-
gemfile: ['rails50', 'rails51', 'rails52', 'rails60', 'rails61']
|
11
|
+
ruby: [2.3, 2.4, 2.5, 2.6, 2.7, '3.0', 3.1]
|
12
|
+
gemfile: ['rails50', 'rails51', 'rails52', 'rails60', 'rails61', 'rails70']
|
13
13
|
exclude:
|
14
14
|
- ruby: 2.3
|
15
15
|
gemfile: rails60
|
16
16
|
- ruby: 2.3
|
17
17
|
gemfile: rails61
|
18
|
+
- ruby: 2.3
|
19
|
+
gemfile: rails70
|
18
20
|
- ruby: 2.4
|
19
21
|
gemfile: rails60
|
20
22
|
- ruby: 2.4
|
21
23
|
gemfile: rails61
|
24
|
+
- ruby: 2.4
|
25
|
+
gemfile: rails70
|
26
|
+
- ruby: 2.5
|
27
|
+
gemfile: rails70
|
28
|
+
- ruby: 2.6
|
29
|
+
gemfile: rails70
|
22
30
|
- ruby: 3.0
|
23
31
|
gemfile: rails50
|
24
32
|
- ruby: 3.0
|
25
33
|
gemfile: rails51
|
26
34
|
- ruby: 3.0
|
27
35
|
gemfile: rails52
|
36
|
+
- ruby: 3.1
|
37
|
+
gemfile: rails50
|
38
|
+
- ruby: 3.1
|
39
|
+
gemfile: rails51
|
40
|
+
- ruby: 3.1
|
41
|
+
gemfile: rails52
|
28
42
|
|
29
43
|
name: ruby ${{ matrix.ruby }}, ${{ matrix.gemfile }}
|
30
44
|
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
# CHANGELOG
|
2
2
|
|
3
|
+
## 2.2.0
|
4
|
+
|
5
|
+
* Use coactive 0.3.
|
6
|
+
|
7
|
+
## 2.1.0
|
8
|
+
|
9
|
+
* Add traversal config.
|
10
|
+
* Add callbacks for `call_all`.
|
11
|
+
* Add calling instrumentation.
|
12
|
+
* Bump coactive version to 0.2.
|
13
|
+
|
14
|
+
## 2.0.0
|
15
|
+
|
16
|
+
* Replace interaction feature with coactive.
|
17
|
+
|
3
18
|
## 1.2.0
|
4
19
|
|
5
20
|
* Add variable setting feature.
|
data/README.md
CHANGED
@@ -27,6 +27,9 @@ Create interactor with `call` method and call it as follows:
|
|
27
27
|
|
28
28
|
```ruby
|
29
29
|
class Interactor < IIInteractor::Base
|
30
|
+
context_in :message
|
31
|
+
context_out :result
|
32
|
+
|
30
33
|
def call
|
31
34
|
@context.result = "called by #{@context.message}"
|
32
35
|
end
|
@@ -39,31 +42,13 @@ Interactor.call(message: 'something')
|
|
39
42
|
The first argument of `Interactor.call` is set to `@context`.
|
40
43
|
The return value of `Interactor.call` is the same as `@context`.
|
41
44
|
|
42
|
-
### Context variables
|
43
|
-
|
44
45
|
You can define context variables used in interactor explicitly.
|
45
|
-
|
46
|
+
`context_in` copies context to instance variables of interactor,
|
47
|
+
while `context_out` copies instance variables of interactor to context.
|
46
48
|
|
47
|
-
|
48
|
-
class Interactor < IIInteractor::Base
|
49
|
-
context_in :input
|
50
|
-
context_out :result
|
49
|
+
### Context options
|
51
50
|
|
52
|
-
|
53
|
-
puts @input
|
54
|
-
@result = 'result value'
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
puts Interactor.call(input: 'input').result
|
59
|
-
#=> input
|
60
|
-
# result value
|
61
|
-
```
|
62
|
-
|
63
|
-
`context_in` copies context into instance variables of interactor,
|
64
|
-
while `context_out` copies instance variables of interactor into context.
|
65
|
-
|
66
|
-
You can also define required context as follows:
|
51
|
+
You can define required context as follows:
|
67
52
|
|
68
53
|
```ruby
|
69
54
|
class Interactor < IIInteractor::Base
|
@@ -104,34 +89,9 @@ Interactor.call.result
|
|
104
89
|
#=> returned value
|
105
90
|
```
|
106
91
|
|
107
|
-
###
|
108
|
-
|
109
|
-
Following callbacks are available:
|
110
|
-
|
111
|
-
* `before_call`
|
112
|
-
* `around_call`
|
113
|
-
* `after_call`
|
114
|
-
|
115
|
-
For example:
|
116
|
-
|
117
|
-
```ruby
|
118
|
-
class Interactor < IIInteractor::Base
|
119
|
-
before_call do
|
120
|
-
@message = @context.message
|
121
|
-
end
|
122
|
-
|
123
|
-
def call
|
124
|
-
puts @message
|
125
|
-
end
|
126
|
-
end
|
127
|
-
|
128
|
-
Interactor.call(message: 'something')
|
129
|
-
#=> something
|
130
|
-
```
|
131
|
-
|
132
|
-
### Interactions
|
92
|
+
### Coactions
|
133
93
|
|
134
|
-
You can call other interactors in the same context using `
|
94
|
+
You can call other interactors in the same context using `coact`:
|
135
95
|
|
136
96
|
```ruby
|
137
97
|
class AInteractor < IIInteractor::Base
|
@@ -147,8 +107,8 @@ class BInteractor < IIInteractor::Base
|
|
147
107
|
end
|
148
108
|
|
149
109
|
class MainInteractor < IIInteractor::Base
|
150
|
-
|
151
|
-
|
110
|
+
coact AInteractor
|
111
|
+
coact BInteractor
|
152
112
|
end
|
153
113
|
|
154
114
|
MainInteractor.call
|
@@ -156,166 +116,7 @@ MainInteractor.call
|
|
156
116
|
# BInteractor
|
157
117
|
```
|
158
118
|
|
159
|
-
|
160
|
-
|
161
|
-
You can also define named interactions.
|
162
|
-
The interactors to be called are looked up from all interactors.
|
163
|
-
|
164
|
-
```ruby
|
165
|
-
class AInteractor < IIInteractor::Base
|
166
|
-
react :some_name
|
167
|
-
|
168
|
-
def call
|
169
|
-
puts self.class.name
|
170
|
-
end
|
171
|
-
end
|
172
|
-
|
173
|
-
class BInteractor < IIInteractor::Base
|
174
|
-
react :some_name
|
175
|
-
|
176
|
-
def call
|
177
|
-
puts self.class.name
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
class MainInteractor < IIInteractor::Base
|
182
|
-
interact :some_name
|
183
|
-
end
|
184
|
-
|
185
|
-
MainInteractor.call
|
186
|
-
#=> AInteractor
|
187
|
-
# BInteractor
|
188
|
-
```
|
189
|
-
|
190
|
-
Note followings:
|
191
|
-
|
192
|
-
* All files in `app/interactors` are loaded in development mode to lookup interactors having same name.
|
193
|
-
* The called interactors are unordered.
|
194
|
-
|
195
|
-
#### Object based interaction
|
196
|
-
|
197
|
-
You can also define object based interactions.
|
198
|
-
The interactors to be called are looked up from the namespace corresponding with caller interactor.
|
199
|
-
|
200
|
-
```ruby
|
201
|
-
class A
|
202
|
-
end
|
203
|
-
|
204
|
-
class B
|
205
|
-
end
|
206
|
-
|
207
|
-
class Main::AInteractor < IIInteractor::Base
|
208
|
-
def call
|
209
|
-
puts self.class.name
|
210
|
-
end
|
211
|
-
end
|
212
|
-
|
213
|
-
class Main::BInteractor < IIInteractor::Base
|
214
|
-
def call
|
215
|
-
puts self.class.name
|
216
|
-
end
|
217
|
-
end
|
218
|
-
|
219
|
-
class MainInteractor < IIInteractor::Base
|
220
|
-
interact A
|
221
|
-
interact B
|
222
|
-
end
|
223
|
-
|
224
|
-
MainInteractor.call
|
225
|
-
#=> Main::AInteractor
|
226
|
-
# Main::BInteractor
|
227
|
-
```
|
228
|
-
|
229
|
-
#### Custom interaction
|
230
|
-
|
231
|
-
You can also customize lookup of interactors as follows:
|
232
|
-
|
233
|
-
```ruby
|
234
|
-
class AInteractor < IIInteractor::Base
|
235
|
-
def call
|
236
|
-
puts self.class.name
|
237
|
-
end
|
238
|
-
end
|
239
|
-
|
240
|
-
class BInteractor < IIInteractor::Base
|
241
|
-
def call
|
242
|
-
puts self.class.name
|
243
|
-
end
|
244
|
-
end
|
245
|
-
|
246
|
-
class MainInteractor < IIInteractor::Base
|
247
|
-
# set block
|
248
|
-
interact do
|
249
|
-
if @context.condition == 'A'
|
250
|
-
AInteractor
|
251
|
-
else
|
252
|
-
BInteractor
|
253
|
-
end
|
254
|
-
end
|
255
|
-
|
256
|
-
# set method name
|
257
|
-
interact :conditional_interactors
|
258
|
-
|
259
|
-
def conditional_interactors
|
260
|
-
if @context.condition == 'A'
|
261
|
-
AInteractor
|
262
|
-
else
|
263
|
-
BInteractor
|
264
|
-
end
|
265
|
-
end
|
266
|
-
end
|
267
|
-
|
268
|
-
MainInteractor.call(condition: 'A')
|
269
|
-
#=> AInteractor
|
270
|
-
|
271
|
-
MainInteractor.call(condition: 'B')
|
272
|
-
#=> BInteractor
|
273
|
-
```
|
274
|
-
|
275
|
-
#### Nested interaction
|
276
|
-
|
277
|
-
You can define nested interactions as follows:
|
278
|
-
|
279
|
-
```ruby
|
280
|
-
class NestedAInteractor < IIInteractor::Base
|
281
|
-
def call
|
282
|
-
puts self.class.name
|
283
|
-
end
|
284
|
-
end
|
285
|
-
|
286
|
-
class NestedBInteractor < IIInteractor::Base
|
287
|
-
def call
|
288
|
-
puts self.class.name
|
289
|
-
end
|
290
|
-
end
|
291
|
-
|
292
|
-
class AInteractor < IIInteractor::Base
|
293
|
-
interact NestedAInteractor
|
294
|
-
|
295
|
-
def call
|
296
|
-
puts self.class.name
|
297
|
-
end
|
298
|
-
end
|
299
|
-
|
300
|
-
class BInteractor < IIInteractor::Base
|
301
|
-
interact NestedBInteractor
|
302
|
-
|
303
|
-
def call
|
304
|
-
puts self.class.name
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
|
-
class MainInteractor < IIInteractor::Base
|
309
|
-
interact AInteractor
|
310
|
-
interact BInteractor
|
311
|
-
end
|
312
|
-
|
313
|
-
MainInteractor.call
|
314
|
-
#=> NestedAInteractor
|
315
|
-
# AInteractor
|
316
|
-
# NestedBInteractor
|
317
|
-
# BInteractor
|
318
|
-
```
|
119
|
+
See [coactive](https://github.com/kanety/coactive) for more `coact` examples:
|
319
120
|
|
320
121
|
### Stop interactions
|
321
122
|
|
@@ -336,8 +137,8 @@ class BInteractor < IIInteractor::Base
|
|
336
137
|
end
|
337
138
|
|
338
139
|
class MainInteractor < IIInteractor::Base
|
339
|
-
|
340
|
-
|
140
|
+
coact AInteractor
|
141
|
+
coact BInteractor
|
341
142
|
end
|
342
143
|
|
343
144
|
context = MainInteractor.call
|
@@ -379,8 +180,8 @@ class BInteractor < IIInteractor::Base
|
|
379
180
|
end
|
380
181
|
|
381
182
|
class MainInteractor < IIInteractor::Base
|
382
|
-
|
383
|
-
|
183
|
+
coact AInteractor
|
184
|
+
coact BInteractor
|
384
185
|
end
|
385
186
|
|
386
187
|
context = MainInteractor.call
|
@@ -394,6 +195,38 @@ context.failure?
|
|
394
195
|
#=> true
|
395
196
|
```
|
396
197
|
|
198
|
+
### Callbacks
|
199
|
+
|
200
|
+
Following callbacks are available:
|
201
|
+
|
202
|
+
* `before_all`, `around_all`, `after_all`
|
203
|
+
* `before_call`, `around_call`, `after_call`
|
204
|
+
|
205
|
+
`*_all` wraps all coactors, and `*_call` wraps `call` method.
|
206
|
+
That is, `before_all` is called before running all coactors, and `before_call` is called before running `call` method.
|
207
|
+
For example:
|
208
|
+
|
209
|
+
```ruby
|
210
|
+
class Interactor < IIInteractor::Base
|
211
|
+
before_all do
|
212
|
+
puts "before_all"
|
213
|
+
end
|
214
|
+
|
215
|
+
before_call do
|
216
|
+
puts "before_call"
|
217
|
+
end
|
218
|
+
|
219
|
+
def call
|
220
|
+
puts @context.message
|
221
|
+
end
|
222
|
+
end
|
223
|
+
|
224
|
+
Interactor.call(message: 'something')
|
225
|
+
#=> before_all
|
226
|
+
# before_call
|
227
|
+
# something
|
228
|
+
```
|
229
|
+
|
397
230
|
### Pass a block
|
398
231
|
|
399
232
|
You can pass a block to `call` method of a interactor.
|
@@ -413,8 +246,8 @@ class BInteractor < IIInteractor::Base
|
|
413
246
|
end
|
414
247
|
|
415
248
|
class MainInteractor < IIInteractor::Base
|
416
|
-
|
417
|
-
|
249
|
+
coact AInteractor
|
250
|
+
coact BInteractor
|
418
251
|
end
|
419
252
|
|
420
253
|
MainInteractor.call do |interactor, message|
|
@@ -436,7 +269,9 @@ IIInteractor::LogSubscriber.attach_to :ii_interactor
|
|
436
269
|
This subscriber will write logs in debug mode as the following example:
|
437
270
|
|
438
271
|
```
|
439
|
-
|
272
|
+
Calling BasicInteractor with #<IIInteractor::Context ...>
|
273
|
+
...
|
274
|
+
Called BasicInteractor (Duration: 0.1ms, Allocations: 4)
|
440
275
|
```
|
441
276
|
|
442
277
|
## Contributing
|
data/bin/console
CHANGED
data/gemfiles/rails60.gemfile
CHANGED
data/ii_interactor.gemspec
CHANGED
data/lib/ii_interactor/base.rb
CHANGED
@@ -1,20 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
|
-
require_relative 'context'
|
4
3
|
require_relative 'core'
|
5
|
-
require_relative 'variables'
|
6
4
|
require_relative 'callbacks'
|
7
5
|
require_relative 'instrumentation'
|
8
|
-
require_relative '
|
9
|
-
require_relative '
|
6
|
+
require_relative 'context'
|
7
|
+
require_relative 'contextualizer'
|
8
|
+
require_relative 'coactors'
|
10
9
|
|
11
10
|
module IIInteractor
|
12
11
|
class Base
|
13
12
|
include Core
|
14
13
|
include Callbacks
|
15
14
|
include Instrumentation
|
16
|
-
include
|
17
|
-
include
|
18
|
-
include Lookup
|
15
|
+
include Contextualizer
|
16
|
+
include Coactors
|
19
17
|
end
|
20
18
|
end
|
@@ -6,9 +6,16 @@ module IIInteractor
|
|
6
6
|
include ActiveSupport::Callbacks
|
7
7
|
|
8
8
|
included do
|
9
|
+
define_callbacks :all
|
9
10
|
define_callbacks :call
|
10
11
|
end
|
11
12
|
|
13
|
+
def call_all
|
14
|
+
run_callbacks :all do
|
15
|
+
super
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
12
19
|
def call_self
|
13
20
|
run_callbacks :call do
|
14
21
|
super
|
@@ -16,6 +23,18 @@ module IIInteractor
|
|
16
23
|
end
|
17
24
|
|
18
25
|
class_methods do
|
26
|
+
def before_all(*args, &block)
|
27
|
+
set_callback(:all, :before, *args, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
def after_all(*args, &block)
|
31
|
+
set_callback(:all, :after, *args, &block)
|
32
|
+
end
|
33
|
+
|
34
|
+
def around_all(*args, &block)
|
35
|
+
set_callback(:all, :around, *args, &block)
|
36
|
+
end
|
37
|
+
|
19
38
|
def before_call(*args, &block)
|
20
39
|
set_callback(:call, :before, *args, &block)
|
21
40
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IIInteractor
|
4
|
+
module Coactors
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
include Coactive::Base
|
9
|
+
|
10
|
+
configure_coactive do |config|
|
11
|
+
config.load_paths = ['app/interactors']
|
12
|
+
config.class_suffix = 'Interactor'
|
13
|
+
config.use_cache = true
|
14
|
+
config.lookup_superclass_until = ['ActiveRecord::Base', 'ActiveModel::Base']
|
15
|
+
end
|
16
|
+
|
17
|
+
class << self
|
18
|
+
alias_method :interact, :coact
|
19
|
+
alias_method :react, :coaction
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/lib/ii_interactor/config.rb
CHANGED
@@ -1,13 +1,34 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module IIInteractor
|
4
|
-
class Context <
|
5
|
-
|
4
|
+
class Context < Coactive::Context
|
5
|
+
class Status < Struct.new(:failed, :stopped, :called)
|
6
|
+
def initialize(*)
|
7
|
+
self.failed = false
|
8
|
+
self.stopped = false
|
9
|
+
self.called = []
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :_status, :_block
|
14
|
+
|
15
|
+
def initialize(data = {}, &block)
|
16
|
+
if data.is_a?(IIInteractor::Context)
|
17
|
+
@_block = data._block
|
18
|
+
@_status = data._status
|
19
|
+
else
|
20
|
+
@_block = block
|
21
|
+
@_status = Status.new
|
22
|
+
end
|
6
23
|
super
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
"#<#{self.class} #{self.class.inspect(@_data)} (#{self.class.inspect(@_status.to_h)})>"
|
28
|
+
end
|
29
|
+
|
30
|
+
def call_block!(*args)
|
31
|
+
@_block.call(*args) if @_block
|
11
32
|
end
|
12
33
|
|
13
34
|
def success?
|
@@ -15,21 +36,27 @@ module IIInteractor
|
|
15
36
|
end
|
16
37
|
|
17
38
|
def failure?
|
18
|
-
|
39
|
+
@_status.failed == true
|
19
40
|
end
|
20
41
|
|
21
42
|
def stopped?
|
22
|
-
|
43
|
+
@_status.stopped == true
|
23
44
|
end
|
24
45
|
|
25
46
|
def fail!(data = {})
|
26
|
-
|
27
|
-
data.each { |k, v|
|
47
|
+
@_status.failed = true
|
48
|
+
data.each { |k, v| @_data[k] = v }
|
49
|
+
define_accessors!(data.keys)
|
28
50
|
end
|
29
51
|
|
30
52
|
def stop!(data = {})
|
31
|
-
|
32
|
-
data.each { |k, v|
|
53
|
+
@_status.stopped = true
|
54
|
+
data.each { |k, v| @_data[k] = v }
|
55
|
+
define_accessors!(data.keys)
|
56
|
+
end
|
57
|
+
|
58
|
+
def called!(interactor)
|
59
|
+
@_status.called << interactor
|
33
60
|
end
|
34
61
|
end
|
35
62
|
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IIInteractor
|
4
|
+
module Contextualizer
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
include Coactive::Contextualizer
|
7
|
+
|
8
|
+
def call_self
|
9
|
+
contextualize do
|
10
|
+
super
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class_methods do
|
15
|
+
def context_in(*names, **options)
|
16
|
+
context(*names, **options)
|
17
|
+
end
|
18
|
+
|
19
|
+
def context_out(*names, **options)
|
20
|
+
options[:output] = true
|
21
|
+
if options.delete(:from_return)
|
22
|
+
options[:output] = :return
|
23
|
+
end
|
24
|
+
context(*names, **options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
data/lib/ii_interactor/core.rb
CHANGED
@@ -3,26 +3,32 @@
|
|
3
3
|
module IIInteractor
|
4
4
|
module Core
|
5
5
|
extend ActiveSupport::Concern
|
6
|
+
include Coactive::Initializer
|
6
7
|
|
7
8
|
included do
|
8
|
-
|
9
|
+
self.context_class = IIInteractor::Context
|
9
10
|
end
|
10
11
|
|
11
|
-
def initialize(
|
12
|
-
|
13
|
-
context
|
14
|
-
else
|
15
|
-
IIInteractor::Context.new(context, &block)
|
16
|
-
end
|
12
|
+
def initialize(*)
|
13
|
+
super
|
17
14
|
end
|
18
15
|
|
19
16
|
def call_all
|
20
|
-
planned =
|
21
|
-
|
22
|
-
|
23
|
-
|
17
|
+
planned = case IIInteractor.config.traversal
|
18
|
+
when :preorder
|
19
|
+
[self] + coactors
|
20
|
+
when :postorder
|
21
|
+
coactors + [self]
|
22
|
+
when :inorder
|
23
|
+
planned = coactors.in_groups(2, false)
|
24
|
+
planned[0] + [self] + planned[1]
|
25
|
+
end
|
26
|
+
|
27
|
+
planned.each do |interactor|
|
28
|
+
if interactor == self
|
29
|
+
call_self
|
24
30
|
else
|
25
|
-
interactor.call_all
|
31
|
+
interactor.new(@context).call_all
|
26
32
|
end
|
27
33
|
break if @context.stopped?
|
28
34
|
end
|
@@ -30,7 +36,7 @@ module IIInteractor
|
|
30
36
|
|
31
37
|
def call_self
|
32
38
|
call.tap do
|
33
|
-
@context.
|
39
|
+
@context.called!(self)
|
34
40
|
end
|
35
41
|
end
|
36
42
|
|
@@ -41,7 +47,7 @@ module IIInteractor
|
|
41
47
|
end
|
42
48
|
|
43
49
|
def inform(*args)
|
44
|
-
@context.
|
50
|
+
@context.call_block!(*([self] + args))
|
45
51
|
end
|
46
52
|
|
47
53
|
def fail!(data = {})
|
@@ -54,12 +60,12 @@ module IIInteractor
|
|
54
60
|
end
|
55
61
|
|
56
62
|
class_methods do
|
57
|
-
def call(
|
58
|
-
interactor = new(
|
63
|
+
def call(args = {}, &block)
|
64
|
+
interactor = new(args, &block)
|
59
65
|
interactor.call_all
|
60
66
|
interactor.context
|
61
67
|
rescue UnprogressableError
|
62
|
-
interactor.context.
|
68
|
+
interactor.context._status.called.reverse.each do |called|
|
63
69
|
called.rollback
|
64
70
|
end
|
65
71
|
interactor.context
|
@@ -4,6 +4,11 @@ module IIInteractor
|
|
4
4
|
module Instrumentation
|
5
5
|
extend ActiveSupport::Concern
|
6
6
|
|
7
|
+
def call_all
|
8
|
+
ActiveSupport::Notifications.instrument 'calling.ii_interactor', interactor: self
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
7
12
|
def call_self
|
8
13
|
ActiveSupport::Notifications.instrument 'call.ii_interactor', interactor: self do
|
9
14
|
super
|
@@ -2,6 +2,13 @@
|
|
2
2
|
|
3
3
|
module IIInteractor
|
4
4
|
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
|
+
def calling(event)
|
6
|
+
debug do
|
7
|
+
interactor = event.payload[:interactor]
|
8
|
+
"Calling #{interactor.class} with #{interactor.context}"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
5
12
|
def call(event)
|
6
13
|
debug do
|
7
14
|
interactor = event.payload[:interactor]
|
@@ -9,6 +16,8 @@ module IIInteractor
|
|
9
16
|
end
|
10
17
|
end
|
11
18
|
|
19
|
+
private
|
20
|
+
|
12
21
|
def additional_log(event)
|
13
22
|
additions = ["Duration: %.1fms" % event.duration]
|
14
23
|
additions << "Allocations: %d" % event.allocations if event.respond_to?(:allocations)
|
data/lib/ii_interactor.rb
CHANGED
@@ -1,10 +1,10 @@
|
|
1
1
|
require 'active_support'
|
2
|
+
require 'coactive'
|
2
3
|
|
3
4
|
require 'ii_interactor/version'
|
4
5
|
require 'ii_interactor/errors'
|
5
6
|
require 'ii_interactor/config'
|
6
7
|
require 'ii_interactor/base'
|
7
|
-
require 'ii_interactor/loader'
|
8
8
|
require 'ii_interactor/log_subscriber'
|
9
9
|
|
10
10
|
module IIInteractor
|
@@ -16,9 +16,5 @@ module IIInteractor
|
|
16
16
|
def config
|
17
17
|
Config
|
18
18
|
end
|
19
|
-
|
20
|
-
def load
|
21
|
-
Loader.call
|
22
|
-
end
|
23
19
|
end
|
24
20
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: ii_interactor
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 2.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yoshikazu Kaneta
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-05-09 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '5.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: coactive
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.3'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.3'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rails
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -116,23 +130,19 @@ files:
|
|
116
130
|
- gemfiles/rails52.gemfile
|
117
131
|
- gemfiles/rails60.gemfile
|
118
132
|
- gemfiles/rails61.gemfile
|
133
|
+
- gemfiles/rails70.gemfile
|
119
134
|
- ii_interactor.gemspec
|
120
135
|
- lib/ii_interactor.rb
|
121
136
|
- lib/ii_interactor/base.rb
|
122
137
|
- lib/ii_interactor/callbacks.rb
|
138
|
+
- lib/ii_interactor/coactors.rb
|
123
139
|
- lib/ii_interactor/config.rb
|
124
140
|
- lib/ii_interactor/context.rb
|
141
|
+
- lib/ii_interactor/contextualizer.rb
|
125
142
|
- lib/ii_interactor/core.rb
|
126
143
|
- lib/ii_interactor/errors.rb
|
127
144
|
- lib/ii_interactor/instrumentation.rb
|
128
|
-
- lib/ii_interactor/interaction.rb
|
129
|
-
- lib/ii_interactor/loader.rb
|
130
145
|
- lib/ii_interactor/log_subscriber.rb
|
131
|
-
- lib/ii_interactor/lookup.rb
|
132
|
-
- lib/ii_interactor/lookups/base.rb
|
133
|
-
- lib/ii_interactor/lookups/name.rb
|
134
|
-
- lib/ii_interactor/lookups/object.rb
|
135
|
-
- lib/ii_interactor/variables.rb
|
136
146
|
- lib/ii_interactor/version.rb
|
137
147
|
homepage: https://github.com/kanety/ii_interactor
|
138
148
|
licenses: []
|
@@ -152,7 +162,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
152
162
|
- !ruby/object:Gem::Version
|
153
163
|
version: '0'
|
154
164
|
requirements: []
|
155
|
-
rubygems_version: 3.
|
165
|
+
rubygems_version: 3.3.3
|
156
166
|
signing_key:
|
157
167
|
specification_version: 4
|
158
168
|
summary: A base interactor to support management of bussiness logic
|
@@ -1,43 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IIInteractor
|
4
|
-
module Interaction
|
5
|
-
extend ActiveSupport::Concern
|
6
|
-
|
7
|
-
included do
|
8
|
-
class_attribute :_interactions
|
9
|
-
self._interactions = []
|
10
|
-
class_attribute :_reactions
|
11
|
-
self._reactions = []
|
12
|
-
end
|
13
|
-
|
14
|
-
class_methods do
|
15
|
-
def interact(*interactors, **options, &block)
|
16
|
-
if block
|
17
|
-
self._interactions = _interactions + [block]
|
18
|
-
elsif options[:before]
|
19
|
-
index = self._interactions.index { |interaction| interaction == options[:before] }
|
20
|
-
self._interactions = self._interactions.insert(index, *interactors)
|
21
|
-
else
|
22
|
-
self._interactions = _interactions + interactors
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
def interactions
|
27
|
-
self._interactions
|
28
|
-
end
|
29
|
-
|
30
|
-
def clear_interactions
|
31
|
-
self._interactions = []
|
32
|
-
end
|
33
|
-
|
34
|
-
def react(*reactions)
|
35
|
-
self._reactions = _reactions + reactions
|
36
|
-
end
|
37
|
-
|
38
|
-
def reactions
|
39
|
-
self._reactions
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
data/lib/ii_interactor/loader.rb
DELETED
@@ -1,19 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IIInteractor
|
4
|
-
module Loader
|
5
|
-
class << self
|
6
|
-
def call
|
7
|
-
return unless defined?(Rails)
|
8
|
-
return if Rails.application.config.eager_load
|
9
|
-
|
10
|
-
engines = [Rails] + Rails::Engine.subclasses.map(&:instance)
|
11
|
-
engines.each do |engine|
|
12
|
-
Dir["#{engine.root}/app/interactors/**/*.rb"].each do |file|
|
13
|
-
require file
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
data/lib/ii_interactor/lookup.rb
DELETED
@@ -1,66 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative 'lookups/base'
|
4
|
-
require_relative 'lookups/name'
|
5
|
-
require_relative 'lookups/object'
|
6
|
-
|
7
|
-
module IIInteractor
|
8
|
-
module Lookup
|
9
|
-
extend ActiveSupport::Concern
|
10
|
-
|
11
|
-
def lookup_all
|
12
|
-
lookup.map { |interactor| [interactor] + interactor.new(@context).lookup_all }.flatten
|
13
|
-
end
|
14
|
-
|
15
|
-
def lookup
|
16
|
-
self.class._interactions.map do |interaction|
|
17
|
-
if interaction.is_a?(Symbol) && respond_to?(interaction, true)
|
18
|
-
send(interaction)
|
19
|
-
elsif interaction.is_a?(Proc)
|
20
|
-
instance_exec(&interaction)
|
21
|
-
else
|
22
|
-
interaction
|
23
|
-
end
|
24
|
-
end.flatten.compact.map do |interaction|
|
25
|
-
if interaction.is_a?(Class) && interaction < IIInteractor::Base
|
26
|
-
interaction
|
27
|
-
else
|
28
|
-
self.class.lookup(interaction)
|
29
|
-
end
|
30
|
-
end.flatten.compact
|
31
|
-
end
|
32
|
-
|
33
|
-
class_methods do
|
34
|
-
def lookup(*interactions)
|
35
|
-
interactions = _interactions unless interactions
|
36
|
-
interactions.map { |interaction| Lookup.call(self, interaction) }.flatten
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
class << self
|
41
|
-
class_attribute :lookups
|
42
|
-
self.lookups = [Lookups::Name, Lookups::Object]
|
43
|
-
|
44
|
-
class_attribute :cache
|
45
|
-
self.cache = {}
|
46
|
-
|
47
|
-
def call(klass, interaction)
|
48
|
-
with_cache(klass, interaction) do
|
49
|
-
lookup = lookups.detect { |lookup| lookup.call?(interaction) }
|
50
|
-
lookup.new(klass, interaction).call if lookup
|
51
|
-
end
|
52
|
-
end
|
53
|
-
|
54
|
-
private
|
55
|
-
|
56
|
-
def with_cache(klass, interaction)
|
57
|
-
if Config.lookup_cache
|
58
|
-
self.cache[klass] ||= {}
|
59
|
-
self.cache[klass][interaction] ||= yield
|
60
|
-
else
|
61
|
-
yield
|
62
|
-
end
|
63
|
-
end
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IIInteractor
|
4
|
-
module Lookups
|
5
|
-
class Base
|
6
|
-
def initialize(klass, interaction)
|
7
|
-
@klass = klass
|
8
|
-
@interaction = interaction
|
9
|
-
end
|
10
|
-
|
11
|
-
def call
|
12
|
-
end
|
13
|
-
|
14
|
-
class << self
|
15
|
-
def call?(interaction)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,20 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IIInteractor
|
4
|
-
module Lookups
|
5
|
-
class Name < Base
|
6
|
-
def call
|
7
|
-
IIInteractor.load
|
8
|
-
IIInteractor::Base.descendants.select do |interactor|
|
9
|
-
interactor._reactions.any? { |reaction| reaction == @interaction }
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
class << self
|
14
|
-
def call?(interaction)
|
15
|
-
interaction.is_a?(Symbol)
|
16
|
-
end
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IIInteractor
|
4
|
-
module Lookups
|
5
|
-
class Object < Base
|
6
|
-
def call
|
7
|
-
return if terminate?
|
8
|
-
|
9
|
-
if @interaction.name.present? && (interactor = resolve)
|
10
|
-
interactor
|
11
|
-
elsif @interaction.superclass
|
12
|
-
self.class.new(@klass, @interaction.superclass).call
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
private
|
17
|
-
|
18
|
-
def terminate?
|
19
|
-
@interaction.name.to_s.in?(['Object', 'ActiveRecord::Base', 'ActiveModel::Base'])
|
20
|
-
end
|
21
|
-
|
22
|
-
def resolve
|
23
|
-
name = resolve_name
|
24
|
-
interactor = name.safe_constantize
|
25
|
-
return interactor if interactor && name == interactor.name
|
26
|
-
end
|
27
|
-
|
28
|
-
def resolve_name
|
29
|
-
namespace = @klass.name.to_s.sub(/Interactor$/, '').to_s
|
30
|
-
[namespace, "#{@interaction.name}Interactor"].join('::')
|
31
|
-
end
|
32
|
-
|
33
|
-
class << self
|
34
|
-
def call?(interaction)
|
35
|
-
interaction.is_a?(Module)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module IIInteractor
|
4
|
-
class Variable < Struct.new(:name, :options)
|
5
|
-
def default
|
6
|
-
options[:default] if options
|
7
|
-
end
|
8
|
-
|
9
|
-
def required?
|
10
|
-
options[:required] if options
|
11
|
-
end
|
12
|
-
|
13
|
-
def from_return?
|
14
|
-
options[:from_return] if options
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
module Variables
|
19
|
-
extend ActiveSupport::Concern
|
20
|
-
|
21
|
-
def call_self
|
22
|
-
(self.class.context_ins + self.class.context_outs).each do |var|
|
23
|
-
if var.required? && !@context.respond_to?(var.name)
|
24
|
-
raise RequiredContextError.new("missing required context: #{var.name}")
|
25
|
-
end
|
26
|
-
if var.default && !@context.respond_to?(var.name)
|
27
|
-
@context[var.name] = Variables.resolve(self, var.default)
|
28
|
-
end
|
29
|
-
instance_variable_set("@#{var.name}", @context[var.name])
|
30
|
-
end
|
31
|
-
|
32
|
-
super.tap do |return_value|
|
33
|
-
self.class.context_outs.each do |var|
|
34
|
-
@context[var.name] =
|
35
|
-
if var.from_return?
|
36
|
-
return_value
|
37
|
-
else
|
38
|
-
instance_variable_get("@#{var.name}")
|
39
|
-
end
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class << self
|
45
|
-
def resolve(interactor, value)
|
46
|
-
if value.respond_to?(:call)
|
47
|
-
interactor.instance_exec(&value)
|
48
|
-
elsif value.is_a?(Symbol) && interactor.respond_to?(value, true)
|
49
|
-
interactor.send(value)
|
50
|
-
else
|
51
|
-
value.deep_dup
|
52
|
-
end
|
53
|
-
end
|
54
|
-
end
|
55
|
-
|
56
|
-
included do
|
57
|
-
class_attribute :context_ins, :context_outs
|
58
|
-
self.context_ins = []
|
59
|
-
self.context_outs = []
|
60
|
-
end
|
61
|
-
|
62
|
-
class_methods do
|
63
|
-
def context_in(*names, **options)
|
64
|
-
self.context_ins = self.context_ins + names.map { |name| Variable.new(name, options) }
|
65
|
-
end
|
66
|
-
|
67
|
-
def context_out(*names, **options)
|
68
|
-
self.context_outs = self.context_outs + names.map { |name| Variable.new(name, options) }
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|