saphyr 0.4.0.beta
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 +7 -0
- data/CHANGELOG +7 -0
- data/LICENSE +21 -0
- data/lib/saphyr/asserts/base_assert.rb +58 -0
- data/lib/saphyr/asserts/error_constants.rb +28 -0
- data/lib/saphyr/asserts/numeric_assert.rb +66 -0
- data/lib/saphyr/asserts/size_assert.rb +54 -0
- data/lib/saphyr/asserts/string_assert.rb +21 -0
- data/lib/saphyr/asserts.rb +15 -0
- data/lib/saphyr/engine.rb +220 -0
- data/lib/saphyr/fields/array_field.rb +80 -0
- data/lib/saphyr/fields/boolean_field.rb +20 -0
- data/lib/saphyr/fields/field_base.rb +235 -0
- data/lib/saphyr/fields/float_field.rb +49 -0
- data/lib/saphyr/fields/integer_field.rb +49 -0
- data/lib/saphyr/fields/schema_field.rb +26 -0
- data/lib/saphyr/fields/string_field.rb +41 -0
- data/lib/saphyr/fields.rb +13 -0
- data/lib/saphyr/helpers/format.rb +106 -0
- data/lib/saphyr/helpers.rb +7 -0
- data/lib/saphyr/schema.rb +73 -0
- data/lib/saphyr/validator.rb +129 -0
- data/lib/saphyr/version.rb +5 -0
- data/lib/saphyr.rb +160 -0
- data/rdoc/01_Define_Schema.md +133 -0
- data/rdoc/02_Field_Types.md +210 -0
- data/rdoc/03_Strict_Mode.md +80 -0
- metadata +106 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA256:
|
|
3
|
+
metadata.gz: 48f8284121fe854fd431ed4afa7a656206c17d4d1ddcb21ad6540db9ece53f15
|
|
4
|
+
data.tar.gz: 454d04e4c206d9bf827690a656d8d60573ebebfb6a625af409e4b1be560d038e
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 16b265ab45002d654a716b994c6df15b48eafdd4617d3e1cc6e968905a5bd7172458c63c37213e3e2c1051a041b1cd1da9b97d108aba586b6b92137e5d7b8798
|
|
7
|
+
data.tar.gz: 0305d518e223973cb92c269030cb356d30d7c609e8abf86899cc6ab017164e853258bf67989a76c8e39521c6b804ced86254e42131afd851c0629022c7711a4b
|
data/CHANGELOG
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
The MIT License (MIT)
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2023 Olivier Delbos
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Asserts
|
|
3
|
+
|
|
4
|
+
module BaseAssert
|
|
5
|
+
def assert_boolean value
|
|
6
|
+
value.is_a? TrueClass or value.is_a? FalseClass
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def assert_class klass, value, errors, error_code=Fields::FieldBase::ERR_TYPE
|
|
10
|
+
klass = [klass] unless klass.is_a? Array
|
|
11
|
+
test = false
|
|
12
|
+
klass.each do |k|
|
|
13
|
+
if value.is_a? k; test = true; break; end
|
|
14
|
+
end
|
|
15
|
+
unless test
|
|
16
|
+
errors << {
|
|
17
|
+
type: err(error_code),
|
|
18
|
+
data: {
|
|
19
|
+
type: klass.to_s,
|
|
20
|
+
got: value.class.name,
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
end
|
|
24
|
+
test
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def assert_eq opt_value, value, errors, error_code=Fields::FieldBase::ERR_EQ
|
|
28
|
+
return nil if opt_value.nil?
|
|
29
|
+
unless value == opt_value
|
|
30
|
+
errors << {
|
|
31
|
+
type: err(error_code),
|
|
32
|
+
data: {
|
|
33
|
+
_val: value,
|
|
34
|
+
eq: opt_value,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return false
|
|
38
|
+
end
|
|
39
|
+
true
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def assert_in opt_values, value, errors, error_code=Fields::FieldBase::ERR_IN
|
|
43
|
+
return nil if opt_values.nil?
|
|
44
|
+
unless opt_values.include? value
|
|
45
|
+
errors << {
|
|
46
|
+
type: err(error_code),
|
|
47
|
+
data: {
|
|
48
|
+
_val: value,
|
|
49
|
+
in: opt_values,
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return false
|
|
53
|
+
end
|
|
54
|
+
true
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Asserts
|
|
3
|
+
|
|
4
|
+
module ErrorConstants
|
|
5
|
+
# Base
|
|
6
|
+
ERR_NOT_NULLABLE = 'not-nullable'
|
|
7
|
+
ERR_BAD_FORMAT = 'bad-format'
|
|
8
|
+
ERR_TYPE = 'type'
|
|
9
|
+
ERR_IN = 'in'
|
|
10
|
+
ERR_EQ = 'eq'
|
|
11
|
+
# Size
|
|
12
|
+
ERR_SIZE_EQ = 'size-eq'
|
|
13
|
+
ERR_SIZE_LEN = 'size-len'
|
|
14
|
+
ERR_SIZE_MIN = 'size-min'
|
|
15
|
+
ERR_SIZE_MAX = 'size-max'
|
|
16
|
+
# Numeric
|
|
17
|
+
ERR_GT = 'gt'
|
|
18
|
+
ERR_GTE = 'gte'
|
|
19
|
+
ERR_LT = 'lt'
|
|
20
|
+
ERR_LTE = 'lte'
|
|
21
|
+
# String
|
|
22
|
+
ERR_LEN = 'len'
|
|
23
|
+
ERR_MIN = 'min'
|
|
24
|
+
ERR_MAX = 'max'
|
|
25
|
+
ERR_REGEXP = 'regexp'
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Asserts
|
|
3
|
+
|
|
4
|
+
module NumericAssert
|
|
5
|
+
def assert_numeric_gt opt_value, value, errors, error_code=Fields::FieldBase::ERR_GT
|
|
6
|
+
return nil if opt_value.nil?
|
|
7
|
+
if value <= opt_value
|
|
8
|
+
errors << {
|
|
9
|
+
type: err(error_code),
|
|
10
|
+
data: {
|
|
11
|
+
_val: value,
|
|
12
|
+
gt: opt_value,
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return false
|
|
16
|
+
end
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
def assert_numeric_gte opt_value, value, errors, error_code=Fields::FieldBase::ERR_GTE
|
|
21
|
+
return nil if opt_value.nil?
|
|
22
|
+
if value < opt_value
|
|
23
|
+
errors << {
|
|
24
|
+
type: err(error_code),
|
|
25
|
+
data: {
|
|
26
|
+
_val: value,
|
|
27
|
+
gte: opt_value,
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
return false
|
|
31
|
+
end
|
|
32
|
+
true
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def assert_numeric_lt opt_value, value, errors, error_code=Fields::FieldBase::ERR_LT
|
|
36
|
+
return nil if opt_value.nil?
|
|
37
|
+
if value >= opt_value
|
|
38
|
+
errors << {
|
|
39
|
+
type: err(error_code),
|
|
40
|
+
data: {
|
|
41
|
+
_val: value,
|
|
42
|
+
lt: opt_value,
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
return false
|
|
46
|
+
end
|
|
47
|
+
true
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def assert_numeric_lte opt_value, value, errors, error_code=Fields::FieldBase::ERR_LTE
|
|
51
|
+
return nil if opt_value.nil?
|
|
52
|
+
if value > opt_value
|
|
53
|
+
errors << {
|
|
54
|
+
type: err(error_code),
|
|
55
|
+
data: {
|
|
56
|
+
_val: value,
|
|
57
|
+
lte: opt_value,
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
return false
|
|
61
|
+
end
|
|
62
|
+
true
|
|
63
|
+
end
|
|
64
|
+
end
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Asserts
|
|
3
|
+
|
|
4
|
+
module SizeAssert
|
|
5
|
+
def assert_size_len opt_value, value, errors, error_code=Fields::FieldBase::ERR_SIZE_LEN
|
|
6
|
+
return nil if opt_value.nil?
|
|
7
|
+
unless value.size == opt_value
|
|
8
|
+
errors << {
|
|
9
|
+
type: err(error_code),
|
|
10
|
+
data: {
|
|
11
|
+
_val: value,
|
|
12
|
+
len: opt_value,
|
|
13
|
+
got: value.size,
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
return false
|
|
17
|
+
end
|
|
18
|
+
true
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def assert_size_min opt_value, value, errors, error_code=Fields::FieldBase::ERR_SIZE_MIN
|
|
22
|
+
return nil if opt_value.nil?
|
|
23
|
+
if value.size < opt_value
|
|
24
|
+
errors << {
|
|
25
|
+
type: err(error_code),
|
|
26
|
+
data: {
|
|
27
|
+
_val: value,
|
|
28
|
+
min: opt_value,
|
|
29
|
+
got: value.size,
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
return false
|
|
33
|
+
end
|
|
34
|
+
true
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def assert_size_max opt_value, value, errors, error_code=Fields::FieldBase::ERR_SIZE_MAX
|
|
38
|
+
return nil if opt_value.nil?
|
|
39
|
+
if value.size > opt_value
|
|
40
|
+
errors << {
|
|
41
|
+
type: err(error_code),
|
|
42
|
+
data: {
|
|
43
|
+
_val: value,
|
|
44
|
+
max: opt_value,
|
|
45
|
+
got: value.size,
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return false
|
|
49
|
+
end
|
|
50
|
+
true
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Asserts
|
|
3
|
+
|
|
4
|
+
module StringAssert
|
|
5
|
+
def assert_string_regexp opt_value, value, errors, error_code=Fields::FieldBase::ERR_REGEXP
|
|
6
|
+
return nil if opt_value.nil?
|
|
7
|
+
unless value =~ opt_value
|
|
8
|
+
errors << {
|
|
9
|
+
type: err(error_code),
|
|
10
|
+
data: {
|
|
11
|
+
_val: value,
|
|
12
|
+
regexp: opt_value,
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
return false
|
|
16
|
+
end
|
|
17
|
+
true
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Saphyr
|
|
4
|
+
# Group all modules related to atomic assertions.
|
|
5
|
+
#
|
|
6
|
+
# @api private
|
|
7
|
+
module Asserts
|
|
8
|
+
end
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
require_relative './asserts/error_constants'
|
|
12
|
+
require_relative './asserts/base_assert'
|
|
13
|
+
require_relative './asserts/size_assert'
|
|
14
|
+
require_relative './asserts/numeric_assert'
|
|
15
|
+
require_relative './asserts/string_assert'
|
|
@@ -0,0 +1,220 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
module Saphyr
|
|
4
|
+
|
|
5
|
+
# The engine used to handle the validation processus.
|
|
6
|
+
# @api private
|
|
7
|
+
class Engine
|
|
8
|
+
|
|
9
|
+
# Class used to encapsule the validation engine context.
|
|
10
|
+
# @api private
|
|
11
|
+
class Context
|
|
12
|
+
attr_reader :validators, :schema, :data, :fragment, :path, :errors
|
|
13
|
+
|
|
14
|
+
def initialize(validators, schema, data, fragment, path, errors=[])
|
|
15
|
+
@validators = validators
|
|
16
|
+
@schema = schema
|
|
17
|
+
@data = data
|
|
18
|
+
@fragment = fragment
|
|
19
|
+
@path = path
|
|
20
|
+
@errors = errors
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
# Create a new context derived from the current one.
|
|
24
|
+
# @param schema [Saphyr::Schema] The schema associated with the new context.
|
|
25
|
+
# @param fragment [Hash] The data fragment.
|
|
26
|
+
# @param path [String] The path of the new context.
|
|
27
|
+
def derive(schema, fragment, path)
|
|
28
|
+
Context.new @validators, schema, @data, fragment, path, @errors
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
# Get the current field path from the root of the document.
|
|
32
|
+
# @return [String]
|
|
33
|
+
def get_path(name)
|
|
34
|
+
return @path + name if @path == '//'
|
|
35
|
+
return @path if name == ''
|
|
36
|
+
@path + '.' + name
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
# Find a schema given his name.
|
|
40
|
+
# Lookup first into the local validators if there isn't any schema found then
|
|
41
|
+
# lookup into the global schemas.
|
|
42
|
+
# @param name [Symbol] The name of the schema.
|
|
43
|
+
# @return [Saphyr::Schema]
|
|
44
|
+
# @rmaise [Saphyr::Error] if no schema was found.
|
|
45
|
+
def find_schema(name)
|
|
46
|
+
@validators.each do |validator|
|
|
47
|
+
schema = validator.find_schema name
|
|
48
|
+
return schema unless schema.nil?
|
|
49
|
+
end
|
|
50
|
+
schema = Saphyr.global_schema name
|
|
51
|
+
raise Saphyr::Error.new "Cannot find schema name: #{name}" if schema.nil?
|
|
52
|
+
schema
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Get data needed for validation
|
|
56
|
+
# @return The full data or a fragment of data is it exists.
|
|
57
|
+
def data_to_validate()
|
|
58
|
+
return @data if @fragment.nil?
|
|
59
|
+
@fragment
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
# -----
|
|
64
|
+
|
|
65
|
+
def initialize(ctx)
|
|
66
|
+
@ctx = ctx
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
def validate
|
|
70
|
+
array_validation if @ctx.schema.root_array?
|
|
71
|
+
object_validation if @ctx.schema.root_object?
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
private
|
|
75
|
+
|
|
76
|
+
def array_validation()
|
|
77
|
+
fields = @ctx.schema.fields
|
|
78
|
+
unless fields.size == 1
|
|
79
|
+
raise Saphyr::Error.new 'When root is :array, only :_root_ field must exists'
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
field = fields['_root_']
|
|
83
|
+
if field.nil?
|
|
84
|
+
raise Saphyr::Error.new 'When root is :array, must define :_root_ field'
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
errors = field.validate @ctx, '', @ctx.data_to_validate
|
|
88
|
+
unless errors.size == 0
|
|
89
|
+
@ctx.errors << {
|
|
90
|
+
path: '//',
|
|
91
|
+
errors: errors,
|
|
92
|
+
}
|
|
93
|
+
end
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
def object_validation()
|
|
97
|
+
# Computte all conditional fields
|
|
98
|
+
allowed_cond_fields = []
|
|
99
|
+
forbidden_cond_fields = []
|
|
100
|
+
@ctx.schema.conditionals.each do |data|
|
|
101
|
+
condition, schema = data
|
|
102
|
+
if @ctx.validators.last.send condition
|
|
103
|
+
allowed_cond_fields += schema.fields.keys
|
|
104
|
+
else
|
|
105
|
+
forbidden_cond_fields += schema.fields.keys
|
|
106
|
+
end
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
do_validation @ctx.schema, allowed_cond_fields, forbidden_cond_fields, []
|
|
110
|
+
|
|
111
|
+
fields = @ctx.schema.fields.keys
|
|
112
|
+
@ctx.schema.conditionals.each do |data|
|
|
113
|
+
condition, schema = data
|
|
114
|
+
|
|
115
|
+
if @ctx.validators.last.send condition
|
|
116
|
+
do_validation schema, allowed_cond_fields, forbidden_cond_fields, fields
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
def do_validation(schema, allowed_cond_fields, forbidden_cond_fields, exclude_fields)
|
|
122
|
+
data = @ctx.data_to_validate
|
|
123
|
+
|
|
124
|
+
# Apply casting
|
|
125
|
+
schema.casts.each_pair do |field, method|
|
|
126
|
+
data[field] = @ctx.validators.last.send method, data[field]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
fields = schema.fields
|
|
130
|
+
field_keys = fields.keys
|
|
131
|
+
data_keys = data.keys
|
|
132
|
+
|
|
133
|
+
field_names = field_keys.union data_keys
|
|
134
|
+
field_names.each do |name|
|
|
135
|
+
field_path = @ctx.get_path name
|
|
136
|
+
field = fields[name]
|
|
137
|
+
|
|
138
|
+
if field.nil?
|
|
139
|
+
next unless @ctx.schema.strict?
|
|
140
|
+
next if allowed_cond_fields.include? name
|
|
141
|
+
next if exclude_fields.include? name
|
|
142
|
+
|
|
143
|
+
# If there is already an error for this field we skip adding a new one
|
|
144
|
+
# Bacause if there are many conditional schema, each one will add
|
|
145
|
+
# the field errors.
|
|
146
|
+
k = @ctx.errors.select { |err| err[:path] == field_path }
|
|
147
|
+
next if k.size != 0
|
|
148
|
+
|
|
149
|
+
if forbidden_cond_fields.include? name
|
|
150
|
+
@ctx.errors << {
|
|
151
|
+
path: field_path,
|
|
152
|
+
errors: [
|
|
153
|
+
{
|
|
154
|
+
type: 'conditional:not-allowed',
|
|
155
|
+
data: { field: name }
|
|
156
|
+
},
|
|
157
|
+
],
|
|
158
|
+
}
|
|
159
|
+
else
|
|
160
|
+
@ctx.errors << {
|
|
161
|
+
path: field_path,
|
|
162
|
+
errors: [
|
|
163
|
+
{
|
|
164
|
+
type: 'strict_mode:missing_in_schema',
|
|
165
|
+
data: { field: name }
|
|
166
|
+
},
|
|
167
|
+
],
|
|
168
|
+
}
|
|
169
|
+
end
|
|
170
|
+
next
|
|
171
|
+
end
|
|
172
|
+
|
|
173
|
+
unless data.key? name
|
|
174
|
+
next unless @ctx.schema.strict?
|
|
175
|
+
if field.required?
|
|
176
|
+
@ctx.errors << {
|
|
177
|
+
path: field_path,
|
|
178
|
+
errors: [
|
|
179
|
+
{
|
|
180
|
+
type: 'strict_mode:missing_in_data',
|
|
181
|
+
data: {
|
|
182
|
+
field: name,
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
],
|
|
186
|
+
}
|
|
187
|
+
end
|
|
188
|
+
next
|
|
189
|
+
end
|
|
190
|
+
|
|
191
|
+
value = data[name]
|
|
192
|
+
|
|
193
|
+
if value.nil?
|
|
194
|
+
unless field.nullable?
|
|
195
|
+
@ctx.errors << {
|
|
196
|
+
path: field_path,
|
|
197
|
+
errors: [
|
|
198
|
+
{
|
|
199
|
+
type: Saphyr::Fields::FieldBase::ERR_NOT_NULLABLE,
|
|
200
|
+
data: {
|
|
201
|
+
field: name,
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
],
|
|
205
|
+
}
|
|
206
|
+
end
|
|
207
|
+
next
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
errors = field.validate @ctx, name, value
|
|
211
|
+
unless errors.size == 0
|
|
212
|
+
@ctx.errors << {
|
|
213
|
+
path: field_path,
|
|
214
|
+
errors: errors,
|
|
215
|
+
}
|
|
216
|
+
end
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Fields
|
|
3
|
+
|
|
4
|
+
class ArrayField < FieldBase
|
|
5
|
+
PREFIX = 'array'
|
|
6
|
+
|
|
7
|
+
AUTHORIZED_OPTIONS = [:len, :min, :max, :of_type, :of_schema, :opts]
|
|
8
|
+
|
|
9
|
+
REQUIRED_ONE_OF_OPTIONS = [:of_type, :of_schema]
|
|
10
|
+
|
|
11
|
+
EXCLUSIVE_OPTIONS = [
|
|
12
|
+
[ :len, [:min, :max] ],
|
|
13
|
+
[ :of_schema, [:opts] ],
|
|
14
|
+
]
|
|
15
|
+
|
|
16
|
+
# Cannot have: min == max, use +:len+ instead
|
|
17
|
+
NOT_EQUALS_OPTIONS = [
|
|
18
|
+
[:min, :max],
|
|
19
|
+
]
|
|
20
|
+
|
|
21
|
+
# Cannot have: min > max
|
|
22
|
+
NOT_SUP_OPTIONS = [
|
|
23
|
+
[:min, :max],
|
|
24
|
+
]
|
|
25
|
+
|
|
26
|
+
def initialize(opts={})
|
|
27
|
+
super
|
|
28
|
+
|
|
29
|
+
# TODO : Check that :of_type exists
|
|
30
|
+
|
|
31
|
+
# TODO : Check that :of_schema exists
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
private
|
|
35
|
+
|
|
36
|
+
def do_validate(ctx, name, value, errors)
|
|
37
|
+
return unless assert_class Array, value, errors
|
|
38
|
+
assert_size_len @opts[:len], value, errors
|
|
39
|
+
assert_size_min @opts[:min], value, errors
|
|
40
|
+
assert_size_max @opts[:max], value, errors
|
|
41
|
+
|
|
42
|
+
of_type = @opts[:of_type]
|
|
43
|
+
unless of_type.nil?
|
|
44
|
+
opts = {}
|
|
45
|
+
field_type_opts = @opts[:opts]
|
|
46
|
+
opts = field_type_opts unless field_type_opts.nil?
|
|
47
|
+
|
|
48
|
+
# Raise exception if field type is not found
|
|
49
|
+
field_type = Saphyr.config.instanciate_field_type of_type, opts
|
|
50
|
+
value.each_with_index do |current, index|
|
|
51
|
+
field_path = make_path ctx, name, index
|
|
52
|
+
errors = field_type.validate ctx, name, current
|
|
53
|
+
if errors.size != 0
|
|
54
|
+
ctx.errors << {
|
|
55
|
+
path: field_path,
|
|
56
|
+
errors: errors,
|
|
57
|
+
}
|
|
58
|
+
end
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
of_schema = @opts[:of_schema]
|
|
63
|
+
unless of_schema.nil?
|
|
64
|
+
value.each_with_index do |current, index|
|
|
65
|
+
field_path = make_path ctx, name, index
|
|
66
|
+
schema = ctx.find_schema of_schema # Raise exceptions if not found
|
|
67
|
+
new_ctx = ctx.derive schema, current, field_path
|
|
68
|
+
engine = Saphyr::Engine.new new_ctx
|
|
69
|
+
engine.validate
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
def make_path(ctx, name, index)
|
|
75
|
+
return ctx.get_path "[#{index}]" if name == ''
|
|
76
|
+
ctx.get_path "#{name}.[#{index}]"
|
|
77
|
+
end
|
|
78
|
+
end
|
|
79
|
+
end
|
|
80
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
module Saphyr
|
|
2
|
+
module Fields
|
|
3
|
+
|
|
4
|
+
# The +boolean+ field type
|
|
5
|
+
#
|
|
6
|
+
# Allowed options are: +:eq+.
|
|
7
|
+
class BooleanField < FieldBase
|
|
8
|
+
PREFIX = 'boolean'
|
|
9
|
+
|
|
10
|
+
AUTHORIZED_OPTIONS = [:eq]
|
|
11
|
+
|
|
12
|
+
private
|
|
13
|
+
|
|
14
|
+
def do_validate(ctx, name, value, errors)
|
|
15
|
+
return unless assert_class [TrueClass, FalseClass], value, errors
|
|
16
|
+
assert_eq @opts[:eq], value, errors
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|