ii_interactor 1.0.0 → 2.0.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 +1 -1
- data/CHANGELOG.md +21 -0
- data/README.md +71 -150
- data/ii_interactor.gemspec +1 -0
- data/lib/ii_interactor/base.rb +8 -66
- data/lib/ii_interactor/callbacks.rb +6 -0
- data/lib/ii_interactor/coactors.rb +23 -0
- data/lib/ii_interactor/context.rb +0 -1
- data/lib/ii_interactor/core.rb +69 -0
- data/lib/ii_interactor/errors.rb +3 -0
- data/lib/ii_interactor/instrumentation.rb +13 -0
- data/lib/ii_interactor/log_subscriber.rb +18 -0
- data/lib/ii_interactor/variables.rb +72 -0
- data/lib/ii_interactor/version.rb +1 -1
- data/lib/ii_interactor.rb +2 -5
- metadata +23 -9
- 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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a2fdfb2e93eb53ee2b70845fb78c285aae26c237681537ae59893675873974f1
|
4
|
+
data.tar.gz: b85095ca4396ccc3523fbe6f212ed335f057a77dc60e87b0969c14666a5e0d0f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2b1321aee1be7d0c362315ef1020db0113d77445366617de0e0f9ff010c49d1118f7a26f5182102065efa60eb832616ded910f1e3bd222fc897d5fcaa0947236
|
7
|
+
data.tar.gz: a0d731eb5334b3846530e60858146c9b1f748d01b313917ee7e50153ab5f22f9fdb8a2cc53c24d08459ff7f074ee203579752c4d778bfad618e269c3361e318f
|
data/.github/workflows/ci.yml
CHANGED
data/CHANGELOG.md
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# CHANGELOG
|
2
|
+
|
3
|
+
## 2.0.0
|
4
|
+
|
5
|
+
* Replace interaction feature with coactive.
|
6
|
+
|
7
|
+
## 1.2.0
|
8
|
+
|
9
|
+
* Add variable setting feature.
|
10
|
+
|
11
|
+
## 1.1.1
|
12
|
+
|
13
|
+
* Check `config.eager_load` instead of `Rails.env` before file loading.
|
14
|
+
|
15
|
+
## 1.1.0
|
16
|
+
|
17
|
+
* Add log subscriber.
|
18
|
+
|
19
|
+
## 1.0.0
|
20
|
+
|
21
|
+
* First release.
|
data/README.md
CHANGED
@@ -36,222 +36,128 @@ Interactor.call(message: 'something')
|
|
36
36
|
#=> #<IIInteractor::Context message="something", result="called by something">
|
37
37
|
```
|
38
38
|
|
39
|
-
The first argument of `call` is set to `@context`.
|
40
|
-
The return value of `call` is the same as `@context`.
|
39
|
+
The first argument of `Interactor.call` is set to `@context`.
|
40
|
+
The return value of `Interactor.call` is the same as `@context`.
|
41
41
|
|
42
|
-
###
|
43
|
-
|
44
|
-
Following callbacks are available:
|
45
|
-
|
46
|
-
* `before_call`
|
47
|
-
* `around_call`
|
48
|
-
* `after_call`
|
42
|
+
### Context variables
|
49
43
|
|
44
|
+
You can define context variables used in interactor explicitly.
|
50
45
|
For example:
|
51
46
|
|
52
47
|
```ruby
|
53
48
|
class Interactor < IIInteractor::Base
|
54
|
-
|
55
|
-
|
56
|
-
end
|
49
|
+
context_in :input
|
50
|
+
context_out :result
|
57
51
|
|
58
52
|
def call
|
59
|
-
puts @
|
53
|
+
puts @input
|
54
|
+
@result = 'result value'
|
60
55
|
end
|
61
56
|
end
|
62
57
|
|
63
|
-
Interactor.call(
|
64
|
-
#=>
|
58
|
+
puts Interactor.call(input: 'input').result
|
59
|
+
#=> input
|
60
|
+
# result value
|
65
61
|
```
|
66
62
|
|
67
|
-
|
63
|
+
`context_in` copies context into instance variables of interactor,
|
64
|
+
while `context_out` copies instance variables of interactor into context.
|
68
65
|
|
69
|
-
You can
|
66
|
+
You can also define required context as follows:
|
70
67
|
|
71
68
|
```ruby
|
72
|
-
class
|
73
|
-
|
74
|
-
puts self.class.name
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class BInteractor < IIInteractor::Base
|
79
|
-
def call
|
80
|
-
puts self.class.name
|
81
|
-
end
|
82
|
-
end
|
83
|
-
|
84
|
-
class MainInteractor < IIInteractor::Base
|
85
|
-
interact AInteractor
|
86
|
-
interact BInteractor
|
69
|
+
class Interactor < IIInteractor::Base
|
70
|
+
context_in :input, required: true
|
87
71
|
end
|
88
72
|
|
89
|
-
|
90
|
-
#=>
|
91
|
-
# BInteractor
|
73
|
+
Interactor.call
|
74
|
+
#=> IIInteractor::RequiredContextError (missing required context: input2)
|
92
75
|
```
|
93
76
|
|
94
|
-
|
95
|
-
|
96
|
-
You can also define named interactions.
|
97
|
-
The interactors to be called are looked up from all interactors.
|
77
|
+
You can also define default value as follows:
|
98
78
|
|
99
79
|
```ruby
|
100
|
-
class
|
101
|
-
|
102
|
-
|
103
|
-
def call
|
104
|
-
puts self.class.name
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
class BInteractor < IIInteractor::Base
|
109
|
-
react :some_name
|
80
|
+
class Interactor < IIInteractor::Base
|
81
|
+
context_in :input, default: 'input'
|
110
82
|
|
111
83
|
def call
|
112
|
-
puts
|
84
|
+
puts @input
|
113
85
|
end
|
114
86
|
end
|
115
87
|
|
116
|
-
|
117
|
-
|
118
|
-
end
|
119
|
-
|
120
|
-
MainInteractor.call
|
121
|
-
#=> AInteractor
|
122
|
-
# BInteractor
|
88
|
+
Interactor.call
|
89
|
+
#=> input
|
123
90
|
```
|
124
91
|
|
125
|
-
|
126
|
-
|
127
|
-
* All files in `app/interactors` are loaded in development mode to lookup interactors having same name.
|
128
|
-
* The called interactors are unordered.
|
129
|
-
|
130
|
-
#### Object based interaction
|
131
|
-
|
132
|
-
You can also define object based interactions.
|
133
|
-
The interactors to be called are looked up from the namespace corresponding with caller interactor.
|
92
|
+
You can also set context from return value of `call` method:
|
134
93
|
|
135
94
|
```ruby
|
136
|
-
class
|
137
|
-
|
138
|
-
|
139
|
-
class B
|
140
|
-
end
|
95
|
+
class Interactor < IIInteractor::Base
|
96
|
+
context_out :result, from_return: true
|
141
97
|
|
142
|
-
class Main::AInteractor < IIInteractor::Base
|
143
98
|
def call
|
144
|
-
|
99
|
+
'returned value'
|
145
100
|
end
|
146
101
|
end
|
147
102
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
end
|
152
|
-
end
|
103
|
+
Interactor.call.result
|
104
|
+
#=> returned value
|
105
|
+
```
|
153
106
|
|
154
|
-
|
155
|
-
interact A
|
156
|
-
interact B
|
157
|
-
end
|
107
|
+
### Callbacks
|
158
108
|
|
159
|
-
|
160
|
-
#=> Main::AInteractor
|
161
|
-
# Main::BInteractor
|
162
|
-
```
|
109
|
+
Following callbacks are available:
|
163
110
|
|
164
|
-
|
111
|
+
* `before_call`
|
112
|
+
* `around_call`
|
113
|
+
* `after_call`
|
165
114
|
|
166
|
-
|
115
|
+
For example:
|
167
116
|
|
168
117
|
```ruby
|
169
|
-
class
|
170
|
-
|
171
|
-
|
118
|
+
class Interactor < IIInteractor::Base
|
119
|
+
before_call do
|
120
|
+
@message = @context.message
|
172
121
|
end
|
173
|
-
end
|
174
122
|
|
175
|
-
class BInteractor < IIInteractor::Base
|
176
123
|
def call
|
177
|
-
puts
|
178
|
-
end
|
179
|
-
end
|
180
|
-
|
181
|
-
class MainInteractor < IIInteractor::Base
|
182
|
-
# set block
|
183
|
-
interact do
|
184
|
-
if @context.condition == 'A'
|
185
|
-
AInteractor
|
186
|
-
else
|
187
|
-
BInteractor
|
188
|
-
end
|
189
|
-
end
|
190
|
-
|
191
|
-
# set method name
|
192
|
-
interact :conditional_interactors
|
193
|
-
|
194
|
-
def conditional_interactors
|
195
|
-
if @context.condition == 'A'
|
196
|
-
AInteractor
|
197
|
-
else
|
198
|
-
BInteractor
|
199
|
-
end
|
124
|
+
puts @message
|
200
125
|
end
|
201
126
|
end
|
202
127
|
|
203
|
-
|
204
|
-
#=>
|
205
|
-
|
206
|
-
MainInteractor.call(condition: 'B')
|
207
|
-
#=> BInteractor
|
128
|
+
Interactor.call(message: 'something')
|
129
|
+
#=> something
|
208
130
|
```
|
209
131
|
|
210
|
-
|
132
|
+
### Coactions
|
211
133
|
|
212
|
-
You can
|
134
|
+
You can call other interactors in the same context using `coact`:
|
213
135
|
|
214
136
|
```ruby
|
215
|
-
class NestedAInteractor < IIInteractor::Base
|
216
|
-
def call
|
217
|
-
puts self.class.name
|
218
|
-
end
|
219
|
-
end
|
220
|
-
|
221
|
-
class NestedBInteractor < IIInteractor::Base
|
222
|
-
def call
|
223
|
-
puts self.class.name
|
224
|
-
end
|
225
|
-
end
|
226
|
-
|
227
137
|
class AInteractor < IIInteractor::Base
|
228
|
-
interact NestedAInteractor
|
229
|
-
|
230
138
|
def call
|
231
139
|
puts self.class.name
|
232
140
|
end
|
233
141
|
end
|
234
142
|
|
235
143
|
class BInteractor < IIInteractor::Base
|
236
|
-
interact NestedBInteractor
|
237
|
-
|
238
144
|
def call
|
239
145
|
puts self.class.name
|
240
146
|
end
|
241
147
|
end
|
242
148
|
|
243
149
|
class MainInteractor < IIInteractor::Base
|
244
|
-
|
245
|
-
|
150
|
+
coact AInteractor
|
151
|
+
coact BInteractor
|
246
152
|
end
|
247
153
|
|
248
154
|
MainInteractor.call
|
249
|
-
#=>
|
250
|
-
# AInteractor
|
251
|
-
# NestedBInteractor
|
155
|
+
#=> AInteractor
|
252
156
|
# BInteractor
|
253
157
|
```
|
254
158
|
|
159
|
+
See [coactive](https://github.com/kanety/coactive) for more `coact` examples:
|
160
|
+
|
255
161
|
### Stop interactions
|
256
162
|
|
257
163
|
You can stop interactions as follows:
|
@@ -271,8 +177,8 @@ class BInteractor < IIInteractor::Base
|
|
271
177
|
end
|
272
178
|
|
273
179
|
class MainInteractor < IIInteractor::Base
|
274
|
-
|
275
|
-
|
180
|
+
coact AInteractor
|
181
|
+
coact BInteractor
|
276
182
|
end
|
277
183
|
|
278
184
|
context = MainInteractor.call
|
@@ -314,8 +220,8 @@ class BInteractor < IIInteractor::Base
|
|
314
220
|
end
|
315
221
|
|
316
222
|
class MainInteractor < IIInteractor::Base
|
317
|
-
|
318
|
-
|
223
|
+
coact AInteractor
|
224
|
+
coact BInteractor
|
319
225
|
end
|
320
226
|
|
321
227
|
context = MainInteractor.call
|
@@ -348,8 +254,8 @@ class BInteractor < IIInteractor::Base
|
|
348
254
|
end
|
349
255
|
|
350
256
|
class MainInteractor < IIInteractor::Base
|
351
|
-
|
352
|
-
|
257
|
+
coact AInteractor
|
258
|
+
coact BInteractor
|
353
259
|
end
|
354
260
|
|
355
261
|
MainInteractor.call do |interactor, message|
|
@@ -359,6 +265,21 @@ end
|
|
359
265
|
# BInteractor: called B
|
360
266
|
```
|
361
267
|
|
268
|
+
### Logging
|
269
|
+
|
270
|
+
Interactor supports instrumentation hook supplied by `ActiveSupport::Notifications`.
|
271
|
+
You can enable log subscriber as follows:
|
272
|
+
|
273
|
+
```ruby
|
274
|
+
IIInteractor::LogSubscriber.attach_to :ii_interactor
|
275
|
+
```
|
276
|
+
|
277
|
+
This subscriber will write logs in debug mode as the following example:
|
278
|
+
|
279
|
+
```
|
280
|
+
Called SimpleInteractor (Duration: 0.3ms, Allocations: 42)
|
281
|
+
```
|
282
|
+
|
362
283
|
## Contributing
|
363
284
|
|
364
285
|
Bug reports and pull requests are welcome at https://github.com/kanety/ii_interactor.
|
data/ii_interactor.gemspec
CHANGED
data/lib/ii_interactor/base.rb
CHANGED
@@ -1,76 +1,18 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require_relative 'context'
|
4
|
+
require_relative 'core'
|
5
|
+
require_relative 'variables'
|
4
6
|
require_relative 'callbacks'
|
5
|
-
require_relative '
|
6
|
-
require_relative '
|
7
|
+
require_relative 'instrumentation'
|
8
|
+
require_relative 'coactors'
|
7
9
|
|
8
10
|
module IIInteractor
|
9
11
|
class Base
|
12
|
+
include Core
|
10
13
|
include Callbacks
|
11
|
-
include
|
12
|
-
include
|
13
|
-
|
14
|
-
attr_reader :context
|
15
|
-
|
16
|
-
def initialize(context = {}, &block)
|
17
|
-
@context = if context.is_a?(IIInteractor::Context)
|
18
|
-
context
|
19
|
-
else
|
20
|
-
IIInteractor::Context.new(context, &block)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def call_all
|
25
|
-
planned = lookup.map { |interactor| interactor.new(@context) } + [self]
|
26
|
-
@context._planned += planned
|
27
|
-
planned.each_with_index do |interactor, i|
|
28
|
-
if i == planned.size - 1
|
29
|
-
interactor.call_self
|
30
|
-
else
|
31
|
-
interactor.call_all
|
32
|
-
end
|
33
|
-
break if @context.stopped?
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def call_self
|
38
|
-
run_callbacks :call do
|
39
|
-
call
|
40
|
-
end
|
41
|
-
@context._called << self
|
42
|
-
end
|
43
|
-
|
44
|
-
def call
|
45
|
-
end
|
46
|
-
|
47
|
-
def rollback
|
48
|
-
end
|
49
|
-
|
50
|
-
def inform(*args)
|
51
|
-
@context._block.call(*([self] + args)) if @context._block
|
52
|
-
end
|
53
|
-
|
54
|
-
def fail!(data = {})
|
55
|
-
@context.fail!(data)
|
56
|
-
raise UnprogressableError.new(@context)
|
57
|
-
end
|
58
|
-
|
59
|
-
def stop!(data = {})
|
60
|
-
@context.stop!(data)
|
61
|
-
end
|
62
|
-
|
63
|
-
class << self
|
64
|
-
def call(context = {}, &block)
|
65
|
-
interactor = new(context, &block)
|
66
|
-
interactor.call_all
|
67
|
-
interactor.context
|
68
|
-
rescue UnprogressableError
|
69
|
-
interactor.context._called.reverse.each do |called|
|
70
|
-
called.rollback
|
71
|
-
end
|
72
|
-
interactor.context
|
73
|
-
end
|
74
|
-
end
|
14
|
+
include Instrumentation
|
15
|
+
include Variables
|
16
|
+
include Coactors
|
75
17
|
end
|
76
18
|
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
|
@@ -0,0 +1,69 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IIInteractor
|
4
|
+
module Core
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
attr_reader :context
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(context = {}, &block)
|
12
|
+
@context = if context.is_a?(IIInteractor::Context)
|
13
|
+
context
|
14
|
+
else
|
15
|
+
IIInteractor::Context.new(context, &block)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def call_all
|
20
|
+
planned = coactors.map { |interactor| interactor.new(@context) } + [self]
|
21
|
+
planned.each_with_index do |interactor, i|
|
22
|
+
if i == planned.size - 1
|
23
|
+
interactor.call_self
|
24
|
+
else
|
25
|
+
interactor.call_all
|
26
|
+
end
|
27
|
+
break if @context.stopped?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def call_self
|
32
|
+
call.tap do
|
33
|
+
@context._called << self
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def call
|
38
|
+
end
|
39
|
+
|
40
|
+
def rollback
|
41
|
+
end
|
42
|
+
|
43
|
+
def inform(*args)
|
44
|
+
@context._block.call(*([self] + args)) if @context._block
|
45
|
+
end
|
46
|
+
|
47
|
+
def fail!(data = {})
|
48
|
+
@context.fail!(data)
|
49
|
+
raise UnprogressableError.new(@context)
|
50
|
+
end
|
51
|
+
|
52
|
+
def stop!(data = {})
|
53
|
+
@context.stop!(data)
|
54
|
+
end
|
55
|
+
|
56
|
+
class_methods do
|
57
|
+
def call(*args, &block)
|
58
|
+
interactor = new(*args, &block)
|
59
|
+
interactor.call_all
|
60
|
+
interactor.context
|
61
|
+
rescue UnprogressableError
|
62
|
+
interactor.context._called.reverse.each do |called|
|
63
|
+
called.rollback
|
64
|
+
end
|
65
|
+
interactor.context
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
data/lib/ii_interactor/errors.rb
CHANGED
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module IIInteractor
|
4
|
+
class LogSubscriber < ActiveSupport::LogSubscriber
|
5
|
+
def call(event)
|
6
|
+
debug do
|
7
|
+
interactor = event.payload[:interactor]
|
8
|
+
"Called #{interactor.class} (#{additional_log(event)})"
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
def additional_log(event)
|
13
|
+
additions = ["Duration: %.1fms" % event.duration]
|
14
|
+
additions << "Allocations: %d" % event.allocations if event.respond_to?(:allocations)
|
15
|
+
additions.join(', ')
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,72 @@
|
|
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
|
data/lib/ii_interactor.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
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/
|
8
|
+
require 'ii_interactor/log_subscriber'
|
8
9
|
|
9
10
|
module IIInteractor
|
10
11
|
class << self
|
@@ -15,9 +16,5 @@ module IIInteractor
|
|
15
16
|
def config
|
16
17
|
Config
|
17
18
|
end
|
18
|
-
|
19
|
-
def load
|
20
|
-
Loader.call
|
21
|
-
end
|
22
19
|
end
|
23
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.0.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: 2021-
|
11
|
+
date: 2021-11-29 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.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.1'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rails
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -104,6 +118,7 @@ files:
|
|
104
118
|
- ".github/workflows/ci.yml"
|
105
119
|
- ".gitignore"
|
106
120
|
- ".rspec"
|
121
|
+
- CHANGELOG.md
|
107
122
|
- Gemfile
|
108
123
|
- LICENSE
|
109
124
|
- README.md
|
@@ -119,15 +134,14 @@ files:
|
|
119
134
|
- lib/ii_interactor.rb
|
120
135
|
- lib/ii_interactor/base.rb
|
121
136
|
- lib/ii_interactor/callbacks.rb
|
137
|
+
- lib/ii_interactor/coactors.rb
|
122
138
|
- lib/ii_interactor/config.rb
|
123
139
|
- lib/ii_interactor/context.rb
|
140
|
+
- lib/ii_interactor/core.rb
|
124
141
|
- lib/ii_interactor/errors.rb
|
125
|
-
- lib/ii_interactor/
|
126
|
-
- lib/ii_interactor/
|
127
|
-
- lib/ii_interactor/
|
128
|
-
- lib/ii_interactor/lookups/base.rb
|
129
|
-
- lib/ii_interactor/lookups/name.rb
|
130
|
-
- lib/ii_interactor/lookups/object.rb
|
142
|
+
- lib/ii_interactor/instrumentation.rb
|
143
|
+
- lib/ii_interactor/log_subscriber.rb
|
144
|
+
- lib/ii_interactor/variables.rb
|
131
145
|
- lib/ii_interactor/version.rb
|
132
146
|
homepage: https://github.com/kanety/ii_interactor
|
133
147
|
licenses: []
|
@@ -147,7 +161,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
147
161
|
- !ruby/object:Gem::Version
|
148
162
|
version: '0'
|
149
163
|
requirements: []
|
150
|
-
rubygems_version: 3.
|
164
|
+
rubygems_version: 3.0.3
|
151
165
|
signing_key:
|
152
166
|
specification_version: 4
|
153
167
|
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.env.production?
|
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
|
-
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 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
|