ii_interactor 1.2.0 → 2.2.0

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