interactify 0.3.0.pre.alpha.1 → 0.4.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/.rubocop.yml +1 -0
- data/.ruby-version +1 -0
- data/Appraisals +23 -0
- data/CHANGELOG.md +14 -0
- data/README.md +33 -44
- data/gemfiles/.bundle/config +2 -0
- data/gemfiles/no_railties_no_sidekiq.gemfile +18 -0
- data/gemfiles/no_railties_no_sidekiq.gemfile.lock +127 -0
- data/gemfiles/railties_6.gemfile +14 -0
- data/gemfiles/railties_6.gemfile.lock +253 -0
- data/gemfiles/railties_6_no_sidekiq.gemfile +19 -0
- data/gemfiles/railties_6_no_sidekiq.gemfile.lock +159 -0
- data/gemfiles/railties_6_sidekiq.gemfile +20 -0
- data/gemfiles/railties_6_sidekiq.gemfile.lock +168 -0
- data/gemfiles/railties_7_no_sidekiq.gemfile +19 -0
- data/gemfiles/railties_7_no_sidekiq.gemfile.lock +158 -0
- data/gemfiles/railties_7_sidekiq.gemfile +20 -0
- data/gemfiles/railties_7_sidekiq.gemfile.lock +167 -0
- data/lib/interactify/async/job_klass.rb +63 -0
- data/lib/interactify/async/job_maker.rb +58 -0
- data/lib/interactify/async/jobable.rb +96 -0
- data/lib/interactify/async/null_job.rb +23 -0
- data/lib/interactify/configuration.rb +15 -0
- data/lib/interactify/contracts/call_wrapper.rb +19 -0
- data/lib/interactify/contracts/failure.rb +8 -0
- data/lib/interactify/contracts/helpers.rb +81 -0
- data/lib/interactify/contracts/mismatching_promise_error.rb +19 -0
- data/lib/interactify/contracts/promising.rb +36 -0
- data/lib/interactify/contracts/setup.rb +39 -0
- data/lib/interactify/dsl/each_chain.rb +90 -0
- data/lib/interactify/dsl/if_interactor.rb +81 -0
- data/lib/interactify/dsl/if_klass.rb +82 -0
- data/lib/interactify/dsl/organizer.rb +32 -0
- data/lib/interactify/dsl/unique_klass_name.rb +23 -0
- data/lib/interactify/dsl/wrapper.rb +74 -0
- data/lib/interactify/dsl.rb +12 -6
- data/lib/interactify/rspec_matchers/matchers.rb +68 -0
- data/lib/interactify/version.rb +1 -1
- data/lib/interactify/{interactor_wiring → wiring}/callable_representation.rb +2 -2
- data/lib/interactify/{interactor_wiring → wiring}/constants.rb +4 -4
- data/lib/interactify/{interactor_wiring → wiring}/error_context.rb +1 -1
- data/lib/interactify/{interactor_wiring → wiring}/files.rb +1 -1
- data/lib/interactify/{interactor_wiring.rb → wiring.rb} +5 -5
- data/lib/interactify.rb +58 -38
- metadata +48 -71
- data/lib/interactify/async_job_klass.rb +0 -61
- data/lib/interactify/call_wrapper.rb +0 -17
- data/lib/interactify/contract_failure.rb +0 -6
- data/lib/interactify/contract_helpers.rb +0 -71
- data/lib/interactify/each_chain.rb +0 -88
- data/lib/interactify/if_interactor.rb +0 -70
- data/lib/interactify/interactor_wrapper.rb +0 -72
- data/lib/interactify/job_maker.rb +0 -56
- data/lib/interactify/jobable.rb +0 -92
- data/lib/interactify/mismatching_promise_error.rb +0 -17
- data/lib/interactify/organizer.rb +0 -30
- data/lib/interactify/promising.rb +0 -34
- data/lib/interactify/rspec/matchers.rb +0 -67
- data/lib/interactify/unique_klass_name.rb +0 -21
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interactify
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.4.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Mark Burns
|
@@ -11,35 +11,21 @@ cert_chain: []
|
|
11
11
|
date: 2023-12-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
|
-
name:
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ">="
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ">="
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
|
-
- !ruby/object:Gem::Dependency
|
28
|
-
name: interactor-contracts
|
14
|
+
name: activesupport
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
30
16
|
requirements:
|
31
17
|
- - ">="
|
32
18
|
- !ruby/object:Gem::Version
|
33
|
-
version:
|
19
|
+
version: 6.0.0
|
34
20
|
type: :runtime
|
35
21
|
prerelease: false
|
36
22
|
version_requirements: !ruby/object:Gem::Requirement
|
37
23
|
requirements:
|
38
24
|
- - ">="
|
39
25
|
- !ruby/object:Gem::Version
|
40
|
-
version:
|
26
|
+
version: 6.0.0
|
41
27
|
- !ruby/object:Gem::Dependency
|
42
|
-
name:
|
28
|
+
name: interactor
|
43
29
|
requirement: !ruby/object:Gem::Requirement
|
44
30
|
requirements:
|
45
31
|
- - ">="
|
@@ -53,7 +39,7 @@ dependencies:
|
|
53
39
|
- !ruby/object:Gem::Version
|
54
40
|
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
|
-
name:
|
42
|
+
name: interactor-contracts
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
58
44
|
requirements:
|
59
45
|
- - ">="
|
@@ -66,34 +52,6 @@ dependencies:
|
|
66
52
|
- - ">="
|
67
53
|
- !ruby/object:Gem::Version
|
68
54
|
version: '0'
|
69
|
-
- !ruby/object:Gem::Dependency
|
70
|
-
name: debug
|
71
|
-
requirement: !ruby/object:Gem::Requirement
|
72
|
-
requirements:
|
73
|
-
- - ">="
|
74
|
-
- !ruby/object:Gem::Version
|
75
|
-
version: '0'
|
76
|
-
type: :development
|
77
|
-
prerelease: false
|
78
|
-
version_requirements: !ruby/object:Gem::Requirement
|
79
|
-
requirements:
|
80
|
-
- - ">="
|
81
|
-
- !ruby/object:Gem::Version
|
82
|
-
version: '0'
|
83
|
-
- !ruby/object:Gem::Dependency
|
84
|
-
name: deep_matching
|
85
|
-
requirement: !ruby/object:Gem::Requirement
|
86
|
-
requirements:
|
87
|
-
- - ">="
|
88
|
-
- !ruby/object:Gem::Version
|
89
|
-
version: '0'
|
90
|
-
type: :development
|
91
|
-
prerelease: false
|
92
|
-
version_requirements: !ruby/object:Gem::Requirement
|
93
|
-
requirements:
|
94
|
-
- - ">="
|
95
|
-
- !ruby/object:Gem::Version
|
96
|
-
version: '0'
|
97
55
|
description: |
|
98
56
|
Adds the following to your interactor chains
|
99
57
|
- lambda support
|
@@ -110,32 +68,51 @@ extra_rdoc_files: []
|
|
110
68
|
files:
|
111
69
|
- ".rspec"
|
112
70
|
- ".rubocop.yml"
|
71
|
+
- ".ruby-version"
|
72
|
+
- Appraisals
|
113
73
|
- CHANGELOG.md
|
114
74
|
- LICENSE.txt
|
115
75
|
- README.md
|
116
76
|
- Rakefile
|
77
|
+
- gemfiles/.bundle/config
|
78
|
+
- gemfiles/no_railties_no_sidekiq.gemfile
|
79
|
+
- gemfiles/no_railties_no_sidekiq.gemfile.lock
|
80
|
+
- gemfiles/railties_6.gemfile
|
81
|
+
- gemfiles/railties_6.gemfile.lock
|
82
|
+
- gemfiles/railties_6_no_sidekiq.gemfile
|
83
|
+
- gemfiles/railties_6_no_sidekiq.gemfile.lock
|
84
|
+
- gemfiles/railties_6_sidekiq.gemfile
|
85
|
+
- gemfiles/railties_6_sidekiq.gemfile.lock
|
86
|
+
- gemfiles/railties_7_no_sidekiq.gemfile
|
87
|
+
- gemfiles/railties_7_no_sidekiq.gemfile.lock
|
88
|
+
- gemfiles/railties_7_sidekiq.gemfile
|
89
|
+
- gemfiles/railties_7_sidekiq.gemfile.lock
|
117
90
|
- lib/interactify.rb
|
118
|
-
- lib/interactify/
|
119
|
-
- lib/interactify/
|
120
|
-
- lib/interactify/
|
121
|
-
- lib/interactify/
|
91
|
+
- lib/interactify/async/job_klass.rb
|
92
|
+
- lib/interactify/async/job_maker.rb
|
93
|
+
- lib/interactify/async/jobable.rb
|
94
|
+
- lib/interactify/async/null_job.rb
|
95
|
+
- lib/interactify/configuration.rb
|
96
|
+
- lib/interactify/contracts/call_wrapper.rb
|
97
|
+
- lib/interactify/contracts/failure.rb
|
98
|
+
- lib/interactify/contracts/helpers.rb
|
99
|
+
- lib/interactify/contracts/mismatching_promise_error.rb
|
100
|
+
- lib/interactify/contracts/promising.rb
|
101
|
+
- lib/interactify/contracts/setup.rb
|
122
102
|
- lib/interactify/dsl.rb
|
123
|
-
- lib/interactify/each_chain.rb
|
124
|
-
- lib/interactify/if_interactor.rb
|
125
|
-
- lib/interactify/
|
126
|
-
- lib/interactify/
|
127
|
-
- lib/interactify/
|
128
|
-
- lib/interactify/
|
129
|
-
- lib/interactify/
|
130
|
-
- lib/interactify/interactor_wrapper.rb
|
131
|
-
- lib/interactify/job_maker.rb
|
132
|
-
- lib/interactify/jobable.rb
|
133
|
-
- lib/interactify/mismatching_promise_error.rb
|
134
|
-
- lib/interactify/organizer.rb
|
135
|
-
- lib/interactify/promising.rb
|
136
|
-
- lib/interactify/rspec/matchers.rb
|
137
|
-
- lib/interactify/unique_klass_name.rb
|
103
|
+
- lib/interactify/dsl/each_chain.rb
|
104
|
+
- lib/interactify/dsl/if_interactor.rb
|
105
|
+
- lib/interactify/dsl/if_klass.rb
|
106
|
+
- lib/interactify/dsl/organizer.rb
|
107
|
+
- lib/interactify/dsl/unique_klass_name.rb
|
108
|
+
- lib/interactify/dsl/wrapper.rb
|
109
|
+
- lib/interactify/rspec_matchers/matchers.rb
|
138
110
|
- lib/interactify/version.rb
|
111
|
+
- lib/interactify/wiring.rb
|
112
|
+
- lib/interactify/wiring/callable_representation.rb
|
113
|
+
- lib/interactify/wiring/constants.rb
|
114
|
+
- lib/interactify/wiring/error_context.rb
|
115
|
+
- lib/interactify/wiring/files.rb
|
139
116
|
- sig/interactify.rbs
|
140
117
|
homepage: https://github.com/markburns/interactify
|
141
118
|
licenses:
|
@@ -154,14 +131,14 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
154
131
|
requirements:
|
155
132
|
- - ">="
|
156
133
|
- !ruby/object:Gem::Version
|
157
|
-
version:
|
134
|
+
version: 3.1.4
|
158
135
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
159
136
|
requirements:
|
160
|
-
- - "
|
137
|
+
- - ">="
|
161
138
|
- !ruby/object:Gem::Version
|
162
|
-
version:
|
139
|
+
version: '0'
|
163
140
|
requirements: []
|
164
|
-
rubygems_version: 3.
|
141
|
+
rubygems_version: 3.3.26
|
165
142
|
signing_key:
|
166
143
|
specification_version: 4
|
167
144
|
summary: Interactors with bells and whistles
|
@@ -1,61 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Interactify
|
4
|
-
class AsyncJobKlass
|
5
|
-
attr_reader :container_klass, :klass_suffix
|
6
|
-
|
7
|
-
def initialize(container_klass:, klass_suffix:)
|
8
|
-
@container_klass = container_klass
|
9
|
-
@klass_suffix = klass_suffix
|
10
|
-
end
|
11
|
-
|
12
|
-
def async_job_klass
|
13
|
-
klass = Class.new do
|
14
|
-
include Interactor
|
15
|
-
include Interactor::Contracts
|
16
|
-
end
|
17
|
-
|
18
|
-
attach_call(klass)
|
19
|
-
attach_call!(klass)
|
20
|
-
|
21
|
-
klass
|
22
|
-
end
|
23
|
-
|
24
|
-
def attach_call(async_job_klass)
|
25
|
-
# e.g. SomeInteractor::AsyncWithSuffix.call(foo: 'bar')
|
26
|
-
async_job_klass.send(:define_singleton_method, :call) do |context|
|
27
|
-
call!(context)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
def attach_call!(async_job_klass)
|
32
|
-
this = self
|
33
|
-
|
34
|
-
# e.g. SomeInteractor::AsyncWithSuffix.call!(foo: 'bar')
|
35
|
-
async_job_klass.send(:define_singleton_method, :call!) do |context|
|
36
|
-
# e.g. SomeInteractor::JobWithSuffix
|
37
|
-
job_klass = this.container_klass.const_get("Job#{this.klass_suffix}")
|
38
|
-
|
39
|
-
# e.g. SomeInteractor::JobWithSuffix.perform_async({foo: 'bar'})
|
40
|
-
job_klass.perform_async(this.args(context))
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
def args(context)
|
45
|
-
args = context.to_h.stringify_keys
|
46
|
-
|
47
|
-
return args unless container_klass.respond_to?(:expected_keys)
|
48
|
-
|
49
|
-
restrict_to_optional_or_keys_from_contract(args)
|
50
|
-
end
|
51
|
-
|
52
|
-
def restrict_to_optional_or_keys_from_contract(args)
|
53
|
-
keys = container_klass.expected_keys.map(&:to_s)
|
54
|
-
|
55
|
-
optional = Array(container_klass.optional_attrs).map(&:to_s)
|
56
|
-
keys += optional
|
57
|
-
|
58
|
-
args.slice(*keys)
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,17 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Interactify
|
4
|
-
module CallWrapper
|
5
|
-
# https://github.com/collectiveidea/interactor/blob/57b2af9a5a5afeb2c01059c40b792485cc21b052/lib/interactor.rb#L114
|
6
|
-
# Interactor#run calls Interactor#run!
|
7
|
-
# https://github.com/collectiveidea/interactor/blob/57b2af9a5a5afeb2c01059c40b792485cc21b052/lib/interactor.rb#L49
|
8
|
-
# Interactor.call calls Interactor.run
|
9
|
-
#
|
10
|
-
# The non bang methods call the bang methods and rescue
|
11
|
-
def run
|
12
|
-
@_interactor_called_by_non_bang_method = true
|
13
|
-
|
14
|
-
super
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,71 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "interactify/jobable"
|
4
|
-
require "interactify/call_wrapper"
|
5
|
-
require "interactify/organizer"
|
6
|
-
require "interactify/contract_failure"
|
7
|
-
|
8
|
-
module Interactify
|
9
|
-
module ContractHelpers
|
10
|
-
extend ActiveSupport::Concern
|
11
|
-
|
12
|
-
class_methods do
|
13
|
-
def expect(*attrs, filled: true)
|
14
|
-
expects do
|
15
|
-
attrs.each do |attr|
|
16
|
-
field = required(attr)
|
17
|
-
field.filled if filled
|
18
|
-
end
|
19
|
-
end
|
20
|
-
|
21
|
-
delegate(*attrs, to: :context)
|
22
|
-
end
|
23
|
-
|
24
|
-
def optional(*attrs)
|
25
|
-
@optional_attrs ||= []
|
26
|
-
@optional_attrs += attrs
|
27
|
-
|
28
|
-
delegate(*attrs, to: :context)
|
29
|
-
end
|
30
|
-
|
31
|
-
attr_reader :optional_attrs
|
32
|
-
|
33
|
-
def promise(*attrs, filled: true, should_delegate: true)
|
34
|
-
promises do
|
35
|
-
attrs.each do |attr|
|
36
|
-
field = required(attr)
|
37
|
-
field.filled if filled
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
delegate(*attrs, to: :context) if should_delegate
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
included do
|
46
|
-
c = Class.new(ContractFailure)
|
47
|
-
# example self is Whatever::SomeInteractor
|
48
|
-
# failure class: Whatever::SomeInteractor::InteractorContractFailure
|
49
|
-
const_set "InteractorContractFailure", c
|
50
|
-
prepend CallWrapper
|
51
|
-
include Organizer
|
52
|
-
|
53
|
-
on_breach do |breaches|
|
54
|
-
breaches = breaches.map { |b| { b.property => b.messages } }.inject(&:merge)
|
55
|
-
|
56
|
-
Interactify.trigger_contract_breach_hook(context, breaches)
|
57
|
-
|
58
|
-
if @_interactor_called_by_non_bang_method == true
|
59
|
-
context.fail! contract_failures: breaches
|
60
|
-
else
|
61
|
-
# e.g. raises
|
62
|
-
# SomeNamespace::SomeClass::ContractFailure, {whatever: 'is missing'}
|
63
|
-
# but also sending the context into Sentry
|
64
|
-
exception = c.new(breaches.to_json)
|
65
|
-
Interactify.trigger_before_raise_hook(exception)
|
66
|
-
raise exception
|
67
|
-
end
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
@@ -1,88 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "interactify/unique_klass_name"
|
4
|
-
|
5
|
-
module Interactify
|
6
|
-
class EachChain
|
7
|
-
attr_reader :each_loop_klasses, :plural_resource_name, :evaluating_receiver
|
8
|
-
|
9
|
-
def self.attach_klass(evaluating_receiver, plural_resource_name, *each_loop_klasses)
|
10
|
-
iteratable = new(each_loop_klasses, plural_resource_name, evaluating_receiver)
|
11
|
-
iteratable.attach_klass
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(each_loop_klasses, plural_resource_name, evaluating_receiver)
|
15
|
-
@each_loop_klasses = each_loop_klasses
|
16
|
-
@plural_resource_name = plural_resource_name
|
17
|
-
@evaluating_receiver = evaluating_receiver
|
18
|
-
end
|
19
|
-
|
20
|
-
# allows us to dynamically create an interactor chain
|
21
|
-
# that iterates over the packages and
|
22
|
-
# uses the passed in each_loop_klasses
|
23
|
-
# rubocop:disable all
|
24
|
-
def klass
|
25
|
-
this = self
|
26
|
-
|
27
|
-
Class.new do # class SomeNamespace::EachPackage
|
28
|
-
include Interactify # include Interactify
|
29
|
-
|
30
|
-
expects do # expects do
|
31
|
-
required(this.plural_resource_name) # required(:packages)
|
32
|
-
end # end
|
33
|
-
|
34
|
-
define_singleton_method(:source_location) do # def self.source_location
|
35
|
-
const_source_location this.evaluating_receiver.to_s # [file, line]
|
36
|
-
end # end
|
37
|
-
|
38
|
-
define_method(:run!) do # def run!
|
39
|
-
context.send(this.plural_resource_name).each_with_index do |resource, index|# context.packages.each_with_index do |package, index|
|
40
|
-
context[this.singular_resource_name] = resource # context.package = package
|
41
|
-
context[this.singular_resource_index_name] = index # context.package_index = index
|
42
|
-
|
43
|
-
klasses = InteractorWrapper.wrap_many(self, this.each_loop_klasses)
|
44
|
-
|
45
|
-
klasses.each do |interactor| # [A, B, C].each do |interactor|
|
46
|
-
interactor.call!(context) # interactor.call!(context)
|
47
|
-
end # end
|
48
|
-
end # end
|
49
|
-
|
50
|
-
context[this.singular_resource_name] = nil # context.package = nil
|
51
|
-
context[this.singular_resource_index_name] = nil # context.package_index = nil
|
52
|
-
|
53
|
-
context # context
|
54
|
-
end # end
|
55
|
-
|
56
|
-
define_method(:inspect) do
|
57
|
-
"<#{this.namespace}::#{this.iterator_klass_name} iterates_over: #{this.each_loop_klasses.inspect}>"
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
61
|
-
# rubocop:enable all
|
62
|
-
|
63
|
-
def attach_klass
|
64
|
-
name = iterator_klass_name
|
65
|
-
|
66
|
-
namespace.const_set(name, klass)
|
67
|
-
namespace.const_get(name)
|
68
|
-
end
|
69
|
-
|
70
|
-
def namespace
|
71
|
-
evaluating_receiver
|
72
|
-
end
|
73
|
-
|
74
|
-
def iterator_klass_name
|
75
|
-
prefix = "Each#{singular_resource_name.to_s.camelize}"
|
76
|
-
|
77
|
-
UniqueKlassName.for(namespace, prefix)
|
78
|
-
end
|
79
|
-
|
80
|
-
def singular_resource_name
|
81
|
-
plural_resource_name.to_s.singularize.to_sym
|
82
|
-
end
|
83
|
-
|
84
|
-
def singular_resource_index_name
|
85
|
-
"#{singular_resource_name}_index".to_sym
|
86
|
-
end
|
87
|
-
end
|
88
|
-
end
|
@@ -1,70 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "interactify/unique_klass_name"
|
4
|
-
|
5
|
-
module Interactify
|
6
|
-
class IfInteractor
|
7
|
-
attr_reader :condition, :success_interactor, :failure_interactor, :evaluating_receiver
|
8
|
-
|
9
|
-
def self.attach_klass(evaluating_receiver, condition, succcess_interactor, failure_interactor)
|
10
|
-
ifable = new(evaluating_receiver, condition, succcess_interactor, failure_interactor)
|
11
|
-
ifable.attach_klass
|
12
|
-
end
|
13
|
-
|
14
|
-
def initialize(evaluating_receiver, condition, succcess_interactor, failure_interactor)
|
15
|
-
@evaluating_receiver = evaluating_receiver
|
16
|
-
@condition = condition
|
17
|
-
@success_interactor = succcess_interactor
|
18
|
-
@failure_interactor = failure_interactor
|
19
|
-
end
|
20
|
-
|
21
|
-
# allows us to dynamically create an interactor chain
|
22
|
-
# that iterates over the packages and
|
23
|
-
# uses the passed in each_loop_klasses
|
24
|
-
# rubocop:disable all
|
25
|
-
def klass
|
26
|
-
this = self
|
27
|
-
|
28
|
-
Class.new do
|
29
|
-
include Interactor
|
30
|
-
include Interactor::Contracts
|
31
|
-
|
32
|
-
expects do
|
33
|
-
required(this.condition) unless this.condition.is_a?(Proc)
|
34
|
-
end
|
35
|
-
|
36
|
-
define_singleton_method(:source_location) do
|
37
|
-
const_source_location this.evaluating_receiver.to_s # [file, line]
|
38
|
-
end
|
39
|
-
|
40
|
-
define_method(:run!) do
|
41
|
-
result = this.condition.is_a?(Proc) ? this.condition.call(context) : context.send(this.condition)
|
42
|
-
interactor = result ? this.success_interactor : this.failure_interactor
|
43
|
-
interactor&.respond_to?(:call!) ? interactor.call!(context) : interactor&.call(context)
|
44
|
-
end
|
45
|
-
|
46
|
-
define_method(:inspect) do
|
47
|
-
"<#{this.namespace}::#{this.if_klass_name} #{this.condition} ? #{this.success_interactor} : #{this.failure_interactor}>"
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
# rubocop:enable all
|
52
|
-
|
53
|
-
def attach_klass
|
54
|
-
name = if_klass_name
|
55
|
-
namespace.const_set(name, klass)
|
56
|
-
namespace.const_get(name)
|
57
|
-
end
|
58
|
-
|
59
|
-
def namespace
|
60
|
-
evaluating_receiver
|
61
|
-
end
|
62
|
-
|
63
|
-
def if_klass_name
|
64
|
-
prefix = condition.is_a?(Proc) ? "Proc" : condition
|
65
|
-
prefix = "If#{prefix.to_s.camelize}"
|
66
|
-
|
67
|
-
UniqueKlassName.for(namespace, prefix)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
@@ -1,72 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "interactify/unique_klass_name"
|
4
|
-
|
5
|
-
module Interactify
|
6
|
-
class InteractorWrapper
|
7
|
-
attr_reader :organizer, :interactor
|
8
|
-
|
9
|
-
def self.wrap_many(organizer, interactors)
|
10
|
-
Array(interactors).map do |interactor|
|
11
|
-
wrap(organizer, interactor)
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.wrap(organizer, interactor)
|
16
|
-
new(organizer, interactor).wrap
|
17
|
-
end
|
18
|
-
|
19
|
-
def initialize(organizer, interactor)
|
20
|
-
@organizer = organizer
|
21
|
-
@interactor = interactor
|
22
|
-
end
|
23
|
-
|
24
|
-
def wrap
|
25
|
-
case interactor
|
26
|
-
when Hash
|
27
|
-
wrap_conditional
|
28
|
-
when Array
|
29
|
-
wrap_chain
|
30
|
-
when Proc
|
31
|
-
wrap_proc
|
32
|
-
else
|
33
|
-
interactor
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
def wrap_chain
|
38
|
-
return self.class.wrap(organizer, interactor.first) if interactor.length == 1
|
39
|
-
|
40
|
-
klass_name = UniqueKlassName.for(organizer, "Chained")
|
41
|
-
organizer.chain(klass_name, *interactor.map { self.class.wrap(organizer, _1) })
|
42
|
-
end
|
43
|
-
|
44
|
-
def wrap_conditional
|
45
|
-
raise ArgumentError, "Hash must have at least :if, and :then key" unless condition && then_do
|
46
|
-
|
47
|
-
return organizer.if(condition, then_do, else_do) if else_do
|
48
|
-
|
49
|
-
organizer.if(condition, then_do)
|
50
|
-
end
|
51
|
-
|
52
|
-
def condition = interactor[:if]
|
53
|
-
def then_do = interactor[:then]
|
54
|
-
def else_do = interactor[:else]
|
55
|
-
|
56
|
-
def wrap_proc
|
57
|
-
this = self
|
58
|
-
|
59
|
-
Class.new do
|
60
|
-
include Interactify
|
61
|
-
|
62
|
-
define_singleton_method :wrapped do
|
63
|
-
this.interactor
|
64
|
-
end
|
65
|
-
|
66
|
-
define_method(:call) do
|
67
|
-
this.interactor.call(context)
|
68
|
-
end
|
69
|
-
end
|
70
|
-
end
|
71
|
-
end
|
72
|
-
end
|
@@ -1,56 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require "sidekiq"
|
4
|
-
require "sidekiq/job"
|
5
|
-
|
6
|
-
require "interactify/async_job_klass"
|
7
|
-
|
8
|
-
module Interactify
|
9
|
-
class JobMaker
|
10
|
-
attr_reader :opts, :method_name, :container_klass, :klass_suffix
|
11
|
-
|
12
|
-
def initialize(container_klass:, opts:, klass_suffix:, method_name: :call!)
|
13
|
-
@container_klass = container_klass
|
14
|
-
@opts = opts
|
15
|
-
@method_name = method_name
|
16
|
-
@klass_suffix = klass_suffix
|
17
|
-
end
|
18
|
-
|
19
|
-
concerning :JobClass do
|
20
|
-
def job_klass
|
21
|
-
@job_klass ||= define_job_klass
|
22
|
-
end
|
23
|
-
|
24
|
-
private
|
25
|
-
|
26
|
-
def define_job_klass
|
27
|
-
this = self
|
28
|
-
|
29
|
-
invalid_keys = this.opts.symbolize_keys.keys - %i[queue retry dead backtrace pool tags]
|
30
|
-
|
31
|
-
raise ArgumentError, "Invalid keys: #{invalid_keys}" if invalid_keys.any?
|
32
|
-
|
33
|
-
build_job_klass(opts).tap do |klass|
|
34
|
-
klass.const_set(:JOBABLE_OPTS, opts)
|
35
|
-
klass.const_set(:JOBABLE_METHOD_NAME, method_name)
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
def build_job_klass(opts)
|
40
|
-
Class.new do
|
41
|
-
include Sidekiq::Job
|
42
|
-
|
43
|
-
sidekiq_options(opts)
|
44
|
-
|
45
|
-
def perform(...)
|
46
|
-
self.class.module_parent.send(self.class::JOBABLE_METHOD_NAME, ...)
|
47
|
-
end
|
48
|
-
end
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
def async_job_klass
|
53
|
-
AsyncJobKlass.new(container_klass:, klass_suffix:).async_job_klass
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|