interactify 0.3.0.pre.alpha.1 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (60) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -0
  3. data/.ruby-version +1 -0
  4. data/Appraisals +23 -0
  5. data/CHANGELOG.md +14 -0
  6. data/README.md +33 -44
  7. data/gemfiles/.bundle/config +2 -0
  8. data/gemfiles/no_railties_no_sidekiq.gemfile +18 -0
  9. data/gemfiles/no_railties_no_sidekiq.gemfile.lock +127 -0
  10. data/gemfiles/railties_6.gemfile +14 -0
  11. data/gemfiles/railties_6.gemfile.lock +253 -0
  12. data/gemfiles/railties_6_no_sidekiq.gemfile +19 -0
  13. data/gemfiles/railties_6_no_sidekiq.gemfile.lock +159 -0
  14. data/gemfiles/railties_6_sidekiq.gemfile +20 -0
  15. data/gemfiles/railties_6_sidekiq.gemfile.lock +168 -0
  16. data/gemfiles/railties_7_no_sidekiq.gemfile +19 -0
  17. data/gemfiles/railties_7_no_sidekiq.gemfile.lock +158 -0
  18. data/gemfiles/railties_7_sidekiq.gemfile +20 -0
  19. data/gemfiles/railties_7_sidekiq.gemfile.lock +167 -0
  20. data/lib/interactify/async/job_klass.rb +63 -0
  21. data/lib/interactify/async/job_maker.rb +58 -0
  22. data/lib/interactify/async/jobable.rb +96 -0
  23. data/lib/interactify/async/null_job.rb +23 -0
  24. data/lib/interactify/configuration.rb +15 -0
  25. data/lib/interactify/contracts/call_wrapper.rb +19 -0
  26. data/lib/interactify/contracts/failure.rb +8 -0
  27. data/lib/interactify/contracts/helpers.rb +81 -0
  28. data/lib/interactify/contracts/mismatching_promise_error.rb +19 -0
  29. data/lib/interactify/contracts/promising.rb +36 -0
  30. data/lib/interactify/contracts/setup.rb +39 -0
  31. data/lib/interactify/dsl/each_chain.rb +90 -0
  32. data/lib/interactify/dsl/if_interactor.rb +81 -0
  33. data/lib/interactify/dsl/if_klass.rb +82 -0
  34. data/lib/interactify/dsl/organizer.rb +32 -0
  35. data/lib/interactify/dsl/unique_klass_name.rb +23 -0
  36. data/lib/interactify/dsl/wrapper.rb +74 -0
  37. data/lib/interactify/dsl.rb +12 -6
  38. data/lib/interactify/rspec_matchers/matchers.rb +68 -0
  39. data/lib/interactify/version.rb +1 -1
  40. data/lib/interactify/{interactor_wiring → wiring}/callable_representation.rb +2 -2
  41. data/lib/interactify/{interactor_wiring → wiring}/constants.rb +4 -4
  42. data/lib/interactify/{interactor_wiring → wiring}/error_context.rb +1 -1
  43. data/lib/interactify/{interactor_wiring → wiring}/files.rb +1 -1
  44. data/lib/interactify/{interactor_wiring.rb → wiring.rb} +5 -5
  45. data/lib/interactify.rb +58 -38
  46. metadata +48 -71
  47. data/lib/interactify/async_job_klass.rb +0 -61
  48. data/lib/interactify/call_wrapper.rb +0 -17
  49. data/lib/interactify/contract_failure.rb +0 -6
  50. data/lib/interactify/contract_helpers.rb +0 -71
  51. data/lib/interactify/each_chain.rb +0 -88
  52. data/lib/interactify/if_interactor.rb +0 -70
  53. data/lib/interactify/interactor_wrapper.rb +0 -72
  54. data/lib/interactify/job_maker.rb +0 -56
  55. data/lib/interactify/jobable.rb +0 -92
  56. data/lib/interactify/mismatching_promise_error.rb +0 -17
  57. data/lib/interactify/organizer.rb +0 -30
  58. data/lib/interactify/promising.rb +0 -34
  59. data/lib/interactify/rspec/matchers.rb +0 -67
  60. 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.3.0.pre.alpha.1
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: 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
14
+ name: activesupport
29
15
  requirement: !ruby/object:Gem::Requirement
30
16
  requirements:
31
17
  - - ">="
32
18
  - !ruby/object:Gem::Version
33
- version: '0'
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: '0'
26
+ version: 6.0.0
41
27
  - !ruby/object:Gem::Dependency
42
- name: rails
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: sidekiq
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/async_job_klass.rb
119
- - lib/interactify/call_wrapper.rb
120
- - lib/interactify/contract_failure.rb
121
- - 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
122
102
  - lib/interactify/dsl.rb
123
- - lib/interactify/each_chain.rb
124
- - lib/interactify/if_interactor.rb
125
- - lib/interactify/interactor_wiring.rb
126
- - lib/interactify/interactor_wiring/callable_representation.rb
127
- - lib/interactify/interactor_wiring/constants.rb
128
- - lib/interactify/interactor_wiring/error_context.rb
129
- - lib/interactify/interactor_wiring/files.rb
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: '3.2'
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: 1.3.1
139
+ version: '0'
163
140
  requirements: []
164
- rubygems_version: 3.4.19
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,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 "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