interactify 0.3.0.pre.RC1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/Appraisals +2 -0
  4. data/CHANGELOG.md +5 -0
  5. data/README.md +10 -4
  6. data/gemfiles/no_railties_no_sidekiq.gemfile +3 -1
  7. data/gemfiles/no_railties_no_sidekiq.gemfile.lock +1 -1
  8. data/gemfiles/railties_6_no_sidekiq.gemfile +3 -1
  9. data/gemfiles/railties_6_no_sidekiq.gemfile.lock +2 -1
  10. data/gemfiles/railties_6_sidekiq.gemfile +3 -1
  11. data/gemfiles/railties_6_sidekiq.gemfile.lock +2 -1
  12. data/gemfiles/railties_7_no_sidekiq.gemfile +3 -1
  13. data/gemfiles/railties_7_no_sidekiq.gemfile.lock +2 -1
  14. data/gemfiles/railties_7_sidekiq.gemfile +3 -1
  15. data/gemfiles/railties_7_sidekiq.gemfile.lock +2 -1
  16. data/lib/interactify/async/job_klass.rb +63 -0
  17. data/lib/interactify/async/job_maker.rb +58 -0
  18. data/lib/interactify/async/jobable.rb +96 -0
  19. data/lib/interactify/async/null_job.rb +23 -0
  20. data/lib/interactify/configuration.rb +15 -0
  21. data/lib/interactify/contracts/call_wrapper.rb +19 -0
  22. data/lib/interactify/contracts/failure.rb +8 -0
  23. data/lib/interactify/contracts/helpers.rb +81 -0
  24. data/lib/interactify/contracts/mismatching_promise_error.rb +19 -0
  25. data/lib/interactify/contracts/promising.rb +36 -0
  26. data/lib/interactify/contracts/setup.rb +39 -0
  27. data/lib/interactify/dsl/each_chain.rb +90 -0
  28. data/lib/interactify/dsl/if_interactor.rb +81 -0
  29. data/lib/interactify/dsl/if_klass.rb +82 -0
  30. data/lib/interactify/dsl/organizer.rb +32 -0
  31. data/lib/interactify/dsl/unique_klass_name.rb +23 -0
  32. data/lib/interactify/dsl/wrapper.rb +74 -0
  33. data/lib/interactify/dsl.rb +12 -6
  34. data/lib/interactify/rspec_matchers/matchers.rb +68 -0
  35. data/lib/interactify/version.rb +1 -1
  36. data/lib/interactify/{interactor_wiring → wiring}/callable_representation.rb +2 -2
  37. data/lib/interactify/{interactor_wiring → wiring}/constants.rb +1 -1
  38. data/lib/interactify/{interactor_wiring → wiring}/error_context.rb +1 -1
  39. data/lib/interactify/{interactor_wiring → wiring}/files.rb +1 -1
  40. data/lib/interactify/{interactor_wiring.rb → wiring.rb} +4 -4
  41. data/lib/interactify.rb +13 -50
  42. metadata +31 -56
  43. data/lib/interactify/async_job_klass.rb +0 -61
  44. data/lib/interactify/call_wrapper.rb +0 -17
  45. data/lib/interactify/contract_failure.rb +0 -6
  46. data/lib/interactify/contract_helpers.rb +0 -71
  47. data/lib/interactify/each_chain.rb +0 -88
  48. data/lib/interactify/if_interactor.rb +0 -70
  49. data/lib/interactify/interactor_wrapper.rb +0 -72
  50. data/lib/interactify/job_maker.rb +0 -56
  51. data/lib/interactify/jobable.rb +0 -94
  52. data/lib/interactify/mismatching_promise_error.rb +0 -17
  53. data/lib/interactify/null_job.rb +0 -11
  54. data/lib/interactify/organizer.rb +0 -30
  55. data/lib/interactify/promising.rb +0 -34
  56. data/lib/interactify/rspec/matchers.rb +0 -67
  57. data/lib/interactify/unique_klass_name.rb +0 -21
data/lib/interactify.rb CHANGED
@@ -5,10 +5,11 @@ require "interactor-contracts"
5
5
  require "active_support/all"
6
6
 
7
7
  require "interactify/version"
8
- require "interactify/contract_helpers"
8
+ require "interactify/contracts/helpers"
9
+ require "interactify/contracts/promising"
9
10
  require "interactify/dsl"
10
- require "interactify/interactor_wiring"
11
- require "interactify/promising"
11
+ require "interactify/wiring"
12
+ require "interactify/configuration"
12
13
 
13
14
  module Interactify
14
15
  def self.railties_missing?
@@ -44,6 +45,11 @@ module Interactify
44
45
  end
45
46
  end
46
47
 
48
+ Interactify.instance_eval do
49
+ @sidekiq_missing = nil
50
+ @railties_missing = nil
51
+ end
52
+
47
53
  begin
48
54
  require "sidekiq"
49
55
  rescue LoadError
@@ -51,7 +57,7 @@ rescue LoadError
51
57
  end
52
58
 
53
59
  begin
54
- require 'rails/railtie'
60
+ require "rails/railtie"
55
61
  rescue LoadError
56
62
  Interactify.railties_missing!
57
63
  end
@@ -61,15 +67,7 @@ module Interactify
61
67
 
62
68
  class << self
63
69
  def validate_app(ignore: [])
64
- Interactify::InteractorWiring.new(root: Interactify.configuration.root, ignore:).validate_app
65
- end
66
-
67
- def sidekiq_missing?
68
- @sidekiq_missing
69
- end
70
-
71
- def sidekiq_missing!
72
- @sidekiq_missing = true
70
+ Interactify::Wiring.new(root: Interactify.configuration.root, ignore:).validate_app
73
71
  end
74
72
 
75
73
  def reset
@@ -110,7 +108,7 @@ module Interactify
110
108
 
111
109
  base.include Interactor::Organizer
112
110
  base.include Interactor::Contracts
113
- base.include Interactify::ContractHelpers
111
+ base.include Interactify::Contracts::Helpers
114
112
 
115
113
  # defines two classes on the receiver class
116
114
  # the first is the job class
@@ -131,45 +129,10 @@ module Interactify
131
129
  # that calls the interactor ExampleInteractor with (foo: 'bar')
132
130
  #
133
131
  # ExampleInteractor::Async.call(foo: 'bar')
134
- include Interactify::Jobable
132
+ include Interactify::Async::Jobable
135
133
  interactor_job
136
134
  end
137
135
 
138
- class_methods do
139
- def promising(*args)
140
- Promising.validate(self, *args)
141
- end
142
-
143
- def promised_keys
144
- _interactify_extract_keys(contract.promises)
145
- end
146
-
147
- def expected_keys
148
- _interactify_extract_keys(contract.expectations)
149
- end
150
-
151
- private
152
-
153
- # this is the most brittle part of the code, relying on
154
- # interactor-contracts internals
155
- # so extracted it to here so change is isolated
156
- def _interactify_extract_keys(clauses)
157
- clauses.instance_eval { @terms }.json&.rules&.keys
158
- end
159
- end
160
-
161
- class Configuration
162
- attr_writer :root
163
-
164
- def root
165
- @root ||= fallback
166
- end
167
-
168
- def fallback
169
- Rails.root / "app" if Interactify.railties?
170
- end
171
- end
172
-
173
136
  def called_klass_list
174
137
  context._called.map(&:class)
175
138
  end
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.3.0.pre.RC1
4
+ version: 0.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Mark Burns
@@ -10,34 +10,6 @@ bindir: exe
10
10
  cert_chain: []
11
11
  date: 2023-12-29 00:00:00.000000000 Z
12
12
  dependencies:
13
- - !ruby/object:Gem::Dependency
14
- name: interactor
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
29
- requirement: !ruby/object:Gem::Requirement
30
- requirements:
31
- - - ">="
32
- - !ruby/object:Gem::Version
33
- version: '0'
34
- type: :runtime
35
- prerelease: false
36
- version_requirements: !ruby/object:Gem::Requirement
37
- requirements:
38
- - - ">="
39
- - !ruby/object:Gem::Version
40
- version: '0'
41
13
  - !ruby/object:Gem::Dependency
42
14
  name: activesupport
43
15
  requirement: !ruby/object:Gem::Requirement
@@ -53,13 +25,13 @@ dependencies:
53
25
  - !ruby/object:Gem::Version
54
26
  version: 6.0.0
55
27
  - !ruby/object:Gem::Dependency
56
- name: debug
28
+ name: interactor
57
29
  requirement: !ruby/object:Gem::Requirement
58
30
  requirements:
59
31
  - - ">="
60
32
  - !ruby/object:Gem::Version
61
33
  version: '0'
62
- type: :development
34
+ type: :runtime
63
35
  prerelease: false
64
36
  version_requirements: !ruby/object:Gem::Requirement
65
37
  requirements:
@@ -67,13 +39,13 @@ dependencies:
67
39
  - !ruby/object:Gem::Version
68
40
  version: '0'
69
41
  - !ruby/object:Gem::Dependency
70
- name: appraisal
42
+ name: interactor-contracts
71
43
  requirement: !ruby/object:Gem::Requirement
72
44
  requirements:
73
45
  - - ">="
74
46
  - !ruby/object:Gem::Version
75
47
  version: '0'
76
- type: :development
48
+ type: :runtime
77
49
  prerelease: false
78
50
  version_requirements: !ruby/object:Gem::Requirement
79
51
  requirements:
@@ -116,28 +88,31 @@ files:
116
88
  - gemfiles/railties_7_sidekiq.gemfile
117
89
  - gemfiles/railties_7_sidekiq.gemfile.lock
118
90
  - lib/interactify.rb
119
- - lib/interactify/async_job_klass.rb
120
- - lib/interactify/call_wrapper.rb
121
- - lib/interactify/contract_failure.rb
122
- - lib/interactify/contract_helpers.rb
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
123
102
  - lib/interactify/dsl.rb
124
- - lib/interactify/each_chain.rb
125
- - lib/interactify/if_interactor.rb
126
- - lib/interactify/interactor_wiring.rb
127
- - lib/interactify/interactor_wiring/callable_representation.rb
128
- - lib/interactify/interactor_wiring/constants.rb
129
- - lib/interactify/interactor_wiring/error_context.rb
130
- - lib/interactify/interactor_wiring/files.rb
131
- - lib/interactify/interactor_wrapper.rb
132
- - lib/interactify/job_maker.rb
133
- - lib/interactify/jobable.rb
134
- - lib/interactify/mismatching_promise_error.rb
135
- - lib/interactify/null_job.rb
136
- - lib/interactify/organizer.rb
137
- - lib/interactify/promising.rb
138
- - lib/interactify/rspec/matchers.rb
139
- - 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
140
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
141
116
  - sig/interactify.rbs
142
117
  homepage: https://github.com/markburns/interactify
143
118
  licenses:
@@ -156,12 +131,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
156
131
  requirements:
157
132
  - - ">="
158
133
  - !ruby/object:Gem::Version
159
- version: 2.7.8
134
+ version: 3.1.4
160
135
  required_rubygems_version: !ruby/object:Gem::Requirement
161
136
  requirements:
162
- - - ">"
137
+ - - ">="
163
138
  - !ruby/object:Gem::Version
164
- version: 1.3.1
139
+ version: '0'
165
140
  requirements: []
166
141
  rubygems_version: 3.3.26
167
142
  signing_key:
@@ -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,6 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module Interactify
4
- class ContractFailure < ::Interactor::Failure
5
- end
6
- 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 "interactify/async_job_klass"
4
- require "interactify/null_job"
5
-
6
- module Interactify
7
- class JobMaker
8
- attr_reader :opts, :method_name, :container_klass, :klass_suffix
9
-
10
- def initialize(container_klass:, opts:, klass_suffix:, method_name: :call!)
11
- @container_klass = container_klass
12
- @opts = opts
13
- @method_name = method_name
14
- @klass_suffix = klass_suffix
15
- end
16
-
17
- concerning :JobClass do
18
- def job_klass
19
- @job_klass ||= define_job_klass
20
- end
21
-
22
- private
23
-
24
- def define_job_klass
25
- return NullJob if Interactify.sidekiq_missing?
26
-
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