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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 9e2c11382c90fb3533448d1ddc3ed2f1ca922abb204570beba2eed4ad264fbef
4
- data.tar.gz: dd2cd0bab63421c2c45b595438e2b4ef2f914abc041ce1cb1a655cd6ac98575c
3
+ metadata.gz: 8d41caaf17018a5faf867b26ee15e97c68afbf3126e69ce4a81fc5c0b2394345
4
+ data.tar.gz: dbe6665d293c2f8c42030592ebdbe7671f57c7737ddd28f50c326539e2635536
5
5
  SHA512:
6
- metadata.gz: e4ba848c2b8582434360c1f9f47b646fcea0e1954ec64419d8beb1b46b8bedd73876cc49de3f0a2f6258dc49db034e468b34bb90794a00c8807060cc2304ddb3
7
- data.tar.gz: e765a8adb58f62202ca6e35e302846185d575776805aaed73bc9495de7ebd6bca800f864d47bb176da5731b012af6897272e9810efee7f22af56b3807019d7a2
6
+ metadata.gz: 90c35516d55b89a9e37d56b5b280df3840c96b378ae37cba70d46ad5d5aff694b1c66b2029871028ff72db71293490b232a6796e4e9575eaacbe5d1b353c27f0
7
+ data.tar.gz: f25a6c2e3923c06d7aac135059979108c207953f0034bea8039ed159b88a4ab8adcfbe3f4019ca6c3b5bcf77e7415bde97c11adabb310c64b3bed4621b8e8e04
@@ -4,27 +4,41 @@ on: [push, pull_request]
4
4
 
5
5
  jobs:
6
6
  test:
7
- runs-on: ubuntu-18.04
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
@@ -2,6 +2,7 @@
2
2
  .project
3
3
  Gemfile.lock
4
4
  coverage/
5
+ gemfiles/*.lock
5
6
  pkg/
6
7
  tmp/
7
8
  spec/dummy/db/*.sqlite3
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
- For example:
46
+ `context_in` copies context to instance variables of interactor,
47
+ while `context_out` copies instance variables of interactor to context.
46
48
 
47
- ```ruby
48
- class Interactor < IIInteractor::Base
49
- context_in :input
50
- context_out :result
49
+ ### Context options
51
50
 
52
- def call
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
- ### Callbacks
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 `interact`:
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
- interact AInteractor
151
- interact BInteractor
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
- #### Named interaction
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
- interact AInteractor
340
- interact BInteractor
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
- interact AInteractor
383
- interact BInteractor
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
- interact AInteractor
417
- interact BInteractor
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
- Called SimpleInteractor (Duration: 0.3ms, Allocations: 42)
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
@@ -10,5 +10,5 @@ require "ii_interactor"
10
10
  # require "pry"
11
11
  # Pry.start
12
12
 
13
- # require "irb"
14
- # IRB.start
13
+ require "irb"
14
+ IRB.start
@@ -1,5 +1,6 @@
1
1
  source 'https://rubygems.org'
2
2
 
3
3
  gem "rails", "~> 6.0.0"
4
+ gem "psych", "~> 3.3.0"
4
5
 
5
6
  gemspec path: "../"
@@ -0,0 +1,5 @@
1
+ source 'https://rubygems.org'
2
+
3
+ gem "rails", "~> 7.0.1"
4
+
5
+ gemspec path: "../"
@@ -18,6 +18,7 @@ Gem::Specification.new do |spec|
18
18
  spec.require_paths = ["lib"]
19
19
 
20
20
  spec.add_dependency "activesupport", ">= 5.0"
21
+ spec.add_dependency "coactive", ">= 0.3"
21
22
 
22
23
  spec.add_development_dependency "rails", ">= 5.0"
23
24
  spec.add_development_dependency "sqlite3"
@@ -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 'interaction'
9
- require_relative 'lookup'
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 Variables
17
- include Interaction
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
@@ -5,6 +5,7 @@ module IIInteractor
5
5
  class_attribute :data
6
6
 
7
7
  self.data = {
8
+ traversal: :postorder,
8
9
  lookup_cache: true
9
10
  }
10
11
 
@@ -1,13 +1,34 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IIInteractor
4
- class Context < OpenStruct
5
- def initialize(hash, &block)
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
- self[:_block] = block
8
- self[:_failed] = false
9
- self[:_stopped] = false
10
- self[:_called] = []
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
- self[:_failed] == true
39
+ @_status.failed == true
19
40
  end
20
41
 
21
42
  def stopped?
22
- self[:_stopped] == true
43
+ @_status.stopped == true
23
44
  end
24
45
 
25
46
  def fail!(data = {})
26
- self[:_failed] = true
27
- data.each { |k, v| self[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
- self[:_stopped] = true
32
- data.each { |k, v| self[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
@@ -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
- attr_reader :context
9
+ self.context_class = IIInteractor::Context
9
10
  end
10
11
 
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
12
+ def initialize(*)
13
+ super
17
14
  end
18
15
 
19
16
  def call_all
20
- planned = lookup.map { |interactor| interactor.new(@context) } + [self]
21
- planned.each_with_index do |interactor, i|
22
- if i == planned.size - 1
23
- interactor.call_self
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._called << self
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._block.call(*([self] + args)) if @context._block
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(*args, &block)
58
- interactor = new(*args, &block)
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._called.reverse.each do |called|
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)
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module IIInteractor
4
- VERSION = '1.2.0'
4
+ VERSION = '2.2.0'
5
5
  end
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: 1.2.0
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: 2021-09-22 00:00:00.000000000 Z
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.1.2
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
@@ -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
@@ -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