interactify 0.1.0.pre.alpha.1 → 0.3.0.pre.RC1

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.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +23 -0
  3. data/.ruby-version +1 -0
  4. data/Appraisals +21 -0
  5. data/CHANGELOG.md +18 -1
  6. data/README.md +178 -126
  7. data/gemfiles/.bundle/config +2 -0
  8. data/gemfiles/no_railties_no_sidekiq.gemfile +16 -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 +17 -0
  13. data/gemfiles/railties_6_no_sidekiq.gemfile.lock +158 -0
  14. data/gemfiles/railties_6_sidekiq.gemfile +18 -0
  15. data/gemfiles/railties_6_sidekiq.gemfile.lock +167 -0
  16. data/gemfiles/railties_7_no_sidekiq.gemfile +17 -0
  17. data/gemfiles/railties_7_no_sidekiq.gemfile.lock +157 -0
  18. data/gemfiles/railties_7_sidekiq.gemfile +18 -0
  19. data/gemfiles/railties_7_sidekiq.gemfile.lock +166 -0
  20. data/lib/interactify/async_job_klass.rb +61 -0
  21. data/lib/interactify/call_wrapper.rb +2 -0
  22. data/lib/interactify/contract_failure.rb +6 -0
  23. data/lib/interactify/contract_helpers.rb +10 -10
  24. data/lib/interactify/dsl.rb +6 -2
  25. data/lib/interactify/each_chain.rb +12 -4
  26. data/lib/interactify/if_interactor.rb +10 -4
  27. data/lib/interactify/interactor_wiring/callable_representation.rb +79 -0
  28. data/lib/interactify/interactor_wiring/constants.rb +125 -0
  29. data/lib/interactify/interactor_wiring/error_context.rb +41 -0
  30. data/lib/interactify/interactor_wiring/files.rb +51 -0
  31. data/lib/interactify/interactor_wiring.rb +57 -272
  32. data/lib/interactify/interactor_wrapper.rb +72 -0
  33. data/lib/interactify/job_maker.rb +20 -69
  34. data/lib/interactify/jobable.rb +11 -7
  35. data/lib/interactify/mismatching_promise_error.rb +17 -0
  36. data/lib/interactify/null_job.rb +11 -0
  37. data/lib/interactify/organizer.rb +30 -0
  38. data/lib/interactify/promising.rb +34 -0
  39. data/lib/interactify/rspec/matchers.rb +9 -11
  40. data/lib/interactify/unique_klass_name.rb +21 -0
  41. data/lib/interactify/version.rb +1 -1
  42. data/lib/interactify.rb +96 -9
  43. metadata +36 -23
  44. data/lib/interactify/organizer_call_monkey_patch.rb +0 -40
@@ -0,0 +1,157 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ interactify (0.3.0.pre.alpha.2)
5
+ interactor
6
+ interactor-contracts
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actionpack (7.0.0)
12
+ actionview (= 7.0.0)
13
+ activesupport (= 7.0.0)
14
+ rack (~> 2.0, >= 2.2.0)
15
+ rack-test (>= 0.6.3)
16
+ rails-dom-testing (~> 2.0)
17
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
18
+ actionview (7.0.0)
19
+ activesupport (= 7.0.0)
20
+ builder (~> 3.1)
21
+ erubi (~> 1.4)
22
+ rails-dom-testing (~> 2.0)
23
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
24
+ activesupport (7.0.0)
25
+ concurrent-ruby (~> 1.0, >= 1.0.2)
26
+ i18n (>= 1.6, < 2)
27
+ minitest (>= 5.1)
28
+ tzinfo (~> 2.0)
29
+ appraisal (2.5.0)
30
+ bundler
31
+ rake
32
+ thor (>= 0.14.0)
33
+ builder (3.2.4)
34
+ concurrent-ruby (1.2.2)
35
+ crass (1.0.6)
36
+ debug (1.9.1)
37
+ irb (~> 1.10)
38
+ reline (>= 0.3.8)
39
+ diff-lcs (1.5.0)
40
+ docile (1.4.0)
41
+ dry-configurable (1.0.1)
42
+ dry-core (~> 1.0, < 2)
43
+ zeitwerk (~> 2.6)
44
+ dry-core (1.0.0)
45
+ concurrent-ruby (~> 1.0)
46
+ zeitwerk (~> 2.6)
47
+ dry-inflector (1.0.0)
48
+ dry-initializer (3.1.1)
49
+ dry-logic (1.5.0)
50
+ concurrent-ruby (~> 1.0)
51
+ dry-core (~> 1.0, < 2)
52
+ zeitwerk (~> 2.6)
53
+ dry-schema (1.13.3)
54
+ concurrent-ruby (~> 1.0)
55
+ dry-configurable (~> 1.0, >= 1.0.1)
56
+ dry-core (~> 1.0, < 2)
57
+ dry-initializer (~> 3.0)
58
+ dry-logic (>= 1.4, < 2)
59
+ dry-types (>= 1.7, < 2)
60
+ zeitwerk (~> 2.6)
61
+ dry-types (1.7.1)
62
+ concurrent-ruby (~> 1.0)
63
+ dry-core (~> 1.0)
64
+ dry-inflector (~> 1.0)
65
+ dry-logic (~> 1.4)
66
+ zeitwerk (~> 2.6)
67
+ dry-validation (1.10.0)
68
+ concurrent-ruby (~> 1.0)
69
+ dry-core (~> 1.0, < 2)
70
+ dry-initializer (~> 3.0)
71
+ dry-schema (>= 1.12, < 2)
72
+ zeitwerk (~> 2.6)
73
+ erubi (1.12.0)
74
+ i18n (1.14.1)
75
+ concurrent-ruby (~> 1.0)
76
+ interactor (3.1.2)
77
+ interactor-contracts (0.3.0)
78
+ dry-validation (~> 1.0)
79
+ interactor (~> 3)
80
+ io-console (0.7.1)
81
+ irb (1.11.0)
82
+ rdoc
83
+ reline (>= 0.3.8)
84
+ loofah (2.22.0)
85
+ crass (~> 1.0.2)
86
+ nokogiri (>= 1.12.0)
87
+ method_source (1.0.0)
88
+ mini_portile2 (2.8.5)
89
+ minitest (5.20.0)
90
+ nokogiri (1.15.5)
91
+ mini_portile2 (~> 2.8.2)
92
+ racc (~> 1.4)
93
+ psych (5.1.2)
94
+ stringio
95
+ racc (1.7.3)
96
+ rack (2.2.8)
97
+ rack-test (2.1.0)
98
+ rack (>= 1.3)
99
+ rails-dom-testing (2.2.0)
100
+ activesupport (>= 5.0.0)
101
+ minitest
102
+ nokogiri (>= 1.6)
103
+ rails-html-sanitizer (1.6.0)
104
+ loofah (~> 2.21)
105
+ nokogiri (~> 1.14)
106
+ railties (7.0.0)
107
+ actionpack (= 7.0.0)
108
+ activesupport (= 7.0.0)
109
+ method_source
110
+ rake (>= 12.2)
111
+ thor (~> 1.0)
112
+ zeitwerk (~> 2.5)
113
+ rake (13.1.0)
114
+ rdoc (6.6.2)
115
+ psych (>= 4.0.0)
116
+ reline (0.4.1)
117
+ io-console (~> 0.5)
118
+ rspec (3.12.0)
119
+ rspec-core (~> 3.12.0)
120
+ rspec-expectations (~> 3.12.0)
121
+ rspec-mocks (~> 3.12.0)
122
+ rspec-core (3.12.2)
123
+ rspec-support (~> 3.12.0)
124
+ rspec-expectations (3.12.3)
125
+ diff-lcs (>= 1.2.0, < 2.0)
126
+ rspec-support (~> 3.12.0)
127
+ rspec-mocks (3.12.6)
128
+ diff-lcs (>= 1.2.0, < 2.0)
129
+ rspec-support (~> 3.12.0)
130
+ rspec-support (3.12.1)
131
+ simplecov (0.22.0)
132
+ docile (~> 1.1)
133
+ simplecov-html (~> 0.11)
134
+ simplecov_json_formatter (~> 0.1)
135
+ simplecov-html (0.12.3)
136
+ simplecov_json_formatter (0.1.4)
137
+ stringio (3.1.0)
138
+ thor (1.3.0)
139
+ tzinfo (2.0.6)
140
+ concurrent-ruby (~> 1.0)
141
+ zeitwerk (2.6.12)
142
+
143
+ PLATFORMS
144
+ ruby
145
+
146
+ DEPENDENCIES
147
+ appraisal
148
+ bundler (~> 2.0)
149
+ debug
150
+ interactify!
151
+ railties (= 7)
152
+ rake (~> 13.0)
153
+ rspec (~> 3.0)
154
+ simplecov
155
+
156
+ BUNDLED WITH
157
+ 2.4.22
@@ -0,0 +1,18 @@
1
+ # This file was generated by Appraisal
2
+
3
+ source "https://rubygems.org"
4
+
5
+ gem "rake", "~> 13.0"
6
+ gem "railties", "7"
7
+ gem "sidekiq", "7"
8
+
9
+ group :development do
10
+ gem "bundler", "~> 2.0"
11
+ end
12
+
13
+ group :test do
14
+ gem "simplecov", require: false
15
+ gem "rspec", "~> 3.0"
16
+ end
17
+
18
+ gemspec path: "../"
@@ -0,0 +1,166 @@
1
+ PATH
2
+ remote: ..
3
+ specs:
4
+ interactify (0.3.0.pre.alpha.2)
5
+ interactor
6
+ interactor-contracts
7
+
8
+ GEM
9
+ remote: https://rubygems.org/
10
+ specs:
11
+ actionpack (7.0.0)
12
+ actionview (= 7.0.0)
13
+ activesupport (= 7.0.0)
14
+ rack (~> 2.0, >= 2.2.0)
15
+ rack-test (>= 0.6.3)
16
+ rails-dom-testing (~> 2.0)
17
+ rails-html-sanitizer (~> 1.0, >= 1.2.0)
18
+ actionview (7.0.0)
19
+ activesupport (= 7.0.0)
20
+ builder (~> 3.1)
21
+ erubi (~> 1.4)
22
+ rails-dom-testing (~> 2.0)
23
+ rails-html-sanitizer (~> 1.1, >= 1.2.0)
24
+ activesupport (7.0.0)
25
+ concurrent-ruby (~> 1.0, >= 1.0.2)
26
+ i18n (>= 1.6, < 2)
27
+ minitest (>= 5.1)
28
+ tzinfo (~> 2.0)
29
+ appraisal (2.5.0)
30
+ bundler
31
+ rake
32
+ thor (>= 0.14.0)
33
+ builder (3.2.4)
34
+ concurrent-ruby (1.2.2)
35
+ connection_pool (2.4.1)
36
+ crass (1.0.6)
37
+ debug (1.9.1)
38
+ irb (~> 1.10)
39
+ reline (>= 0.3.8)
40
+ diff-lcs (1.5.0)
41
+ docile (1.4.0)
42
+ dry-configurable (1.0.1)
43
+ dry-core (~> 1.0, < 2)
44
+ zeitwerk (~> 2.6)
45
+ dry-core (1.0.0)
46
+ concurrent-ruby (~> 1.0)
47
+ zeitwerk (~> 2.6)
48
+ dry-inflector (1.0.0)
49
+ dry-initializer (3.1.1)
50
+ dry-logic (1.5.0)
51
+ concurrent-ruby (~> 1.0)
52
+ dry-core (~> 1.0, < 2)
53
+ zeitwerk (~> 2.6)
54
+ dry-schema (1.13.3)
55
+ concurrent-ruby (~> 1.0)
56
+ dry-configurable (~> 1.0, >= 1.0.1)
57
+ dry-core (~> 1.0, < 2)
58
+ dry-initializer (~> 3.0)
59
+ dry-logic (>= 1.4, < 2)
60
+ dry-types (>= 1.7, < 2)
61
+ zeitwerk (~> 2.6)
62
+ dry-types (1.7.1)
63
+ concurrent-ruby (~> 1.0)
64
+ dry-core (~> 1.0)
65
+ dry-inflector (~> 1.0)
66
+ dry-logic (~> 1.4)
67
+ zeitwerk (~> 2.6)
68
+ dry-validation (1.10.0)
69
+ concurrent-ruby (~> 1.0)
70
+ dry-core (~> 1.0, < 2)
71
+ dry-initializer (~> 3.0)
72
+ dry-schema (>= 1.12, < 2)
73
+ zeitwerk (~> 2.6)
74
+ erubi (1.12.0)
75
+ i18n (1.14.1)
76
+ concurrent-ruby (~> 1.0)
77
+ interactor (3.1.2)
78
+ interactor-contracts (0.3.0)
79
+ dry-validation (~> 1.0)
80
+ interactor (~> 3)
81
+ io-console (0.7.1)
82
+ irb (1.11.0)
83
+ rdoc
84
+ reline (>= 0.3.8)
85
+ loofah (2.22.0)
86
+ crass (~> 1.0.2)
87
+ nokogiri (>= 1.12.0)
88
+ method_source (1.0.0)
89
+ mini_portile2 (2.8.5)
90
+ minitest (5.20.0)
91
+ nokogiri (1.15.5)
92
+ mini_portile2 (~> 2.8.2)
93
+ racc (~> 1.4)
94
+ psych (5.1.2)
95
+ stringio
96
+ racc (1.7.3)
97
+ rack (2.2.8)
98
+ rack-test (2.1.0)
99
+ rack (>= 1.3)
100
+ rails-dom-testing (2.2.0)
101
+ activesupport (>= 5.0.0)
102
+ minitest
103
+ nokogiri (>= 1.6)
104
+ rails-html-sanitizer (1.6.0)
105
+ loofah (~> 2.21)
106
+ nokogiri (~> 1.14)
107
+ railties (7.0.0)
108
+ actionpack (= 7.0.0)
109
+ activesupport (= 7.0.0)
110
+ method_source
111
+ rake (>= 12.2)
112
+ thor (~> 1.0)
113
+ zeitwerk (~> 2.5)
114
+ rake (13.1.0)
115
+ rdoc (6.6.2)
116
+ psych (>= 4.0.0)
117
+ redis-client (0.19.1)
118
+ connection_pool
119
+ reline (0.4.1)
120
+ io-console (~> 0.5)
121
+ rspec (3.12.0)
122
+ rspec-core (~> 3.12.0)
123
+ rspec-expectations (~> 3.12.0)
124
+ rspec-mocks (~> 3.12.0)
125
+ rspec-core (3.12.2)
126
+ rspec-support (~> 3.12.0)
127
+ rspec-expectations (3.12.3)
128
+ diff-lcs (>= 1.2.0, < 2.0)
129
+ rspec-support (~> 3.12.0)
130
+ rspec-mocks (3.12.6)
131
+ diff-lcs (>= 1.2.0, < 2.0)
132
+ rspec-support (~> 3.12.0)
133
+ rspec-support (3.12.1)
134
+ sidekiq (7.0.0)
135
+ concurrent-ruby (< 2)
136
+ connection_pool (>= 2.3.0)
137
+ rack (>= 2.2.4)
138
+ redis-client (>= 0.9.0)
139
+ simplecov (0.22.0)
140
+ docile (~> 1.1)
141
+ simplecov-html (~> 0.11)
142
+ simplecov_json_formatter (~> 0.1)
143
+ simplecov-html (0.12.3)
144
+ simplecov_json_formatter (0.1.4)
145
+ stringio (3.1.0)
146
+ thor (1.3.0)
147
+ tzinfo (2.0.6)
148
+ concurrent-ruby (~> 1.0)
149
+ zeitwerk (2.6.12)
150
+
151
+ PLATFORMS
152
+ ruby
153
+
154
+ DEPENDENCIES
155
+ appraisal
156
+ bundler (~> 2.0)
157
+ debug
158
+ interactify!
159
+ railties (= 7)
160
+ rake (~> 13.0)
161
+ rspec (~> 3.0)
162
+ sidekiq (= 7)
163
+ simplecov
164
+
165
+ BUNDLED WITH
166
+ 2.4.22
@@ -0,0 +1,61 @@
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,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Interactify
2
4
  module CallWrapper
3
5
  # https://github.com/collectiveidea/interactor/blob/57b2af9a5a5afeb2c01059c40b792485cc21b052/lib/interactor.rb#L114
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Interactify
4
+ class ContractFailure < ::Interactor::Failure
5
+ end
6
+ end
@@ -1,6 +1,9 @@
1
- require 'interactify/jobable'
2
- require 'interactify/call_wrapper'
3
- require 'interactify/organizer_call_monkey_patch'
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/jobable"
4
+ require "interactify/call_wrapper"
5
+ require "interactify/organizer"
6
+ require "interactify/contract_failure"
4
7
 
5
8
  module Interactify
6
9
  module ContractHelpers
@@ -39,16 +42,13 @@ module Interactify
39
42
  end
40
43
  end
41
44
 
42
- class ContractFailure < ::Interactor::Failure
43
- end
44
-
45
45
  included do
46
46
  c = Class.new(ContractFailure)
47
- # example self is Shopkeeper::Fetch
48
- # failure class: Shopkeeper::Fetch::InteractorContractFailure
49
- const_set 'InteractorContractFailure', c
47
+ # example self is Whatever::SomeInteractor
48
+ # failure class: Whatever::SomeInteractor::InteractorContractFailure
49
+ const_set "InteractorContractFailure", c
50
50
  prepend CallWrapper
51
- include OrganizerCallMonkeyPatch if ancestors.include? Interactor::Organizer
51
+ include Organizer
52
52
 
53
53
  on_breach do |breaches|
54
54
  breaches = breaches.map { |b| { b.property => b.messages } }.inject(&:merge)
@@ -1,5 +1,8 @@
1
- require 'interactify/each_chain'
2
- require 'interactify/if_interactor'
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/each_chain"
4
+ require "interactify/if_interactor"
5
+ require "interactify/unique_klass_name"
3
6
 
4
7
  module Interactify
5
8
  module Dsl
@@ -61,6 +64,7 @@ module Interactify
61
64
 
62
65
  # attach the class to the calling namespace
63
66
  where_to_attach = self.binding.receiver
67
+ klass_name = UniqueKlassName.for(where_to_attach, klass_name)
64
68
  where_to_attach.const_set(klass_name, klass)
65
69
  end
66
70
  end
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/unique_klass_name"
4
+
1
5
  module Interactify
2
6
  class EachChain
3
7
  attr_reader :each_loop_klasses, :plural_resource_name, :evaluating_receiver
@@ -36,7 +40,7 @@ module Interactify
36
40
  context[this.singular_resource_name] = resource # context.package = package
37
41
  context[this.singular_resource_index_name] = index # context.package_index = index
38
42
 
39
- klasses = self.class.wrap_lambdas_in_interactors(this.each_loop_klasses)
43
+ klasses = InteractorWrapper.wrap_many(self, this.each_loop_klasses)
40
44
 
41
45
  klasses.each do |interactor| # [A, B, C].each do |interactor|
42
46
  interactor.call!(context) # interactor.call!(context)
@@ -57,8 +61,10 @@ module Interactify
57
61
  # rubocop:enable all
58
62
 
59
63
  def attach_klass
60
- namespace.const_set(iterator_klass_name, klass)
61
- namespace.const_get(iterator_klass_name)
64
+ name = iterator_klass_name
65
+
66
+ namespace.const_set(name, klass)
67
+ namespace.const_get(name)
62
68
  end
63
69
 
64
70
  def namespace
@@ -66,7 +72,9 @@ module Interactify
66
72
  end
67
73
 
68
74
  def iterator_klass_name
69
- :"Each#{singular_resource_name.to_s.camelize}".to_sym
75
+ prefix = "Each#{singular_resource_name.to_s.camelize}"
76
+
77
+ UniqueKlassName.for(namespace, prefix)
70
78
  end
71
79
 
72
80
  def singular_resource_name
@@ -1,3 +1,7 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/unique_klass_name"
4
+
1
5
  module Interactify
2
6
  class IfInteractor
3
7
  attr_reader :condition, :success_interactor, :failure_interactor, :evaluating_receiver
@@ -47,8 +51,9 @@ module Interactify
47
51
  # rubocop:enable all
48
52
 
49
53
  def attach_klass
50
- namespace.const_set(if_klass_name, klass)
51
- namespace.const_get(if_klass_name)
54
+ name = if_klass_name
55
+ namespace.const_set(name, klass)
56
+ namespace.const_get(name)
52
57
  end
53
58
 
54
59
  def namespace
@@ -56,9 +61,10 @@ module Interactify
56
61
  end
57
62
 
58
63
  def if_klass_name
59
- name = condition.is_a?(Proc) ? 'Proc' : condition
64
+ prefix = condition.is_a?(Proc) ? "Proc" : condition
65
+ prefix = "If#{prefix.to_s.camelize}"
60
66
 
61
- "If#{name.to_s.camelize}".to_sym
67
+ UniqueKlassName.for(namespace, prefix)
62
68
  end
63
69
  end
64
70
  end
@@ -0,0 +1,79 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "interactify/interactor_wiring/error_context"
4
+
5
+ module Interactify
6
+ class InteractorWiring
7
+ class CallableRepresentation
8
+ attr_reader :filename, :klass, :wiring
9
+
10
+ delegate :interactor_lookup, to: :wiring
11
+
12
+ def initialize(filename:, klass:, wiring:)
13
+ @filename = filename
14
+ @klass = klass
15
+ @wiring = wiring
16
+ end
17
+
18
+ def validate_callable(error_context: ErrorContext.new)
19
+ if organizer?
20
+ assign_previously_defined(error_context:)
21
+ validate_children(error_context:)
22
+ end
23
+
24
+ validate_self(error_context:)
25
+ end
26
+
27
+ def expected_keys
28
+ klass.respond_to?(:expected_keys) ? Array(klass.expected_keys) : []
29
+ end
30
+
31
+ def promised_keys
32
+ klass.respond_to?(:promised_keys) ? Array(klass.promised_keys) : []
33
+ end
34
+
35
+ def all_keys
36
+ expected_keys.concat(promised_keys)
37
+ end
38
+
39
+ def inspect
40
+ "#<#{self.class.name}#{object_id} @filename=#{filename}, @klass=#{klass.name}>"
41
+ end
42
+
43
+ def organizer?
44
+ klass.respond_to?(:organized) && klass.organized.any?
45
+ end
46
+
47
+ def assign_previously_defined(error_context:)
48
+ return unless contract?
49
+
50
+ error_context.append_previously_defined_keys(all_keys)
51
+ end
52
+
53
+ def validate_children(error_context:)
54
+ klass.organized.each do |interactor|
55
+ interactor_as_callable = interactor_lookup[interactor]
56
+ next if interactor_as_callable.nil?
57
+
58
+ error_context = interactor_as_callable.validate_callable(error_context:)
59
+ end
60
+
61
+ error_context
62
+ end
63
+
64
+ private
65
+
66
+ def contract?
67
+ klass.ancestors.include? Interactor::Contracts
68
+ end
69
+
70
+ def validate_self(error_context:)
71
+ return error_context unless contract?
72
+
73
+ error_context.infer_missing_keys(self)
74
+ error_context.add_promised_keys(promised_keys)
75
+ error_context
76
+ end
77
+ end
78
+ end
79
+ end