nxt_schema 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/Gemfile.lock +3 -3
- data/README.md +80 -38
- data/lib/nxt_schema.rb +17 -17
- data/lib/nxt_schema/dsl.rb +7 -7
- data/lib/nxt_schema/{application.rb → node.rb} +1 -1
- data/lib/nxt_schema/node/any_of.rb +21 -33
- data/lib/nxt_schema/node/base.rb +70 -171
- data/lib/nxt_schema/node/collection.rb +43 -8
- data/lib/nxt_schema/{application → node}/error_store.rb +5 -5
- data/lib/nxt_schema/{application → node}/errors/schema_error.rb +1 -1
- data/lib/nxt_schema/{application → node}/errors/validation_error.rb +1 -1
- data/lib/nxt_schema/node/leaf.rb +7 -5
- data/lib/nxt_schema/node/schema.rb +101 -8
- data/lib/nxt_schema/template/any_of.rb +50 -0
- data/lib/nxt_schema/template/base.rb +218 -0
- data/lib/nxt_schema/template/collection.rb +23 -0
- data/lib/nxt_schema/{node → template}/has_sub_nodes.rb +16 -10
- data/lib/nxt_schema/template/leaf.rb +13 -0
- data/lib/nxt_schema/{node → template}/maybe_evaluator.rb +1 -1
- data/lib/nxt_schema/{node → template}/on_evaluator.rb +1 -1
- data/lib/nxt_schema/template/schema.rb +22 -0
- data/lib/nxt_schema/{node → template}/sub_nodes.rb +1 -1
- data/lib/nxt_schema/{node → template}/type_resolver.rb +2 -2
- data/lib/nxt_schema/{node → template}/type_system_resolver.rb +1 -1
- data/lib/nxt_schema/version.rb +1 -1
- metadata +17 -17
- data/lib/nxt_schema/application/any_of.rb +0 -40
- data/lib/nxt_schema/application/base.rb +0 -116
- data/lib/nxt_schema/application/collection.rb +0 -57
- data/lib/nxt_schema/application/leaf.rb +0 -15
- data/lib/nxt_schema/application/schema.rb +0 -114
data/lib/nxt_schema/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nxt_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Robecke
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-12-03 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -155,32 +155,32 @@ files:
|
|
155
155
|
- bin/console
|
156
156
|
- bin/setup
|
157
157
|
- lib/nxt_schema.rb
|
158
|
-
- lib/nxt_schema/application.rb
|
159
|
-
- lib/nxt_schema/application/any_of.rb
|
160
|
-
- lib/nxt_schema/application/base.rb
|
161
|
-
- lib/nxt_schema/application/collection.rb
|
162
|
-
- lib/nxt_schema/application/error_store.rb
|
163
|
-
- lib/nxt_schema/application/errors/schema_error.rb
|
164
|
-
- lib/nxt_schema/application/errors/validation_error.rb
|
165
|
-
- lib/nxt_schema/application/leaf.rb
|
166
|
-
- lib/nxt_schema/application/schema.rb
|
167
158
|
- lib/nxt_schema/callable.rb
|
168
159
|
- lib/nxt_schema/dsl.rb
|
169
160
|
- lib/nxt_schema/error.rb
|
170
161
|
- lib/nxt_schema/errors/invalid.rb
|
171
162
|
- lib/nxt_schema/errors/invalid_options.rb
|
172
163
|
- lib/nxt_schema/missing_input.rb
|
164
|
+
- lib/nxt_schema/node.rb
|
173
165
|
- lib/nxt_schema/node/any_of.rb
|
174
166
|
- lib/nxt_schema/node/base.rb
|
175
167
|
- lib/nxt_schema/node/collection.rb
|
176
|
-
- lib/nxt_schema/node/
|
168
|
+
- lib/nxt_schema/node/error_store.rb
|
169
|
+
- lib/nxt_schema/node/errors/schema_error.rb
|
170
|
+
- lib/nxt_schema/node/errors/validation_error.rb
|
177
171
|
- lib/nxt_schema/node/leaf.rb
|
178
|
-
- lib/nxt_schema/node/maybe_evaluator.rb
|
179
|
-
- lib/nxt_schema/node/on_evaluator.rb
|
180
172
|
- lib/nxt_schema/node/schema.rb
|
181
|
-
- lib/nxt_schema/
|
182
|
-
- lib/nxt_schema/
|
183
|
-
- lib/nxt_schema/
|
173
|
+
- lib/nxt_schema/template/any_of.rb
|
174
|
+
- lib/nxt_schema/template/base.rb
|
175
|
+
- lib/nxt_schema/template/collection.rb
|
176
|
+
- lib/nxt_schema/template/has_sub_nodes.rb
|
177
|
+
- lib/nxt_schema/template/leaf.rb
|
178
|
+
- lib/nxt_schema/template/maybe_evaluator.rb
|
179
|
+
- lib/nxt_schema/template/on_evaluator.rb
|
180
|
+
- lib/nxt_schema/template/schema.rb
|
181
|
+
- lib/nxt_schema/template/sub_nodes.rb
|
182
|
+
- lib/nxt_schema/template/type_resolver.rb
|
183
|
+
- lib/nxt_schema/template/type_system_resolver.rb
|
184
184
|
- lib/nxt_schema/types.rb
|
185
185
|
- lib/nxt_schema/validators/attribute.rb
|
186
186
|
- lib/nxt_schema/validators/equal_to.rb
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Application
|
3
|
-
class AnyOf < Application::Base
|
4
|
-
def valid?
|
5
|
-
valid_application.present?
|
6
|
-
end
|
7
|
-
|
8
|
-
def call
|
9
|
-
# TODO: We should check that this is not empty!
|
10
|
-
child_applications.map(&:call)
|
11
|
-
|
12
|
-
if valid?
|
13
|
-
self.output = valid_application.output
|
14
|
-
else
|
15
|
-
child_applications.each do |application|
|
16
|
-
merge_errors(application)
|
17
|
-
end
|
18
|
-
end
|
19
|
-
|
20
|
-
self
|
21
|
-
end
|
22
|
-
|
23
|
-
private
|
24
|
-
|
25
|
-
delegate :[], to: :child_applications
|
26
|
-
|
27
|
-
def valid_application
|
28
|
-
child_applications.find(&:valid?)
|
29
|
-
end
|
30
|
-
|
31
|
-
def child_applications
|
32
|
-
@child_applications ||= nodes.map { |node| node.build_application(input: input, context: context, parent: self) }
|
33
|
-
end
|
34
|
-
|
35
|
-
def nodes
|
36
|
-
@nodes ||= node.sub_nodes.values
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
40
|
-
end
|
@@ -1,116 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Application
|
3
|
-
class Base
|
4
|
-
def initialize(node:, input: MissingInput.new, parent:, context:, error_key:)
|
5
|
-
@node = node
|
6
|
-
@input = input
|
7
|
-
@parent = parent
|
8
|
-
@output = nil
|
9
|
-
@error_key = error_key
|
10
|
-
@context = context || parent&.context
|
11
|
-
@applied = false
|
12
|
-
@applied_nodes = parent&.applied_nodes || []
|
13
|
-
@is_root = parent.nil?
|
14
|
-
@root = parent.nil? ? self : parent.root
|
15
|
-
@errors = ErrorStore.new(self)
|
16
|
-
@locale = node.options.fetch(:locale) { parent&.locale || 'en' }.to_s
|
17
|
-
|
18
|
-
@index = error_key
|
19
|
-
resolve_error_key(error_key)
|
20
|
-
end
|
21
|
-
|
22
|
-
attr_accessor :output, :node, :input
|
23
|
-
attr_reader :parent, :context, :error_key, :applied, :applied_nodes, :root, :errors, :locale, :index
|
24
|
-
|
25
|
-
def call
|
26
|
-
raise NotImplementedError, 'Implement this in our sub class'
|
27
|
-
end
|
28
|
-
|
29
|
-
delegate :name, :options, to: :node
|
30
|
-
|
31
|
-
def root?
|
32
|
-
@is_root
|
33
|
-
end
|
34
|
-
|
35
|
-
def valid?
|
36
|
-
errors.empty?
|
37
|
-
end
|
38
|
-
|
39
|
-
def add_error(error)
|
40
|
-
errors.add_validation_error(message: error)
|
41
|
-
end
|
42
|
-
|
43
|
-
def add_schema_error(error)
|
44
|
-
errors.add_schema_error(message: error)
|
45
|
-
end
|
46
|
-
|
47
|
-
def merge_errors(application)
|
48
|
-
errors.merge_errors(application)
|
49
|
-
end
|
50
|
-
|
51
|
-
def run_validations
|
52
|
-
return false unless applied?
|
53
|
-
|
54
|
-
node.validations.each do |validation|
|
55
|
-
args = [self, input]
|
56
|
-
validation.call(*args.take(validation.arity))
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
def up(levels = 1)
|
61
|
-
0.upto(levels - 1).inject(self) do |acc, _|
|
62
|
-
parent = acc.send(:parent)
|
63
|
-
break acc unless parent
|
64
|
-
|
65
|
-
parent
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
private
|
70
|
-
|
71
|
-
attr_writer :applied, :root
|
72
|
-
|
73
|
-
def coerce_input
|
74
|
-
output = input.is_a?(MissingInput) && node.omnipresent? ? input : node.type[input]
|
75
|
-
self.output = output
|
76
|
-
|
77
|
-
rescue Dry::Types::CoercionError => error
|
78
|
-
add_schema_error(error.message)
|
79
|
-
end
|
80
|
-
|
81
|
-
def apply_on_evaluators
|
82
|
-
node.on_evaluators.each { |evaluator| evaluator.call(input, self, context) { |result| self.input = result } }
|
83
|
-
end
|
84
|
-
|
85
|
-
def maybe_evaluator_applies?
|
86
|
-
@maybe_evaluator_applies ||= node.maybe_evaluators.inject(false) do |acc, evaluator|
|
87
|
-
result = (acc || evaluator.call(input, self, context))
|
88
|
-
|
89
|
-
if result
|
90
|
-
self.output = input
|
91
|
-
break true
|
92
|
-
else
|
93
|
-
false
|
94
|
-
end
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def register_as_applied_when_valid
|
99
|
-
return unless valid?
|
100
|
-
|
101
|
-
self.applied = true
|
102
|
-
applied_nodes << self
|
103
|
-
end
|
104
|
-
|
105
|
-
def resolve_error_key(key)
|
106
|
-
parts = [parent&.error_key].compact
|
107
|
-
parts << (key.present? ? "#{node.name}[#{key}]" : node.name)
|
108
|
-
@error_key = parts.join('.')
|
109
|
-
end
|
110
|
-
|
111
|
-
def applied?
|
112
|
-
@applied
|
113
|
-
end
|
114
|
-
end
|
115
|
-
end
|
116
|
-
end
|
@@ -1,57 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Application
|
3
|
-
class Collection < Application::Base
|
4
|
-
def call
|
5
|
-
apply_on_evaluators
|
6
|
-
child_applications # build applications here so we can access them even when invalid
|
7
|
-
return self if maybe_evaluator_applies?
|
8
|
-
|
9
|
-
coerce_input
|
10
|
-
validate_filled
|
11
|
-
return self unless valid?
|
12
|
-
|
13
|
-
child_applications.each_with_index do |item, index|
|
14
|
-
current_application = item.call
|
15
|
-
|
16
|
-
if !current_application.valid?
|
17
|
-
merge_errors(current_application)
|
18
|
-
else
|
19
|
-
output[index] = current_application.output
|
20
|
-
end
|
21
|
-
end
|
22
|
-
|
23
|
-
register_as_applied_when_valid
|
24
|
-
run_validations
|
25
|
-
|
26
|
-
self
|
27
|
-
end
|
28
|
-
|
29
|
-
delegate :[], to: :child_applications
|
30
|
-
|
31
|
-
private
|
32
|
-
|
33
|
-
def validate_filled
|
34
|
-
add_schema_error('is not allowed to be empty') if input.blank? && !maybe_evaluator_applies?
|
35
|
-
end
|
36
|
-
|
37
|
-
def child_applications
|
38
|
-
@child_applications ||= begin
|
39
|
-
return [] unless input.respond_to?(:each_with_index)
|
40
|
-
|
41
|
-
input.each_with_index.map do |item, index|
|
42
|
-
build_child_application(item, index)
|
43
|
-
end
|
44
|
-
end
|
45
|
-
|
46
|
-
end
|
47
|
-
|
48
|
-
def build_child_application(item, error_key)
|
49
|
-
sub_node.build_application(input: item, context: context, parent: self, error_key: error_key)
|
50
|
-
end
|
51
|
-
|
52
|
-
def sub_node
|
53
|
-
@sub_node ||= node.sub_nodes.values.first
|
54
|
-
end
|
55
|
-
end
|
56
|
-
end
|
57
|
-
end
|
@@ -1,114 +0,0 @@
|
|
1
|
-
module NxtSchema
|
2
|
-
module Application
|
3
|
-
class Schema < Application::Base
|
4
|
-
def call
|
5
|
-
apply_on_evaluators
|
6
|
-
child_applications # build applications here so we can access them even when invalid
|
7
|
-
return self if maybe_evaluator_applies?
|
8
|
-
|
9
|
-
coerce_input
|
10
|
-
return self unless valid?
|
11
|
-
|
12
|
-
flag_missing_keys
|
13
|
-
apply_additional_keys_strategy
|
14
|
-
|
15
|
-
child_applications.each do |key, child|
|
16
|
-
current_application = child.call
|
17
|
-
|
18
|
-
if !current_application.valid?
|
19
|
-
merge_errors(current_application)
|
20
|
-
else
|
21
|
-
output[key] = current_application.output
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
transform_keys
|
26
|
-
register_as_applied_when_valid
|
27
|
-
run_validations
|
28
|
-
self
|
29
|
-
end
|
30
|
-
|
31
|
-
delegate :[], to: :child_applications
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def transform_keys
|
36
|
-
transformer = node.key_transformer
|
37
|
-
return unless transformer && output.respond_to?(:transform_keys!)
|
38
|
-
|
39
|
-
output.transform_keys!(&transformer)
|
40
|
-
end
|
41
|
-
|
42
|
-
def keys
|
43
|
-
@keys ||= node.sub_nodes.reject { |key, _| optional_and_not_given_key?(key) }.keys
|
44
|
-
end
|
45
|
-
|
46
|
-
def additional_keys
|
47
|
-
@additional_keys ||= input.keys - keys
|
48
|
-
end
|
49
|
-
|
50
|
-
def optional_and_not_given_key?(key)
|
51
|
-
node.sub_nodes[key].optional? && !input.key?(key)
|
52
|
-
end
|
53
|
-
|
54
|
-
def additional_keys?
|
55
|
-
additional_keys.any?
|
56
|
-
end
|
57
|
-
|
58
|
-
def missing_keys
|
59
|
-
@missing_keys ||= node.sub_nodes.reject { |_, node| node.omnipresent? || node.optional? }.keys - input.keys
|
60
|
-
end
|
61
|
-
|
62
|
-
def apply_additional_keys_strategy
|
63
|
-
return if allow_additional_keys?
|
64
|
-
return unless additional_keys?
|
65
|
-
|
66
|
-
if restrict_additional_keys?
|
67
|
-
add_schema_error("Additional keys are not allowed: #{additional_keys}")
|
68
|
-
elsif reject_additional_keys?
|
69
|
-
self.output = output.except(*additional_keys)
|
70
|
-
end
|
71
|
-
end
|
72
|
-
|
73
|
-
def flag_missing_keys
|
74
|
-
return if missing_keys.empty?
|
75
|
-
|
76
|
-
add_schema_error("The following keys are missing: #{missing_keys}")
|
77
|
-
end
|
78
|
-
|
79
|
-
def allow_additional_keys?
|
80
|
-
node.additional_keys_strategy == :allow
|
81
|
-
end
|
82
|
-
|
83
|
-
def reject_additional_keys?
|
84
|
-
node.additional_keys_strategy == :reject
|
85
|
-
end
|
86
|
-
|
87
|
-
def restrict_additional_keys?
|
88
|
-
node.additional_keys_strategy == :restrict
|
89
|
-
end
|
90
|
-
|
91
|
-
def child_applications
|
92
|
-
@child_applications ||= begin
|
93
|
-
keys.inject({}) do |acc, key|
|
94
|
-
child_application = build_child_application(key)
|
95
|
-
acc[key] = child_application if child_application.present?
|
96
|
-
acc
|
97
|
-
end
|
98
|
-
end
|
99
|
-
end
|
100
|
-
|
101
|
-
def build_child_application(key)
|
102
|
-
sub_node = node.sub_nodes[key]
|
103
|
-
return unless sub_node.present?
|
104
|
-
|
105
|
-
value = input_has_key?(input, key) ? input[key] : MissingInput.new
|
106
|
-
sub_node.build_application(input: value, context: context, parent: self)
|
107
|
-
end
|
108
|
-
|
109
|
-
def input_has_key?(input, key)
|
110
|
-
input.respond_to?(:key?) && input.key?(key)
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
|
-
end
|