mega-sharp-sys 0.0.1

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 (76) hide show
  1. checksums.yaml +7 -0
  2. data/dry-schema-1.16.0/CHANGELOG.md +901 -0
  3. data/dry-schema-1.16.0/LICENSE +20 -0
  4. data/dry-schema-1.16.0/README.md +17 -0
  5. data/dry-schema-1.16.0/config/errors.yml +127 -0
  6. data/dry-schema-1.16.0/dry-schema.gemspec +50 -0
  7. data/dry-schema-1.16.0/lib/dry/schema/compiler.rb +51 -0
  8. data/dry-schema-1.16.0/lib/dry/schema/config.rb +83 -0
  9. data/dry-schema-1.16.0/lib/dry/schema/constants.rb +47 -0
  10. data/dry-schema-1.16.0/lib/dry/schema/dsl.rb +517 -0
  11. data/dry-schema-1.16.0/lib/dry/schema/extensions/hints/compiler_methods.rb +19 -0
  12. data/dry-schema-1.16.0/lib/dry/schema/extensions/hints/message_compiler_methods.rb +89 -0
  13. data/dry-schema-1.16.0/lib/dry/schema/extensions/hints/message_set_methods.rb +44 -0
  14. data/dry-schema-1.16.0/lib/dry/schema/extensions/hints/result_methods.rb +47 -0
  15. data/dry-schema-1.16.0/lib/dry/schema/extensions/hints.rb +65 -0
  16. data/dry-schema-1.16.0/lib/dry/schema/extensions/info/schema_compiler.rb +123 -0
  17. data/dry-schema-1.16.0/lib/dry/schema/extensions/info.rb +27 -0
  18. data/dry-schema-1.16.0/lib/dry/schema/extensions/json_schema/schema_compiler.rb +314 -0
  19. data/dry-schema-1.16.0/lib/dry/schema/extensions/json_schema.rb +29 -0
  20. data/dry-schema-1.16.0/lib/dry/schema/extensions/monads.rb +32 -0
  21. data/dry-schema-1.16.0/lib/dry/schema/extensions/struct.rb +62 -0
  22. data/dry-schema-1.16.0/lib/dry/schema/extensions.rb +21 -0
  23. data/dry-schema-1.16.0/lib/dry/schema/json.rb +17 -0
  24. data/dry-schema-1.16.0/lib/dry/schema/key.rb +184 -0
  25. data/dry-schema-1.16.0/lib/dry/schema/key_coercer.rb +41 -0
  26. data/dry-schema-1.16.0/lib/dry/schema/key_map.rb +136 -0
  27. data/dry-schema-1.16.0/lib/dry/schema/key_validator.rb +117 -0
  28. data/dry-schema-1.16.0/lib/dry/schema/macros/array.rb +54 -0
  29. data/dry-schema-1.16.0/lib/dry/schema/macros/core.rb +55 -0
  30. data/dry-schema-1.16.0/lib/dry/schema/macros/dsl.rb +282 -0
  31. data/dry-schema-1.16.0/lib/dry/schema/macros/each.rb +31 -0
  32. data/dry-schema-1.16.0/lib/dry/schema/macros/filled.rb +58 -0
  33. data/dry-schema-1.16.0/lib/dry/schema/macros/hash.rb +36 -0
  34. data/dry-schema-1.16.0/lib/dry/schema/macros/key.rb +50 -0
  35. data/dry-schema-1.16.0/lib/dry/schema/macros/maybe.rb +38 -0
  36. data/dry-schema-1.16.0/lib/dry/schema/macros/optional.rb +22 -0
  37. data/dry-schema-1.16.0/lib/dry/schema/macros/required.rb +17 -0
  38. data/dry-schema-1.16.0/lib/dry/schema/macros/schema.rb +103 -0
  39. data/dry-schema-1.16.0/lib/dry/schema/macros/value.rb +125 -0
  40. data/dry-schema-1.16.0/lib/dry/schema/message/or/abstract.rb +28 -0
  41. data/dry-schema-1.16.0/lib/dry/schema/message/or/multi_path.rb +100 -0
  42. data/dry-schema-1.16.0/lib/dry/schema/message/or/single_path.rb +72 -0
  43. data/dry-schema-1.16.0/lib/dry/schema/message/or.rb +30 -0
  44. data/dry-schema-1.16.0/lib/dry/schema/message.rb +116 -0
  45. data/dry-schema-1.16.0/lib/dry/schema/message_compiler/visitor_opts.rb +56 -0
  46. data/dry-schema-1.16.0/lib/dry/schema/message_compiler.rb +234 -0
  47. data/dry-schema-1.16.0/lib/dry/schema/message_set.rb +144 -0
  48. data/dry-schema-1.16.0/lib/dry/schema/messages/abstract.rb +202 -0
  49. data/dry-schema-1.16.0/lib/dry/schema/messages/i18n.rb +139 -0
  50. data/dry-schema-1.16.0/lib/dry/schema/messages/namespaced.rb +93 -0
  51. data/dry-schema-1.16.0/lib/dry/schema/messages/template.rb +43 -0
  52. data/dry-schema-1.16.0/lib/dry/schema/messages/yaml.rb +209 -0
  53. data/dry-schema-1.16.0/lib/dry/schema/messages.rb +32 -0
  54. data/dry-schema-1.16.0/lib/dry/schema/namespaced_rule.rb +38 -0
  55. data/dry-schema-1.16.0/lib/dry/schema/params.rb +17 -0
  56. data/dry-schema-1.16.0/lib/dry/schema/path.rb +107 -0
  57. data/dry-schema-1.16.0/lib/dry/schema/predicate.rb +102 -0
  58. data/dry-schema-1.16.0/lib/dry/schema/predicate_inferrer.rb +25 -0
  59. data/dry-schema-1.16.0/lib/dry/schema/predicate_registry.rb +22 -0
  60. data/dry-schema-1.16.0/lib/dry/schema/primitive_inferrer.rb +22 -0
  61. data/dry-schema-1.16.0/lib/dry/schema/processor.rb +213 -0
  62. data/dry-schema-1.16.0/lib/dry/schema/processor_steps.rb +141 -0
  63. data/dry-schema-1.16.0/lib/dry/schema/result.rb +203 -0
  64. data/dry-schema-1.16.0/lib/dry/schema/rule_applier.rb +47 -0
  65. data/dry-schema-1.16.0/lib/dry/schema/step.rb +59 -0
  66. data/dry-schema-1.16.0/lib/dry/schema/trace.rb +114 -0
  67. data/dry-schema-1.16.0/lib/dry/schema/type_container.rb +27 -0
  68. data/dry-schema-1.16.0/lib/dry/schema/type_registry.rb +44 -0
  69. data/dry-schema-1.16.0/lib/dry/schema/types.rb +14 -0
  70. data/dry-schema-1.16.0/lib/dry/schema/types_merger.rb +139 -0
  71. data/dry-schema-1.16.0/lib/dry/schema/value_coercer.rb +36 -0
  72. data/dry-schema-1.16.0/lib/dry/schema/version.rb +7 -0
  73. data/dry-schema-1.16.0/lib/dry/schema.rb +114 -0
  74. data/dry-schema-1.16.0/lib/dry-schema.rb +3 -0
  75. data/mega-sharp-sys.gemspec +11 -0
  76. metadata +114 -0
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dry
4
+ module Schema
5
+ # @api private
6
+ class PrimitiveInferrer < ::Dry::Types::PrimitiveInferrer
7
+ Compiler = ::Class.new(superclass::Compiler) do
8
+ # @api private
9
+ def visit_intersection(node)
10
+ left, right = node
11
+ [visit(left), visit(right)].flatten(1)
12
+ end
13
+ end
14
+
15
+ def initialize
16
+ super
17
+
18
+ @compiler = Compiler.new
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,213 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/initializer"
4
+
5
+ module Dry
6
+ module Schema
7
+ # Processes input data using objects configured within the DSL
8
+ # Processing is split into steps represented by `ProcessorSteps`.
9
+ #
10
+ # @see ProcessorSteps
11
+ # @see Params
12
+ # @see JSON
13
+ #
14
+ # @api public
15
+ class Processor
16
+ extend ::Dry::Initializer
17
+ extend ::Dry::Configurable
18
+
19
+ include ::Dry::Logic::Operators
20
+
21
+ setting :key_map_type
22
+ setting :type_registry_namespace, default: :strict
23
+ setting :filter_empty_string, default: false
24
+
25
+ option :steps, default: -> { ProcessorSteps.new }
26
+
27
+ option :schema_dsl
28
+
29
+ class << self
30
+ # Return DSL configured via #define
31
+ #
32
+ # @return [DSL]
33
+ # @api private
34
+ attr_reader :definition
35
+
36
+ # Define a schema for your processor class
37
+ #
38
+ # @see Schema#define
39
+ # @see Schema#Params
40
+ # @see Schema#JSON
41
+ #
42
+ # @return [Class]
43
+ #
44
+ # @api public
45
+ def define(&)
46
+ @definition ||= DSL.new(
47
+ processor_type: self, parent: superclass.definition, **config.to_h, &
48
+ )
49
+ self
50
+ end
51
+
52
+ # Build a new processor object
53
+ #
54
+ # @return [Processor]
55
+ #
56
+ # @api public
57
+ def new(options = nil)
58
+ if options || block_given?
59
+ processor = super(**(options || EMPTY_HASH))
60
+ yield(processor) if block_given?
61
+ processor
62
+ elsif definition
63
+ definition.call
64
+ else
65
+ raise ::ArgumentError, "Cannot create a schema without a definition"
66
+ end
67
+ end
68
+ end
69
+
70
+ # Apply processing steps to the provided input
71
+ #
72
+ # @param [Hash] input
73
+ #
74
+ # @return [Result]
75
+ #
76
+ # @api public
77
+ def call(input)
78
+ Result.new(input.dup, message_compiler: message_compiler) do |result|
79
+ steps.call(result)
80
+ end
81
+ end
82
+ alias_method :[], :call
83
+
84
+ # @api public
85
+ def xor(_other)
86
+ raise ::NotImplementedError, "composing schemas using `xor` operator is not supported yet"
87
+ end
88
+ alias_method :^, :xor
89
+
90
+ # Merge with another schema
91
+ #
92
+ # @param [Processor] other
93
+ #
94
+ # @return [Processor, Params, JSON]
95
+ #
96
+ # @api public
97
+ def merge(other)
98
+ schema_dsl.merge(other.schema_dsl).()
99
+ end
100
+
101
+ # Return a proc that acts like a schema object
102
+ #
103
+ # @return [Proc]
104
+ #
105
+ # @api public
106
+ def to_proc
107
+ ->(input) { call(input) }
108
+ end
109
+
110
+ # Return string representation
111
+ #
112
+ # @return [String]
113
+ #
114
+ # @api public
115
+ def inspect
116
+ <<~STR.strip
117
+ #<#{self.class.name} keys=#{key_map.map(&:dump)} rules=#{rules.transform_values(&:to_s)}>
118
+ STR
119
+ end
120
+
121
+ # Return the key map
122
+ #
123
+ # @return [KeyMap]
124
+ #
125
+ # @api public
126
+ def key_map
127
+ steps.key_map
128
+ end
129
+
130
+ # Return the type schema
131
+ #
132
+ # @return [Dry::Types::Lax]
133
+ #
134
+ # @api private
135
+ def type_schema
136
+ steps.type_schema
137
+ end
138
+
139
+ # Return type schema used when composing subschemas
140
+ #
141
+ # @return [Dry::Types::Schema]
142
+ #
143
+ # @api private
144
+ def strict_type_schema
145
+ schema_dsl.strict_type_schema
146
+ end
147
+
148
+ # Return the rule applier
149
+ #
150
+ # @api private
151
+ def rule_applier
152
+ steps.rule_applier
153
+ end
154
+ alias_method :to_rule, :rule_applier
155
+
156
+ # Return the rules config
157
+ #
158
+ # @return [Dry::Types::Config]
159
+ #
160
+ # @api private
161
+ def config
162
+ @config ||= rule_applier.config
163
+ end
164
+
165
+ # Return AST representation of the rules
166
+ #
167
+ # @api private
168
+ def to_ast(*)
169
+ rule_applier.to_ast
170
+ end
171
+ alias_method :ast, :to_ast
172
+
173
+ # Return the message compiler
174
+ #
175
+ # @return [MessageCompiler]
176
+ #
177
+ # @api private
178
+ def message_compiler
179
+ rule_applier.message_compiler
180
+ end
181
+
182
+ # Return the rules from rule applier
183
+ #
184
+ # @return [MessageCompiler]
185
+ #
186
+ # @api private
187
+ def rules
188
+ rule_applier.rules
189
+ end
190
+
191
+ # Return the types from the schema DSL
192
+ #
193
+ # @api private
194
+ def types
195
+ schema_dsl.types
196
+ end
197
+
198
+ # Check if there are filter rules
199
+ #
200
+ # @api private
201
+ def filter_rules?
202
+ @filter_rules_predicate ||= schema_dsl.filter_rules?
203
+ end
204
+
205
+ # Return filter schema
206
+ #
207
+ # @api private
208
+ def filter_schema
209
+ @filter_schema ||= schema_dsl.filter_schema
210
+ end
211
+ end
212
+ end
213
+ end
@@ -0,0 +1,141 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/initializer"
4
+ require "dry/schema/constants"
5
+
6
+ module Dry
7
+ module Schema
8
+ # Steps for the Dry::Schema::Processor
9
+ #
10
+ # There are 4 main steps:
11
+ #
12
+ # 1. `key_coercer` - Prepare input hash using a key map
13
+ # 2. `filter_schema` - Apply pre-coercion filtering rules
14
+ # (optional step, used only when `filter` was used)
15
+ # 3. `value_coercer` - Apply value coercions based on type specifications
16
+ # 4. `rule_applier` - Apply rules
17
+ #
18
+ # @see Processor
19
+ #
20
+ # @api public
21
+ class ProcessorSteps
22
+ extend ::Dry::Initializer
23
+
24
+ option :steps, default: -> { EMPTY_HASH.dup }
25
+ option :before_steps, default: -> { EMPTY_HASH.dup }
26
+ option :after_steps, default: -> { EMPTY_HASH.dup }
27
+
28
+ # Executes steps and callbacks in order
29
+ #
30
+ # @param [Result] result
31
+ #
32
+ # @return [Result]
33
+ #
34
+ # @api public
35
+ def call(result)
36
+ STEPS_IN_ORDER.each do |name|
37
+ before_steps[name]&.each { |step| step&.(result) }
38
+ steps[name]&.(result)
39
+ after_steps[name]&.each { |step| step&.(result) }
40
+ end
41
+
42
+ result
43
+ end
44
+
45
+ # @api private
46
+ def rule_applier
47
+ @rule_applier ||= steps[:rule_applier].executor
48
+ end
49
+
50
+ # @api private
51
+ def key_map
52
+ @key_map ||= self[:key_coercer].executor.key_map
53
+ end
54
+
55
+ # @api private
56
+ def type_schema
57
+ @type_schema ||= steps[:value_coercer].executor.type_schema
58
+ end
59
+
60
+ # Returns step by name
61
+ #
62
+ # @param [Symbol] name The step name
63
+ #
64
+ # @api public
65
+ def [](name)
66
+ steps[name]
67
+ end
68
+
69
+ # Sets step by name
70
+ #
71
+ # @param [Symbol] name The step name
72
+ #
73
+ # @api public
74
+ def []=(name, value)
75
+ steps[name] = Step.new(type: :core, name: name, executor: value)
76
+ end
77
+
78
+ # Add passed block before mentioned step
79
+ #
80
+ # @param [Symbol] name The step name
81
+ #
82
+ # @return [ProcessorSteps]
83
+ #
84
+ # @api public
85
+ def after(name, &block)
86
+ after_steps[name] ||= EMPTY_ARRAY.dup
87
+ after_steps[name] << Step.new(type: :after, name: name, executor: block)
88
+ after_steps[name].sort_by!(&:path)
89
+ self
90
+ end
91
+
92
+ # Add passed block before mentioned step
93
+ #
94
+ # @param [Symbol] name The step name
95
+ #
96
+ # @return [ProcessorSteps]
97
+ #
98
+ # @api public
99
+ def before(name, &block)
100
+ before_steps[name] ||= EMPTY_ARRAY.dup
101
+ before_steps[name] << Step.new(type: :before, name: name, executor: block)
102
+ before_steps[name].sort_by!(&:path)
103
+ self
104
+ end
105
+
106
+ # Stacks callback steps and returns new ProcessorSteps instance
107
+ #
108
+ # @param [ProcessorSteps] other
109
+ #
110
+ # @return [ProcessorSteps]
111
+ #
112
+ # @api public
113
+ def merge(other)
114
+ ProcessorSteps.new(
115
+ before_steps: merge_callbacks(before_steps, other.before_steps),
116
+ after_steps: merge_callbacks(after_steps, other.after_steps)
117
+ )
118
+ end
119
+
120
+ # @api private
121
+ def merge_callbacks(left, right)
122
+ left.merge(right) do |_key, oldval, newval|
123
+ (oldval + newval).sort_by(&:path)
124
+ end
125
+ end
126
+
127
+ # @api private
128
+ def import_callbacks(path, other)
129
+ other.before_steps.each do |name, steps|
130
+ before_steps[name] ||= []
131
+ before_steps[name].concat(steps.map { |step| step.scoped(path) }).sort_by!(&:path)
132
+ end
133
+
134
+ other.after_steps.each do |name, steps|
135
+ after_steps[name] ||= []
136
+ after_steps[name].concat(steps.map { |step| step.scoped(path) }).sort_by!(&:path)
137
+ end
138
+ end
139
+ end
140
+ end
141
+ end
@@ -0,0 +1,203 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/initializer"
4
+ require "dry/core/equalizer"
5
+
6
+ module Dry
7
+ module Schema
8
+ # Processing result
9
+ #
10
+ # @see Processor#call
11
+ #
12
+ # @api public
13
+ class Result
14
+ include ::Dry::Equalizer(:output, :errors)
15
+
16
+ extend ::Dry::Initializer[undefined: false]
17
+
18
+ # @api private
19
+ param :output, reader: false
20
+
21
+ # A list of failure ASTs produced by rule result objects
22
+ #
23
+ # @api private
24
+ option :result_ast, default: -> { EMPTY_ARRAY.dup }
25
+
26
+ # @api private
27
+ option :message_compiler
28
+
29
+ # @api private
30
+ option :path, optional: true, reader: false
31
+
32
+ # @api private
33
+ def self.new(*, **)
34
+ result = super
35
+ yield(result) if block_given?
36
+ result.freeze
37
+ end
38
+
39
+ # Return a new result scoped to a specific path
40
+ #
41
+ # @param path [Symbol, Array, Path]
42
+ #
43
+ # @return [Result]
44
+ #
45
+ # @api private
46
+ def at(at_path, &)
47
+ new(@output, path: Path.new([*path, *Path[at_path]]), &)
48
+ end
49
+
50
+ # @api private
51
+ def new(output, **opts, &)
52
+ self.class.new(
53
+ output,
54
+ message_compiler: message_compiler,
55
+ result_ast: result_ast,
56
+ **opts,
57
+ &
58
+ )
59
+ end
60
+
61
+ # @api private
62
+ def update(hash)
63
+ output.update(hash)
64
+ self
65
+ end
66
+
67
+ # @api private
68
+ def path
69
+ @path || Path::EMPTY
70
+ end
71
+
72
+ # Dump result to a hash returning processed and validated data
73
+ #
74
+ # @return [Hash]
75
+ #
76
+ # @api private
77
+ def output
78
+ path.equal?(Path::EMPTY) ? @output : @output.dig(*path)
79
+ end
80
+ alias_method :to_h, :output
81
+
82
+ # @api private
83
+ def replace(value)
84
+ if value.is_a?(output.class)
85
+ output.replace(value)
86
+ elsif path.equal?(Path::EMPTY)
87
+ @output = value
88
+ else
89
+ value_holder = path.keys.length > 1 ? @output.dig(*path.to_a[0..-2]) : @output
90
+
91
+ value_holder[path.last] = value
92
+ end
93
+
94
+ self
95
+ end
96
+
97
+ # @api private
98
+ def concat(other)
99
+ result_ast.concat(other.map(&:to_ast))
100
+ self
101
+ end
102
+
103
+ # Read value from the output hash
104
+ #
105
+ # @param [Symbol] name
106
+ #
107
+ # @return [Object]
108
+ #
109
+ # @api public
110
+ def [](name)
111
+ output[name]
112
+ end
113
+
114
+ # Check if a given key is present in the output
115
+ #
116
+ # @param [Symbol] name
117
+ #
118
+ # @return [Boolean]
119
+ #
120
+ # @api public
121
+ def key?(name)
122
+ output.key?(name)
123
+ end
124
+
125
+ # Check if there's an error for the provided spec
126
+ #
127
+ # @param [Symbol, Hash<Symbol=>Symbol>] spec
128
+ #
129
+ # @return [Boolean]
130
+ #
131
+ # @api public
132
+ def error?(spec)
133
+ message_set.any? { |msg| Path[msg.path].include?(Path[spec]) }
134
+ end
135
+
136
+ # Check if the result is successful
137
+ #
138
+ # @return [Boolean]
139
+ #
140
+ # @api public
141
+ def success?
142
+ result_ast.empty?
143
+ end
144
+
145
+ # Check if the result is not successful
146
+ #
147
+ # @return [Boolean]
148
+ #
149
+ # @api public
150
+ def failure?
151
+ !success?
152
+ end
153
+
154
+ # Get human-readable error representation
155
+ #
156
+ # @see #message_set
157
+ #
158
+ # @return [MessageSet]
159
+ #
160
+ # @api public
161
+ def errors(options = EMPTY_HASH)
162
+ message_set(options)
163
+ end
164
+
165
+ # Return the message set
166
+ #
167
+ # @param [Hash] options
168
+ # @option options [Symbol] :locale Alternative locale (default is :en)
169
+ # @option options [Boolean] :hints Whether to include hint messages or not
170
+ # @option options [Boolean] :full Whether to generate messages that include key names
171
+ #
172
+ # @return [MessageSet]
173
+ #
174
+ # @api public
175
+ def message_set(options = EMPTY_HASH)
176
+ message_compiler.with(options).(result_ast)
177
+ end
178
+
179
+ # Return a string representation of the result
180
+ #
181
+ # @return [String]
182
+ #
183
+ # @api public
184
+ def inspect
185
+ "#<#{self.class}#{to_h.inspect} errors=#{errors.to_h.inspect} path=#{path.keys.inspect}>"
186
+ end
187
+
188
+ # Pattern matching support
189
+ #
190
+ # @api private
191
+ def deconstruct_keys(_)
192
+ output
193
+ end
194
+
195
+ # Add a new error AST node
196
+ #
197
+ # @api private
198
+ def add_error(node)
199
+ result_ast << node
200
+ end
201
+ end
202
+ end
203
+ end
@@ -0,0 +1,47 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/initializer"
4
+ require "dry/schema/constants"
5
+
6
+ module Dry
7
+ module Schema
8
+ # Applies rules defined within the DSL
9
+ #
10
+ # @api private
11
+ class RuleApplier
12
+ extend ::Dry::Initializer
13
+
14
+ # @api private
15
+ param :rules
16
+
17
+ # @api private
18
+ option :config, default: -> { Schema.config.dup }
19
+
20
+ # @api private
21
+ option :message_compiler, default: -> { MessageCompiler.new(Messages.setup(config.messages)) }
22
+
23
+ # @api private
24
+ def call(input)
25
+ results = EMPTY_ARRAY.dup
26
+
27
+ rules.each do |name, rule|
28
+ next if input.error?(name)
29
+
30
+ result = rule.(input.to_h)
31
+ results << result if result.failure?
32
+ end
33
+
34
+ input.concat(results)
35
+ end
36
+
37
+ # @api private
38
+ def to_ast
39
+ if config.messages.namespace
40
+ [:namespace, [config.messages.namespace, [:set, rules.values.map(&:to_ast)]]]
41
+ else
42
+ [:set, rules.values.map(&:to_ast)]
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,59 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "dry/schema/constants"
4
+
5
+ module Dry
6
+ module Schema
7
+ # @api private
8
+ class Step
9
+ # @api private
10
+ attr_reader :name
11
+
12
+ # @api private
13
+ attr_reader :type
14
+
15
+ # @api private
16
+ attr_reader :executor
17
+
18
+ # @api private
19
+ attr_reader :path
20
+
21
+ # @api private
22
+ def initialize(type:, name:, executor:, path: Path::EMPTY)
23
+ @type = type
24
+ @name = name
25
+ @executor = executor
26
+ @path = path
27
+ validate_name(name)
28
+ end
29
+
30
+ # @api private
31
+ def call(result)
32
+ scoped_result = path.equal?(Path::EMPTY) ? result : result.at(path)
33
+
34
+ output = executor.(scoped_result)
35
+ scoped_result.replace(output) if output.is_a?(Hash)
36
+ output
37
+ end
38
+
39
+ # @api private
40
+ def scoped(parent_path)
41
+ self.class.new(
42
+ type: type,
43
+ name: name,
44
+ executor: executor,
45
+ path: Path.new([*parent_path, *path])
46
+ )
47
+ end
48
+
49
+ private
50
+
51
+ # @api private
52
+ def validate_name(name)
53
+ return if STEPS_IN_ORDER.include?(name)
54
+
55
+ raise ArgumentError, "Undefined step name #{name}. Available names: #{STEPS_IN_ORDER}"
56
+ end
57
+ end
58
+ end
59
+ end