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.
Files changed (32) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +3 -3
  3. data/README.md +80 -38
  4. data/lib/nxt_schema.rb +17 -17
  5. data/lib/nxt_schema/dsl.rb +7 -7
  6. data/lib/nxt_schema/{application.rb → node.rb} +1 -1
  7. data/lib/nxt_schema/node/any_of.rb +21 -33
  8. data/lib/nxt_schema/node/base.rb +70 -171
  9. data/lib/nxt_schema/node/collection.rb +43 -8
  10. data/lib/nxt_schema/{application → node}/error_store.rb +5 -5
  11. data/lib/nxt_schema/{application → node}/errors/schema_error.rb +1 -1
  12. data/lib/nxt_schema/{application → node}/errors/validation_error.rb +1 -1
  13. data/lib/nxt_schema/node/leaf.rb +7 -5
  14. data/lib/nxt_schema/node/schema.rb +101 -8
  15. data/lib/nxt_schema/template/any_of.rb +50 -0
  16. data/lib/nxt_schema/template/base.rb +218 -0
  17. data/lib/nxt_schema/template/collection.rb +23 -0
  18. data/lib/nxt_schema/{node → template}/has_sub_nodes.rb +16 -10
  19. data/lib/nxt_schema/template/leaf.rb +13 -0
  20. data/lib/nxt_schema/{node → template}/maybe_evaluator.rb +1 -1
  21. data/lib/nxt_schema/{node → template}/on_evaluator.rb +1 -1
  22. data/lib/nxt_schema/template/schema.rb +22 -0
  23. data/lib/nxt_schema/{node → template}/sub_nodes.rb +1 -1
  24. data/lib/nxt_schema/{node → template}/type_resolver.rb +2 -2
  25. data/lib/nxt_schema/{node → template}/type_system_resolver.rb +1 -1
  26. data/lib/nxt_schema/version.rb +1 -1
  27. metadata +17 -17
  28. data/lib/nxt_schema/application/any_of.rb +0 -40
  29. data/lib/nxt_schema/application/base.rb +0 -116
  30. data/lib/nxt_schema/application/collection.rb +0 -57
  31. data/lib/nxt_schema/application/leaf.rb +0 -15
  32. data/lib/nxt_schema/application/schema.rb +0 -114
@@ -1,3 +1,3 @@
1
1
  module NxtSchema
2
- VERSION = "1.0.0"
2
+ VERSION = "1.0.1"
3
3
  end
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.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-23 00:00:00.000000000 Z
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/has_sub_nodes.rb
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/node/sub_nodes.rb
182
- - lib/nxt_schema/node/type_resolver.rb
183
- - lib/nxt_schema/node/type_system_resolver.rb
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,15 +0,0 @@
1
- module NxtSchema
2
- module Application
3
- class Leaf < Application::Base
4
- def call
5
- apply_on_evaluators
6
- return self if maybe_evaluator_applies?
7
-
8
- coerce_input
9
- register_as_applied_when_valid
10
- run_validations
11
- self
12
- end
13
- end
14
- end
15
- 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