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

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