nxt_schema 1.0.1 → 1.0.2
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 +19 -24
- data/README.md +36 -15
- data/lib/nxt_schema.rb +5 -2
- data/lib/nxt_schema/errors/coercion_error.rb +6 -0
- data/lib/nxt_schema/node/any_of.rb +10 -10
- data/lib/nxt_schema/node/base.rb +5 -5
- data/lib/nxt_schema/node/collection.rb +12 -12
- data/lib/nxt_schema/node/error_store.rb +12 -28
- data/lib/nxt_schema/node/errors/schema_error.rb +3 -3
- data/lib/nxt_schema/node/errors/validation_error.rb +3 -3
- data/lib/nxt_schema/node/schema.rb +14 -14
- data/lib/nxt_schema/registry.rb +23 -0
- data/lib/nxt_schema/registry/proxy.rb +21 -0
- data/lib/nxt_schema/template/base.rb +43 -41
- data/lib/nxt_schema/template/type_resolver.rb +25 -10
- data/lib/nxt_schema/types.rb +7 -4
- data/lib/nxt_schema/{missing_input.rb → undefined.rb} +1 -1
- data/lib/nxt_schema/validators/attribute.rb +3 -3
- data/lib/nxt_schema/validators/equal_to.rb +3 -3
- data/lib/nxt_schema/validators/excluded_in.rb +3 -3
- data/lib/nxt_schema/validators/excludes.rb +3 -3
- data/lib/nxt_schema/validators/greater_than.rb +3 -3
- data/lib/nxt_schema/validators/greater_than_or_equal.rb +3 -3
- data/lib/nxt_schema/validators/included_in.rb +3 -3
- data/lib/nxt_schema/validators/includes.rb +3 -3
- data/lib/nxt_schema/validators/less_than.rb +3 -3
- data/lib/nxt_schema/validators/less_than_or_equal.rb +3 -3
- data/lib/nxt_schema/validators/optional_node.rb +6 -6
- data/lib/nxt_schema/validators/pattern.rb +3 -3
- data/lib/nxt_schema/validators/query.rb +4 -4
- data/lib/nxt_schema/validators/validate_with_proxy.rb +7 -7
- data/lib/nxt_schema/version.rb +1 -1
- metadata +6 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a4076ec4518cc51176684f4bb04fca5bcff3554835016f57cce322debf3e9b8c
|
4
|
+
data.tar.gz: 336acbce68af2023b714b2b023d732575138968279efebc74b984b51ff33de13
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 4947f05400dd492a8bed83ae2b0c42110c75ebd6fd495bdcdcef10871f7715c6d69797ab95291006df759945551c0f92869e29f5b03f0343af49f4bcf6aa3497
|
7
|
+
data.tar.gz: 8ed842b8144aacd64f880e3ff7c74c64a9ae218f598522a60f26fb7a0aa2829fb3deaaf93ea0b8600a6346adb6f921d2e56e2249d1ab18e4b5c6427d25bf8759
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
nxt_schema (1.0.
|
4
|
+
nxt_schema (1.0.2)
|
5
5
|
activesupport
|
6
6
|
dry-types
|
7
7
|
nxt_init
|
@@ -10,47 +10,43 @@ PATH
|
|
10
10
|
GEM
|
11
11
|
remote: https://rubygems.org/
|
12
12
|
specs:
|
13
|
-
activesupport (6.
|
13
|
+
activesupport (6.1.3)
|
14
14
|
concurrent-ruby (~> 1.0, >= 1.0.2)
|
15
|
-
i18n (>=
|
16
|
-
minitest (
|
17
|
-
tzinfo (~>
|
18
|
-
zeitwerk (~> 2.
|
15
|
+
i18n (>= 1.6, < 2)
|
16
|
+
minitest (>= 5.1)
|
17
|
+
tzinfo (~> 2.0)
|
18
|
+
zeitwerk (~> 2.3)
|
19
19
|
coderay (1.1.3)
|
20
|
-
concurrent-ruby (1.1.
|
20
|
+
concurrent-ruby (1.1.8)
|
21
21
|
diff-lcs (1.4.4)
|
22
|
-
dry-configurable (0.
|
22
|
+
dry-configurable (0.12.1)
|
23
23
|
concurrent-ruby (~> 1.0)
|
24
|
-
dry-core (~> 0.
|
25
|
-
dry-equalizer (~> 0.2)
|
24
|
+
dry-core (~> 0.5, >= 0.5.0)
|
26
25
|
dry-container (0.7.2)
|
27
26
|
concurrent-ruby (~> 1.0)
|
28
27
|
dry-configurable (~> 0.1, >= 0.1.3)
|
29
|
-
dry-core (0.
|
28
|
+
dry-core (0.5.0)
|
30
29
|
concurrent-ruby (~> 1.0)
|
31
|
-
dry-equalizer (0.3.0)
|
32
30
|
dry-inflector (0.2.0)
|
33
|
-
dry-logic (1.0
|
31
|
+
dry-logic (1.1.0)
|
34
32
|
concurrent-ruby (~> 1.0)
|
35
|
-
dry-core (~> 0.
|
36
|
-
|
37
|
-
dry-types (1.4.0)
|
33
|
+
dry-core (~> 0.5, >= 0.5)
|
34
|
+
dry-types (1.5.1)
|
38
35
|
concurrent-ruby (~> 1.0)
|
39
36
|
dry-container (~> 0.3)
|
40
|
-
dry-core (~> 0.
|
41
|
-
dry-equalizer (~> 0.3)
|
37
|
+
dry-core (~> 0.5, >= 0.5)
|
42
38
|
dry-inflector (~> 0.1, >= 0.1.2)
|
43
39
|
dry-logic (~> 1.0, >= 1.0.2)
|
44
40
|
hirb (0.7.3)
|
45
|
-
i18n (1.8.
|
41
|
+
i18n (1.8.9)
|
46
42
|
concurrent-ruby (~> 1.0)
|
47
43
|
method_profiler (2.0.1)
|
48
44
|
hirb (>= 0.6.0)
|
49
45
|
method_source (1.0.0)
|
50
|
-
minitest (5.14.
|
46
|
+
minitest (5.14.4)
|
51
47
|
nxt_init (0.1.5)
|
52
48
|
activesupport
|
53
|
-
nxt_registry (0.3.
|
49
|
+
nxt_registry (0.3.9)
|
54
50
|
activesupport
|
55
51
|
pry (0.13.1)
|
56
52
|
coderay (~> 1.1)
|
@@ -69,9 +65,8 @@ GEM
|
|
69
65
|
diff-lcs (>= 1.2.0, < 2.0)
|
70
66
|
rspec-support (~> 3.10.0)
|
71
67
|
rspec-support (3.10.0)
|
72
|
-
|
73
|
-
|
74
|
-
thread_safe (~> 0.1)
|
68
|
+
tzinfo (2.0.4)
|
69
|
+
concurrent-ruby (~> 1.0)
|
75
70
|
zeitwerk (2.4.2)
|
76
71
|
|
77
72
|
PLATFORMS
|
data/README.md
CHANGED
@@ -128,7 +128,7 @@ end
|
|
128
128
|
|
129
129
|
result = schema.apply(input: {})
|
130
130
|
result.errors # => {}
|
131
|
-
result.output # => {:email=>NxtSchema::
|
131
|
+
result.output # => {:email=>NxtSchema::Undefined}
|
132
132
|
```
|
133
133
|
|
134
134
|
```ruby
|
@@ -225,10 +225,42 @@ This is suitable to validate and coerce your query params.
|
|
225
225
|
NxtSchema.params do
|
226
226
|
required(:effective_at, :DateTime) # would resolve to Types::Params::DateTime
|
227
227
|
required(:test, :String) # The :String will resolve to NxtSchema::Types::Nominal::String
|
228
|
-
required(:advanced, NxtSchema::Types::
|
228
|
+
required(:advanced, NxtSchema::Types::Registry::Bool) # long version of required(:advanced, :Bool)
|
229
229
|
end
|
230
230
|
```
|
231
231
|
|
232
|
+
#### NxtSchema::Registry
|
233
|
+
|
234
|
+
To make use of NxtSchema.params in your controller you can simply include the `NxtSchema::Registry` to easily register
|
235
|
+
and apply schemas:
|
236
|
+
|
237
|
+
```ruby
|
238
|
+
class UsersController < ApplicationController
|
239
|
+
include NxtSchema::Registry
|
240
|
+
|
241
|
+
# register the schema for the :create action
|
242
|
+
schemas.register(
|
243
|
+
:create,
|
244
|
+
NxtSchema.params do
|
245
|
+
required(:first_name, :String)
|
246
|
+
required(:last_name, :String)
|
247
|
+
end
|
248
|
+
)
|
249
|
+
|
250
|
+
def create
|
251
|
+
User.create!(**create_params)
|
252
|
+
end
|
253
|
+
|
254
|
+
private
|
255
|
+
|
256
|
+
def create_params
|
257
|
+
# apply the registered schema
|
258
|
+
schemas.apply!(:create, params.fetch(:user))
|
259
|
+
end
|
260
|
+
end
|
261
|
+
|
262
|
+
```
|
263
|
+
|
232
264
|
#### Custom types
|
233
265
|
|
234
266
|
You can also register custom types. In order to check out all the cool things you can do with dry types you should
|
@@ -486,16 +518,5 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
486
518
|
--> Would be cool to register things for the schema only
|
487
519
|
--> Would be cool if this was extendable
|
488
520
|
- Do we need all off in order to combine multiple schemas?
|
489
|
-
-
|
490
|
-
|
491
|
-
```ruby
|
492
|
-
PARAMS = NxtRegistry::Registry.new do
|
493
|
-
register(:create) do
|
494
|
-
NxtSchema.params do
|
495
|
-
|
496
|
-
end
|
497
|
-
end
|
498
|
-
end
|
499
|
-
|
500
|
-
PARAMS.resolve(:create).apply(input: params)
|
501
|
-
```
|
521
|
+
- Allow custom errors
|
522
|
+
- Spec inheritance of params
|
data/lib/nxt_schema.rb
CHANGED
@@ -8,10 +8,11 @@ require 'yaml'
|
|
8
8
|
require_relative 'nxt_schema/types'
|
9
9
|
require_relative 'nxt_schema/callable'
|
10
10
|
require_relative 'nxt_schema/node'
|
11
|
-
require_relative 'nxt_schema/
|
11
|
+
require_relative 'nxt_schema/undefined'
|
12
12
|
require_relative 'nxt_schema/error'
|
13
13
|
require_relative 'nxt_schema/errors/invalid'
|
14
14
|
require_relative 'nxt_schema/errors/invalid_options'
|
15
|
+
require_relative 'nxt_schema/errors/coercion_error'
|
15
16
|
|
16
17
|
require_relative 'nxt_schema/validators/registry'
|
17
18
|
require_relative 'nxt_schema/validators/validate_with_proxy'
|
@@ -52,6 +53,8 @@ require_relative 'nxt_schema/node/leaf'
|
|
52
53
|
require_relative 'nxt_schema/node/collection'
|
53
54
|
require_relative 'nxt_schema/node/schema'
|
54
55
|
require_relative 'nxt_schema/dsl'
|
56
|
+
require_relative 'nxt_schema/registry/proxy'
|
57
|
+
require_relative 'nxt_schema/registry'
|
55
58
|
|
56
59
|
module NxtSchema
|
57
60
|
extend Dsl
|
@@ -65,7 +68,7 @@ module NxtSchema
|
|
65
68
|
end
|
66
69
|
|
67
70
|
def register_type(key, type)
|
68
|
-
NxtSchema::Types.
|
71
|
+
NxtSchema::Types.registry(:types).register(key, type)
|
69
72
|
end
|
70
73
|
|
71
74
|
# Load default messages
|
@@ -2,17 +2,17 @@ module NxtSchema
|
|
2
2
|
module Node
|
3
3
|
class AnyOf < Node::Base
|
4
4
|
def valid?
|
5
|
-
|
5
|
+
valid_node.present?
|
6
6
|
end
|
7
7
|
|
8
8
|
def call
|
9
|
-
|
9
|
+
child_nodes.map(&:call)
|
10
10
|
|
11
11
|
if valid?
|
12
|
-
self.output =
|
12
|
+
self.output = valid_node.output
|
13
13
|
else
|
14
|
-
|
15
|
-
merge_errors(
|
14
|
+
child_nodes.each do |node|
|
15
|
+
merge_errors(node)
|
16
16
|
end
|
17
17
|
end
|
18
18
|
|
@@ -21,14 +21,14 @@ module NxtSchema
|
|
21
21
|
|
22
22
|
private
|
23
23
|
|
24
|
-
delegate :[], to: :
|
24
|
+
delegate :[], to: :child_nodes
|
25
25
|
|
26
|
-
def
|
27
|
-
|
26
|
+
def valid_node
|
27
|
+
child_nodes.find(&:valid?)
|
28
28
|
end
|
29
29
|
|
30
|
-
def
|
31
|
-
@
|
30
|
+
def child_nodes
|
31
|
+
@child_nodes ||= nodes.map { |node| node.build_node(input: input, context: context, parent: self) }
|
32
32
|
end
|
33
33
|
|
34
34
|
def nodes
|
data/lib/nxt_schema/node/base.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module NxtSchema
|
2
2
|
module Node
|
3
3
|
class Base
|
4
|
-
def initialize(node:, input:
|
4
|
+
def initialize(node:, input: Undefined.new, parent:, context:, error_key:)
|
5
5
|
@node = node
|
6
6
|
@input = input
|
7
7
|
@parent = parent
|
@@ -44,8 +44,8 @@ module NxtSchema
|
|
44
44
|
errors.add_schema_error(message: error)
|
45
45
|
end
|
46
46
|
|
47
|
-
def merge_errors(
|
48
|
-
errors.merge_errors(
|
47
|
+
def merge_errors(node)
|
48
|
+
errors.merge_errors(node)
|
49
49
|
end
|
50
50
|
|
51
51
|
def run_validations
|
@@ -71,10 +71,10 @@ module NxtSchema
|
|
71
71
|
attr_writer :coerced, :root
|
72
72
|
|
73
73
|
def coerce_input
|
74
|
-
output = input.is_a?(
|
74
|
+
output = input.is_a?(Undefined) && node.omnipresent? ? input : node.type.call(input)
|
75
75
|
self.output = output
|
76
76
|
|
77
|
-
rescue Dry::Types::CoercionError => error
|
77
|
+
rescue Dry::Types::CoercionError, NxtSchema::Errors::CoercionError => error
|
78
78
|
add_schema_error(error.message)
|
79
79
|
end
|
80
80
|
|
@@ -3,20 +3,20 @@ module NxtSchema
|
|
3
3
|
class Collection < Node::Base
|
4
4
|
def call
|
5
5
|
apply_on_evaluators
|
6
|
-
|
6
|
+
child_nodes # build nodes here so we can access them even when invalid
|
7
7
|
return self if maybe_evaluator_applies?
|
8
8
|
|
9
9
|
coerce_input
|
10
10
|
validate_filled
|
11
11
|
return self unless valid?
|
12
12
|
|
13
|
-
|
14
|
-
|
13
|
+
child_nodes.each_with_index do |item, index|
|
14
|
+
child_node = item.call
|
15
15
|
|
16
|
-
if !
|
17
|
-
merge_errors(
|
16
|
+
if !child_node.valid?
|
17
|
+
merge_errors(child_node)
|
18
18
|
else
|
19
|
-
output[index] =
|
19
|
+
output[index] = child_node.output
|
20
20
|
end
|
21
21
|
end
|
22
22
|
|
@@ -26,7 +26,7 @@ module NxtSchema
|
|
26
26
|
self
|
27
27
|
end
|
28
28
|
|
29
|
-
delegate :[], to: :
|
29
|
+
delegate :[], to: :child_nodes
|
30
30
|
|
31
31
|
private
|
32
32
|
|
@@ -34,19 +34,19 @@ module NxtSchema
|
|
34
34
|
add_schema_error('is not allowed to be empty') if input.blank? && !maybe_evaluator_applies?
|
35
35
|
end
|
36
36
|
|
37
|
-
def
|
38
|
-
@
|
37
|
+
def child_nodes
|
38
|
+
@child_nodes ||= begin
|
39
39
|
return [] unless input.respond_to?(:each_with_index)
|
40
40
|
|
41
41
|
input.each_with_index.map do |item, index|
|
42
|
-
|
42
|
+
build_child_node(item, index)
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
46
|
end
|
47
47
|
|
48
|
-
def
|
49
|
-
sub_node.
|
48
|
+
def build_child_node(item, error_key)
|
49
|
+
sub_node.build_node(input: item, context: context, parent: self, error_key: error_key)
|
50
50
|
end
|
51
51
|
|
52
52
|
def sub_node
|
@@ -1,18 +1,18 @@
|
|
1
1
|
module NxtSchema
|
2
2
|
module Node
|
3
3
|
class ErrorStore < ::Hash
|
4
|
-
def initialize(
|
4
|
+
def initialize(node)
|
5
5
|
super()
|
6
|
-
@
|
6
|
+
@node = node
|
7
7
|
end
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :node
|
10
10
|
|
11
11
|
def add_schema_error(message:)
|
12
12
|
add_error(
|
13
|
-
|
13
|
+
node,
|
14
14
|
NxtSchema::Node::Errors::SchemaError.new(
|
15
|
-
|
15
|
+
node: node,
|
16
16
|
message: message
|
17
17
|
)
|
18
18
|
)
|
@@ -20,38 +20,22 @@ module NxtSchema
|
|
20
20
|
|
21
21
|
def add_validation_error(message:)
|
22
22
|
add_error(
|
23
|
-
|
23
|
+
node,
|
24
24
|
NxtSchema::Node::Errors::ValidationError.new(
|
25
|
-
|
25
|
+
node: node,
|
26
26
|
message: message
|
27
27
|
)
|
28
28
|
)
|
29
29
|
end
|
30
30
|
|
31
|
-
def merge_errors(
|
32
|
-
merge!(
|
31
|
+
def merge_errors(node)
|
32
|
+
merge!(node.errors)
|
33
33
|
end
|
34
34
|
|
35
|
-
def add_error(
|
36
|
-
self[
|
37
|
-
self[
|
35
|
+
def add_error(node, error)
|
36
|
+
self[node.error_key] ||= []
|
37
|
+
self[node.error_key] << error
|
38
38
|
end
|
39
|
-
|
40
|
-
# def schema_errors
|
41
|
-
# inject({}) do |acc, (k, v)|
|
42
|
-
# errors = v.select { |e| e.is_a?(NxtSchema::Node::Errors::SchemaError) }
|
43
|
-
# acc[k] = errors if errors.any?
|
44
|
-
# acc
|
45
|
-
# end
|
46
|
-
# end
|
47
|
-
#
|
48
|
-
# def validation_errors
|
49
|
-
# inject({}) do |acc, (k, v)|
|
50
|
-
# errors = v.select { |e| e.is_a?(NxtSchema::Node::Errors::ValidationError) }
|
51
|
-
# acc[k] = errors if errors.any?
|
52
|
-
# acc
|
53
|
-
# end
|
54
|
-
# end
|
55
39
|
end
|
56
40
|
end
|
57
41
|
end
|
@@ -2,12 +2,12 @@ module NxtSchema
|
|
2
2
|
module Node
|
3
3
|
module Errors
|
4
4
|
class SchemaError < ::String
|
5
|
-
def initialize(
|
5
|
+
def initialize(node:, message:)
|
6
6
|
super(message)
|
7
|
-
@
|
7
|
+
@node = node
|
8
8
|
end
|
9
9
|
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :node
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -2,12 +2,12 @@ module NxtSchema
|
|
2
2
|
module Node
|
3
3
|
module Errors
|
4
4
|
class ValidationError < ::String
|
5
|
-
def initialize(
|
5
|
+
def initialize(node:, message:)
|
6
6
|
super(message)
|
7
|
-
@
|
7
|
+
@node = node
|
8
8
|
end
|
9
9
|
|
10
|
-
attr_reader :
|
10
|
+
attr_reader :node
|
11
11
|
end
|
12
12
|
end
|
13
13
|
end
|
@@ -3,7 +3,7 @@ module NxtSchema
|
|
3
3
|
class Schema < Node::Base
|
4
4
|
def call
|
5
5
|
apply_on_evaluators
|
6
|
-
|
6
|
+
child_nodes # build nodes here so we can access them even when invalid
|
7
7
|
return self if maybe_evaluator_applies?
|
8
8
|
|
9
9
|
coerce_input
|
@@ -12,13 +12,13 @@ module NxtSchema
|
|
12
12
|
flag_missing_keys
|
13
13
|
apply_additional_keys_strategy
|
14
14
|
|
15
|
-
|
16
|
-
|
15
|
+
child_nodes.each do |key, child|
|
16
|
+
current_node = child.call
|
17
17
|
|
18
|
-
if !
|
19
|
-
merge_errors(
|
18
|
+
if !current_node.valid?
|
19
|
+
merge_errors(current_node)
|
20
20
|
else
|
21
|
-
output[key] =
|
21
|
+
output[key] = current_node.output
|
22
22
|
end
|
23
23
|
end
|
24
24
|
|
@@ -28,7 +28,7 @@ module NxtSchema
|
|
28
28
|
self
|
29
29
|
end
|
30
30
|
|
31
|
-
delegate :[], to: :
|
31
|
+
delegate :[], to: :child_nodes
|
32
32
|
|
33
33
|
private
|
34
34
|
|
@@ -88,22 +88,22 @@ module NxtSchema
|
|
88
88
|
node.additional_keys_strategy == :restrict
|
89
89
|
end
|
90
90
|
|
91
|
-
def
|
92
|
-
@
|
91
|
+
def child_nodes
|
92
|
+
@child_nodes ||= begin
|
93
93
|
keys.inject({}) do |acc, key|
|
94
|
-
|
95
|
-
acc[key] =
|
94
|
+
child_node = build_child_node(key)
|
95
|
+
acc[key] = child_node if child_node.present?
|
96
96
|
acc
|
97
97
|
end
|
98
98
|
end
|
99
99
|
end
|
100
100
|
|
101
|
-
def
|
101
|
+
def build_child_node(key)
|
102
102
|
sub_node = node.sub_nodes[key]
|
103
103
|
return unless sub_node.present?
|
104
104
|
|
105
|
-
value = input_has_key?(input, key) ? input[key] :
|
106
|
-
sub_node.
|
105
|
+
value = input_has_key?(input, key) ? input[key] : Undefined.new
|
106
|
+
sub_node.build_node(input: value, context: context, parent: self)
|
107
107
|
end
|
108
108
|
|
109
109
|
def input_has_key?(input, key)
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module NxtSchema
|
2
|
+
module Registry
|
3
|
+
module ClassMethods
|
4
|
+
def schemas
|
5
|
+
@schemas ||= NxtSchema::Registry::Proxy.new(self)
|
6
|
+
end
|
7
|
+
|
8
|
+
def inherited(subclass)
|
9
|
+
schemas.each do |key, schema|
|
10
|
+
subclass.schemas.register(key, schema)
|
11
|
+
end
|
12
|
+
|
13
|
+
super
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.included(base)
|
18
|
+
base.extend(ClassMethods)
|
19
|
+
|
20
|
+
delegate :schemas, to: :class
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module NxtSchema
|
2
|
+
module Registry
|
3
|
+
class Proxy
|
4
|
+
def initialize(namespace)
|
5
|
+
@registry = ::NxtRegistry::Registry.new(namespace, call: false)
|
6
|
+
end
|
7
|
+
|
8
|
+
attr_reader :registry
|
9
|
+
|
10
|
+
delegate_missing_to :registry
|
11
|
+
|
12
|
+
def apply(key, input)
|
13
|
+
resolve!(key).apply(input: input)
|
14
|
+
end
|
15
|
+
|
16
|
+
def apply!(key, input)
|
17
|
+
resolve!(key).apply!(input: input)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -21,40 +21,42 @@ module NxtSchema
|
|
21
21
|
resolve_type_system
|
22
22
|
resolve_type(type)
|
23
23
|
resolve_additional_keys_strategy
|
24
|
-
|
24
|
+
node_class # memoize
|
25
25
|
configure(&block) if block_given?
|
26
26
|
end
|
27
27
|
|
28
28
|
attr_accessor :name,
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
29
|
+
:parent_node,
|
30
|
+
:options,
|
31
|
+
:type,
|
32
|
+
:root_node,
|
33
|
+
:additional_keys_strategy
|
34
34
|
|
35
35
|
attr_reader :type_system,
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
36
|
+
:path,
|
37
|
+
:context,
|
38
|
+
:meta,
|
39
|
+
:on_evaluators,
|
40
|
+
:maybe_evaluators,
|
41
|
+
:validations,
|
42
|
+
:configuration,
|
43
|
+
:key_transformer
|
44
44
|
|
45
|
-
def apply(input:
|
46
|
-
|
45
|
+
def apply(input: Undefined.new, context: self.context, parent: nil, error_key: nil)
|
46
|
+
build_node(input: input, context: context, parent: parent, error_key: error_key).call
|
47
47
|
end
|
48
48
|
|
49
|
-
def apply!(input:
|
50
|
-
result =
|
51
|
-
return result if parent
|
49
|
+
def apply!(input: Undefined.new, context: self.context, parent: nil, error_key: nil)
|
50
|
+
result = build_node(input: input, context: context, parent: parent, error_key: error_key).call
|
51
|
+
return result if parent
|
52
52
|
|
53
|
-
raise NxtSchema::Errors::Invalid.new(result)
|
53
|
+
raise NxtSchema::Errors::Invalid.new(result) if result.errors.any?
|
54
|
+
|
55
|
+
result.output
|
54
56
|
end
|
55
57
|
|
56
|
-
def
|
57
|
-
|
58
|
+
def build_node(input: Undefined.new, context: self.context, parent: nil, error_key: nil)
|
59
|
+
node_class.new(
|
58
60
|
node: self,
|
59
61
|
input: input,
|
60
62
|
parent: parent,
|
@@ -75,7 +77,7 @@ module NxtSchema
|
|
75
77
|
@omnipresent
|
76
78
|
end
|
77
79
|
|
78
|
-
def default(value = NxtSchema::
|
80
|
+
def default(value = NxtSchema::Undefined.new, &block)
|
79
81
|
value = missing_input?(value) ? block : value
|
80
82
|
condition = ->(input) { missing_input?(input) || input.nil? }
|
81
83
|
on(condition, value)
|
@@ -83,36 +85,36 @@ module NxtSchema
|
|
83
85
|
self
|
84
86
|
end
|
85
87
|
|
86
|
-
def on(condition, value = NxtSchema::
|
88
|
+
def on(condition, value = NxtSchema::Undefined.new, &block)
|
87
89
|
value = missing_input?(value) ? block : value
|
88
90
|
on_evaluators << OnEvaluator.new(condition: condition, value: value)
|
89
91
|
|
90
92
|
self
|
91
93
|
end
|
92
94
|
|
93
|
-
def maybe(value = NxtSchema::
|
95
|
+
def maybe(value = NxtSchema::Undefined.new, &block)
|
94
96
|
value = missing_input?(value) ? block : value
|
95
97
|
maybe_evaluators << MaybeEvaluator.new(value: value)
|
96
98
|
|
97
99
|
self
|
98
100
|
end
|
99
101
|
|
100
|
-
def validate(key = NxtSchema::
|
102
|
+
def validate(key = NxtSchema::Undefined.new, *args, &block)
|
101
103
|
# TODO: This does not really work with all kinds of chaining combinations yet!
|
102
104
|
|
103
105
|
validator = if key.is_a?(Symbol)
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
106
|
+
validator(key, *args)
|
107
|
+
elsif key.respond_to?(:call)
|
108
|
+
key
|
109
|
+
elsif block_given?
|
110
|
+
if key.is_a?(NxtSchema::Undefined)
|
111
|
+
block
|
112
|
+
else
|
113
|
+
configure(&block)
|
114
|
+
end
|
115
|
+
else
|
116
|
+
raise ArgumentError, "Don't know how to resolve validator from: #{key} with: #{args} #{block}"
|
117
|
+
end
|
116
118
|
|
117
119
|
register_validator(validator)
|
118
120
|
|
@@ -150,8 +152,8 @@ module NxtSchema
|
|
150
152
|
end
|
151
153
|
end
|
152
154
|
|
153
|
-
def
|
154
|
-
@
|
155
|
+
def node_class
|
156
|
+
@node_class ||= "NxtSchema::Node::#{self.class.name.demodulize}".constantize
|
155
157
|
end
|
156
158
|
|
157
159
|
def configure(&block)
|
@@ -201,7 +203,7 @@ module NxtSchema
|
|
201
203
|
end
|
202
204
|
|
203
205
|
def missing_input?(value)
|
204
|
-
value.is_a?
|
206
|
+
value.is_a? Undefined
|
205
207
|
end
|
206
208
|
|
207
209
|
def resolve_key_transformer
|
@@ -4,21 +4,36 @@ module NxtSchema
|
|
4
4
|
def resolve(type_system, type)
|
5
5
|
@resolve ||= {}
|
6
6
|
@resolve[type] ||= begin
|
7
|
-
if type.is_a?(
|
7
|
+
if type.is_a?(Symbol)
|
8
|
+
resolve_type_from_symbol(type, type_system)
|
9
|
+
elsif type.respond_to?(:call)
|
8
10
|
type
|
9
11
|
else
|
10
|
-
|
11
|
-
type = type_system.const_get(type.to_s.classify)
|
12
|
-
|
13
|
-
if type.is_a?(Dry::Types::Type)
|
14
|
-
type
|
15
|
-
else
|
16
|
-
# in case it does not exist fallback to Types::Nominal
|
17
|
-
"NxtSchema::Types::Nominal::#{type.to_s.classify}".constantize
|
18
|
-
end
|
12
|
+
raise_type_not_resolvable_error(type)
|
19
13
|
end
|
14
|
+
rescue NxtRegistry::Errors::KeyNotRegisteredError => error
|
15
|
+
raise_type_not_resolvable_error(type)
|
20
16
|
end
|
21
17
|
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def resolve_type_from_symbol(type, type_system)
|
22
|
+
classified_type = type.to_s.classify
|
23
|
+
|
24
|
+
return type_system.const_get(classified_type) if type_defined_in_type_system?(type, type_system)
|
25
|
+
return NxtSchema::Types::Nominal.const_get(classified_type) if type_defined_in_type_system?(type, NxtSchema::Types::Nominal)
|
26
|
+
|
27
|
+
NxtSchema::Types.registry(:types).resolve!(type)
|
28
|
+
end
|
29
|
+
|
30
|
+
def type_defined_in_type_system?(type, type_system)
|
31
|
+
type_system.constants.include?(type)
|
32
|
+
end
|
33
|
+
|
34
|
+
def raise_type_not_resolvable_error(type)
|
35
|
+
raise ArgumentError, "Can't resolve type: #{type}"
|
36
|
+
end
|
22
37
|
end
|
23
38
|
end
|
24
39
|
end
|
data/lib/nxt_schema/types.rb
CHANGED
@@ -1,10 +1,13 @@
|
|
1
1
|
module NxtSchema
|
2
2
|
module Types
|
3
3
|
include Dry.Types()
|
4
|
+
extend NxtRegistry
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
registry(:types, call: false) do
|
7
|
+
register(:StrippedString, Strict::String.constructor(->(string) { string&.strip }))
|
8
|
+
register(:LengthyStrippedString, resolve!(:StrippedString).constrained(min_size: 1))
|
9
|
+
register(:Enum, -> (*values) { Strict::String.enum(*values) })
|
10
|
+
register(:SymbolizedEnum, -> (*values) { Coercible::Symbol.enum(*values) })
|
11
|
+
end
|
9
12
|
end
|
10
13
|
end
|
@@ -12,15 +12,15 @@ module NxtSchema
|
|
12
12
|
# Query any attribute on a value with validator(:attribute, :size, ->(s) { s < 7 })
|
13
13
|
|
14
14
|
def build
|
15
|
-
lambda do |
|
15
|
+
lambda do |node, value|
|
16
16
|
raise ArgumentError, "#{value} does not respond to query: #{method}" unless value.respond_to?(method)
|
17
17
|
|
18
18
|
if expectation.call(value.send(method))
|
19
19
|
true
|
20
20
|
else
|
21
|
-
|
21
|
+
node.add_error(
|
22
22
|
translate_error(
|
23
|
-
|
23
|
+
node.locale,
|
24
24
|
attribute: value,
|
25
25
|
attribute_name: method,
|
26
26
|
value: value.send(method)
|
@@ -12,15 +12,15 @@ module NxtSchema
|
|
12
12
|
# Query for equality validator(:eql, -> { 3 * 3 * 60 })
|
13
13
|
|
14
14
|
def build
|
15
|
-
lambda do |
|
15
|
+
lambda do |node, value|
|
16
16
|
expected_value = Callable.new(expectation, nil, value).call
|
17
17
|
|
18
18
|
if value == expected_value
|
19
19
|
true
|
20
20
|
else
|
21
|
-
|
21
|
+
node.add_error(
|
22
22
|
translate_error(
|
23
|
-
|
23
|
+
node.locale,
|
24
24
|
actual: value,
|
25
25
|
expected: expected_value
|
26
26
|
)
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :target
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if target.exclude?(value)
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, target: target, value: value)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :target
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value.exclude?(target)
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, target: target, value: value)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :threshold
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value > threshold
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, value: value, threshold: threshold)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :threshold
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value >= threshold
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, value: value, threshold: threshold)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :target
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if target.include?(value)
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, value: value, target: target)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :target
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value.include?(target)
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(coerced?.locale, value: value, target: target)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :threshold
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value < threshold
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, value: value, threshold: threshold)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :threshold
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value <= threshold
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, value: value, threshold: threshold)
|
17
|
+
node.add_error(message)
|
18
18
|
end
|
19
19
|
end
|
20
20
|
end
|
@@ -10,20 +10,20 @@ module NxtSchema
|
|
10
10
|
attr_reader :conditional, :missing_key
|
11
11
|
|
12
12
|
def build
|
13
|
-
lambda do |
|
14
|
-
args = [
|
13
|
+
lambda do |node, value|
|
14
|
+
args = [node, value]
|
15
15
|
|
16
16
|
return if conditional.call(*args.take(conditional.arity))
|
17
|
-
return if
|
17
|
+
return if node.send(:keys).include?(missing_key.to_sym)
|
18
18
|
|
19
19
|
message = ErrorMessages.resolve(
|
20
|
-
|
20
|
+
node.locale,
|
21
21
|
:required_key_missing,
|
22
22
|
key: missing_key,
|
23
|
-
target:
|
23
|
+
target: node.input
|
24
24
|
)
|
25
25
|
|
26
|
-
|
26
|
+
node.add_error(message)
|
27
27
|
end
|
28
28
|
end
|
29
29
|
end
|
@@ -9,12 +9,12 @@ module NxtSchema
|
|
9
9
|
attr_reader :pattern
|
10
10
|
|
11
11
|
def build
|
12
|
-
lambda do |
|
12
|
+
lambda do |node, value|
|
13
13
|
if value.match(pattern)
|
14
14
|
true
|
15
15
|
else
|
16
|
-
message = translate_error(
|
17
|
-
|
16
|
+
message = translate_error(node.locale, value: value, pattern: pattern)
|
17
|
+
node.add_error(message)
|
18
18
|
false
|
19
19
|
end
|
20
20
|
end
|
@@ -8,18 +8,18 @@ module NxtSchema
|
|
8
8
|
register_as :query
|
9
9
|
attr_reader :method
|
10
10
|
|
11
|
-
# Query a boolean method on you value =>
|
11
|
+
# Query a boolean method on you value => node(:test, :String).validate(:query, :good_enough?)
|
12
12
|
# => Would be valid if value.good_enough? is truthy
|
13
13
|
|
14
14
|
def build
|
15
|
-
lambda do |
|
15
|
+
lambda do |node, value|
|
16
16
|
raise ArgumentError, "#{value} does not respond to query: #{method}" unless value.respond_to?(method)
|
17
17
|
|
18
18
|
if value.send(method)
|
19
19
|
true
|
20
20
|
else
|
21
|
-
message = translate_error(
|
22
|
-
|
21
|
+
message = translate_error(node.locale, value: value, actual: value.send(method), query: method)
|
22
|
+
node.add_error(message)
|
23
23
|
end
|
24
24
|
end
|
25
25
|
end
|
@@ -1,14 +1,14 @@
|
|
1
1
|
module NxtSchema
|
2
2
|
module Validator
|
3
3
|
class ValidateWithProxy
|
4
|
-
def initialize(
|
5
|
-
@
|
4
|
+
def initialize(node)
|
5
|
+
@node = node
|
6
6
|
@aggregated_errors = []
|
7
7
|
end
|
8
8
|
|
9
|
-
attr_reader :
|
9
|
+
attr_reader :node
|
10
10
|
|
11
|
-
delegate_missing_to :
|
11
|
+
delegate_missing_to :node
|
12
12
|
|
13
13
|
def validate(&block)
|
14
14
|
result = instance_exec(&block)
|
@@ -24,7 +24,7 @@ module NxtSchema
|
|
24
24
|
|
25
25
|
def copy_aggregated_errors_to_node
|
26
26
|
aggregated_errors.each do |error|
|
27
|
-
|
27
|
+
node.add_error(error)
|
28
28
|
end
|
29
29
|
end
|
30
30
|
|
@@ -33,8 +33,8 @@ module NxtSchema
|
|
33
33
|
attr_reader :aggregated_errors
|
34
34
|
|
35
35
|
def validator(key, *args)
|
36
|
-
validator =
|
37
|
-
validator.call(self,
|
36
|
+
validator = node.node.send(:validator, key, *args)
|
37
|
+
validator.call(self, node.input)
|
38
38
|
end
|
39
39
|
end
|
40
40
|
end
|
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.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andreas Robecke
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-03-20 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
@@ -158,9 +158,9 @@ files:
|
|
158
158
|
- lib/nxt_schema/callable.rb
|
159
159
|
- lib/nxt_schema/dsl.rb
|
160
160
|
- lib/nxt_schema/error.rb
|
161
|
+
- lib/nxt_schema/errors/coercion_error.rb
|
161
162
|
- lib/nxt_schema/errors/invalid.rb
|
162
163
|
- lib/nxt_schema/errors/invalid_options.rb
|
163
|
-
- lib/nxt_schema/missing_input.rb
|
164
164
|
- lib/nxt_schema/node.rb
|
165
165
|
- lib/nxt_schema/node/any_of.rb
|
166
166
|
- lib/nxt_schema/node/base.rb
|
@@ -170,6 +170,8 @@ files:
|
|
170
170
|
- lib/nxt_schema/node/errors/validation_error.rb
|
171
171
|
- lib/nxt_schema/node/leaf.rb
|
172
172
|
- lib/nxt_schema/node/schema.rb
|
173
|
+
- lib/nxt_schema/registry.rb
|
174
|
+
- lib/nxt_schema/registry/proxy.rb
|
173
175
|
- lib/nxt_schema/template/any_of.rb
|
174
176
|
- lib/nxt_schema/template/base.rb
|
175
177
|
- lib/nxt_schema/template/collection.rb
|
@@ -182,6 +184,7 @@ files:
|
|
182
184
|
- lib/nxt_schema/template/type_resolver.rb
|
183
185
|
- lib/nxt_schema/template/type_system_resolver.rb
|
184
186
|
- lib/nxt_schema/types.rb
|
187
|
+
- lib/nxt_schema/undefined.rb
|
185
188
|
- lib/nxt_schema/validators/attribute.rb
|
186
189
|
- lib/nxt_schema/validators/equal_to.rb
|
187
190
|
- lib/nxt_schema/validators/error_messages.rb
|