schemacop 2.4.5 → 3.0.0.rc2
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/.gitignore +3 -0
- data/.rubocop.yml +25 -1
- data/.travis.yml +3 -1
- data/CHANGELOG.md +32 -1
- data/README.md +53 -710
- data/README_V2.md +775 -0
- data/README_V3.md +1195 -0
- data/Rakefile +8 -12
- data/VERSION +1 -1
- data/lib/schemacop.rb +35 -36
- data/lib/schemacop/base_schema.rb +37 -0
- data/lib/schemacop/railtie.rb +10 -0
- data/lib/schemacop/schema.rb +1 -60
- data/lib/schemacop/schema2.rb +22 -0
- data/lib/schemacop/schema3.rb +21 -0
- data/lib/schemacop/scoped_env.rb +25 -13
- data/lib/schemacop/v2.rb +26 -0
- data/lib/schemacop/{caster.rb → v2/caster.rb} +16 -2
- data/lib/schemacop/{collector.rb → v2/collector.rb} +5 -2
- data/lib/schemacop/{dupper.rb → v2/dupper.rb} +1 -1
- data/lib/schemacop/{field_node.rb → v2/field_node.rb} +4 -3
- data/lib/schemacop/v2/node.rb +142 -0
- data/lib/schemacop/{node_resolver.rb → v2/node_resolver.rb} +1 -1
- data/lib/schemacop/v2/node_supporting_field.rb +70 -0
- data/lib/schemacop/{node_supporting_type.rb → v2/node_supporting_type.rb} +14 -11
- data/lib/schemacop/{node_with_block.rb → v2/node_with_block.rb} +3 -2
- data/lib/schemacop/v2/root_node.rb +6 -0
- data/lib/schemacop/v2/validator/array_validator.rb +32 -0
- data/lib/schemacop/{validator → v2/validator}/boolean_validator.rb +1 -1
- data/lib/schemacop/v2/validator/float_validator.rb +7 -0
- data/lib/schemacop/v2/validator/hash_validator.rb +37 -0
- data/lib/schemacop/v2/validator/integer_validator.rb +7 -0
- data/lib/schemacop/{validator → v2/validator}/nil_validator.rb +1 -1
- data/lib/schemacop/v2/validator/number_validator.rb +21 -0
- data/lib/schemacop/v2/validator/object_validator.rb +29 -0
- data/lib/schemacop/v2/validator/string_validator.rb +39 -0
- data/lib/schemacop/{validator → v2/validator}/symbol_validator.rb +1 -1
- data/lib/schemacop/v3.rb +45 -0
- data/lib/schemacop/v3/all_of_node.rb +27 -0
- data/lib/schemacop/v3/any_of_node.rb +28 -0
- data/lib/schemacop/v3/array_node.rb +218 -0
- data/lib/schemacop/v3/boolean_node.rb +16 -0
- data/lib/schemacop/v3/combination_node.rb +45 -0
- data/lib/schemacop/v3/context.rb +17 -0
- data/lib/schemacop/v3/dsl_scope.rb +46 -0
- data/lib/schemacop/v3/global_context.rb +114 -0
- data/lib/schemacop/v3/hash_node.rb +256 -0
- data/lib/schemacop/v3/integer_node.rb +13 -0
- data/lib/schemacop/v3/is_not_node.rb +32 -0
- data/lib/schemacop/v3/node.rb +215 -0
- data/lib/schemacop/v3/node_registry.rb +49 -0
- data/lib/schemacop/v3/number_node.rb +18 -0
- data/lib/schemacop/v3/numeric_node.rb +76 -0
- data/lib/schemacop/v3/object_node.rb +40 -0
- data/lib/schemacop/v3/one_of_node.rb +28 -0
- data/lib/schemacop/v3/reference_node.rb +49 -0
- data/lib/schemacop/v3/result.rb +58 -0
- data/lib/schemacop/v3/string_node.rb +124 -0
- data/lib/schemacop/v3/symbol_node.rb +13 -0
- data/schemacop.gemspec +24 -27
- data/test/lib/test_helper.rb +152 -0
- data/test/schemas/nested/group.rb +6 -0
- data/test/schemas/user.rb +7 -0
- data/test/unit/schemacop/v2/casting_test.rb +120 -0
- data/test/unit/schemacop/v2/collector_test.rb +47 -0
- data/test/unit/schemacop/v2/custom_check_test.rb +95 -0
- data/test/unit/schemacop/v2/custom_if_test.rb +97 -0
- data/test/unit/schemacop/v2/defaults_test.rb +95 -0
- data/test/unit/schemacop/v2/empty_test.rb +16 -0
- data/test/unit/schemacop/v2/nil_dis_allow_test.rb +43 -0
- data/test/unit/schemacop/v2/node_resolver_test.rb +28 -0
- data/test/unit/schemacop/v2/short_forms_test.rb +351 -0
- data/test/unit/schemacop/v2/types_test.rb +88 -0
- data/test/unit/schemacop/v2/validator_array_test.rb +99 -0
- data/test/unit/schemacop/v2/validator_boolean_test.rb +17 -0
- data/test/unit/schemacop/v2/validator_float_test.rb +59 -0
- data/test/unit/schemacop/v2/validator_hash_test.rb +95 -0
- data/test/unit/schemacop/v2/validator_integer_test.rb +48 -0
- data/test/unit/schemacop/v2/validator_nil_test.rb +15 -0
- data/test/unit/schemacop/v2/validator_number_test.rb +62 -0
- data/test/unit/schemacop/v2/validator_object_test.rb +141 -0
- data/test/unit/schemacop/v2/validator_string_test.rb +78 -0
- data/test/unit/schemacop/v2/validator_symbol_test.rb +18 -0
- data/test/unit/schemacop/v3/all_of_node_test.rb +198 -0
- data/test/unit/schemacop/v3/any_of_node_test.rb +218 -0
- data/test/unit/schemacop/v3/array_node_test.rb +815 -0
- data/test/unit/schemacop/v3/boolean_node_test.rb +126 -0
- data/test/unit/schemacop/v3/global_context_test.rb +164 -0
- data/test/unit/schemacop/v3/hash_node_test.rb +884 -0
- data/test/unit/schemacop/v3/integer_node_test.rb +323 -0
- data/test/unit/schemacop/v3/is_not_node_test.rb +173 -0
- data/test/unit/schemacop/v3/node_test.rb +148 -0
- data/test/unit/schemacop/v3/number_node_test.rb +292 -0
- data/test/unit/schemacop/v3/object_node_test.rb +170 -0
- data/test/unit/schemacop/v3/one_of_node_test.rb +187 -0
- data/test/unit/schemacop/v3/reference_node_test.rb +351 -0
- data/test/unit/schemacop/v3/string_node_test.rb +334 -0
- data/test/unit/schemacop/v3/symbol_node_test.rb +75 -0
- metadata +152 -145
- data/doc/Schemacop.html +0 -146
- data/doc/Schemacop/ArrayValidator.html +0 -329
- data/doc/Schemacop/BooleanValidator.html +0 -145
- data/doc/Schemacop/Caster.html +0 -379
- data/doc/Schemacop/Collector.html +0 -787
- data/doc/Schemacop/Dupper.html +0 -214
- data/doc/Schemacop/Exceptions.html +0 -115
- data/doc/Schemacop/Exceptions/InvalidSchemaError.html +0 -124
- data/doc/Schemacop/Exceptions/ValidationError.html +0 -124
- data/doc/Schemacop/FieldNode.html +0 -421
- data/doc/Schemacop/FloatValidator.html +0 -158
- data/doc/Schemacop/HashValidator.html +0 -293
- data/doc/Schemacop/IntegerValidator.html +0 -158
- data/doc/Schemacop/NilValidator.html +0 -145
- data/doc/Schemacop/Node.html +0 -1438
- data/doc/Schemacop/NodeResolver.html +0 -258
- data/doc/Schemacop/NodeSupportingField.html +0 -590
- data/doc/Schemacop/NodeSupportingType.html +0 -612
- data/doc/Schemacop/NodeWithBlock.html +0 -289
- data/doc/Schemacop/NumberValidator.html +0 -232
- data/doc/Schemacop/ObjectValidator.html +0 -298
- data/doc/Schemacop/RootNode.html +0 -171
- data/doc/Schemacop/Schema.html +0 -699
- data/doc/Schemacop/StringValidator.html +0 -295
- data/doc/Schemacop/SymbolValidator.html +0 -145
- data/doc/ScopedEnv.html +0 -351
- data/doc/_index.html +0 -379
- data/doc/class_list.html +0 -51
- data/doc/css/common.css +0 -1
- data/doc/css/full_list.css +0 -58
- data/doc/css/style.css +0 -496
- data/doc/file.README.html +0 -833
- data/doc/file_list.html +0 -56
- data/doc/frames.html +0 -17
- data/doc/index.html +0 -833
- data/doc/inheritance.graphml +0 -524
- data/doc/inheritance.pdf +0 -825
- data/doc/js/app.js +0 -303
- data/doc/js/full_list.js +0 -216
- data/doc/js/jquery.js +0 -4
- data/doc/method_list.html +0 -587
- data/doc/top-level-namespace.html +0 -112
- data/lib/schemacop/node.rb +0 -139
- data/lib/schemacop/node_supporting_field.rb +0 -58
- data/lib/schemacop/root_node.rb +0 -4
- data/lib/schemacop/validator/array_validator.rb +0 -30
- data/lib/schemacop/validator/float_validator.rb +0 -5
- data/lib/schemacop/validator/hash_validator.rb +0 -35
- data/lib/schemacop/validator/integer_validator.rb +0 -5
- data/lib/schemacop/validator/number_validator.rb +0 -19
- data/lib/schemacop/validator/object_validator.rb +0 -27
- data/lib/schemacop/validator/string_validator.rb +0 -37
- data/test/casting_test.rb +0 -90
- data/test/collector_test.rb +0 -45
- data/test/custom_check_test.rb +0 -93
- data/test/custom_if_test.rb +0 -95
- data/test/defaults_test.rb +0 -93
- data/test/empty_test.rb +0 -14
- data/test/nil_dis_allow_test.rb +0 -41
- data/test/node_resolver_test.rb +0 -26
- data/test/short_forms_test.rb +0 -349
- data/test/test_helper.rb +0 -13
- data/test/types_test.rb +0 -84
- data/test/validator_array_test.rb +0 -97
- data/test/validator_boolean_test.rb +0 -15
- data/test/validator_float_test.rb +0 -57
- data/test/validator_hash_test.rb +0 -93
- data/test/validator_integer_test.rb +0 -46
- data/test/validator_nil_test.rb +0 -13
- data/test/validator_number_test.rb +0 -60
- data/test/validator_object_test.rb +0 -139
- data/test/validator_string_test.rb +0 -76
- data/test/validator_symbol_test.rb +0 -16
@@ -0,0 +1,142 @@
|
|
1
|
+
module Schemacop
|
2
|
+
module V2
|
3
|
+
class Node
|
4
|
+
attr_reader :options
|
5
|
+
|
6
|
+
class_attribute :allowed_options
|
7
|
+
self.allowed_options = {}.freeze
|
8
|
+
|
9
|
+
class_attribute :symbols
|
10
|
+
self.symbols = [].freeze
|
11
|
+
|
12
|
+
class_attribute :klasses
|
13
|
+
self.klasses = [].freeze
|
14
|
+
|
15
|
+
def self.option(key, default: nil)
|
16
|
+
self.allowed_options = allowed_options.merge(key => default)
|
17
|
+
end
|
18
|
+
|
19
|
+
option :if
|
20
|
+
option :check
|
21
|
+
option :cast
|
22
|
+
option :default
|
23
|
+
|
24
|
+
def type_label
|
25
|
+
str = (symbols.first || 'unknown').to_s
|
26
|
+
str += '*' if option?(:if)
|
27
|
+
return str
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.symbol(symbol)
|
31
|
+
self.symbols += [symbol]
|
32
|
+
end
|
33
|
+
|
34
|
+
def self.clear_symbols
|
35
|
+
self.symbols = [].freeze
|
36
|
+
end
|
37
|
+
|
38
|
+
def self.klass(klass)
|
39
|
+
self.klasses += [klass]
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.clear_klasses
|
43
|
+
self.klasses = [].freeze
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.register(symbols: [], klasses: [], clear: true, before: nil)
|
47
|
+
NodeResolver.register(self, before: before)
|
48
|
+
symbols = [*symbols]
|
49
|
+
klasses = [*klasses]
|
50
|
+
if clear
|
51
|
+
clear_symbols
|
52
|
+
clear_klasses
|
53
|
+
end
|
54
|
+
symbols.each { |s| symbol s }
|
55
|
+
klasses.each { |k| klass k }
|
56
|
+
end
|
57
|
+
|
58
|
+
def self.type_matches?(type)
|
59
|
+
symbol_matches?(type) || class_matches?(type)
|
60
|
+
end
|
61
|
+
|
62
|
+
def self.symbol_matches?(type)
|
63
|
+
return false unless type.is_a?(Symbol)
|
64
|
+
|
65
|
+
symbols.include?(type)
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.class_matches?(type)
|
69
|
+
return false unless type.is_a?(Class)
|
70
|
+
|
71
|
+
klasses.each do |klass|
|
72
|
+
return true if type <= klass
|
73
|
+
end
|
74
|
+
return false
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.build(options, &block)
|
78
|
+
new(options, &block)
|
79
|
+
end
|
80
|
+
|
81
|
+
def initialize(options = {})
|
82
|
+
# Check and save given options
|
83
|
+
@options = self.class.allowed_options.merge(options)
|
84
|
+
if (obsolete_opts = @options.keys - self.class.allowed_options.keys).any?
|
85
|
+
fail Exceptions::InvalidSchemaError,
|
86
|
+
"Unrecognized option(s) #{obsolete_opts.inspect} for #{self.class.inspect}, allowed options: #{self.class.allowed_options.keys.inspect}."
|
87
|
+
end
|
88
|
+
|
89
|
+
if option?(:cast) && self.class.klasses.size > 1
|
90
|
+
fail Exceptions::InvalidSchemaError,
|
91
|
+
"Casting is only allowed for single-value datatypes, but type #{self.class.inspect} has classes "\
|
92
|
+
"#{self.class.klasses.map(&:inspect)}."
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
def option(key)
|
97
|
+
options[key]
|
98
|
+
end
|
99
|
+
|
100
|
+
def option?(key)
|
101
|
+
!!options[key]
|
102
|
+
end
|
103
|
+
|
104
|
+
def exec_block
|
105
|
+
fail Exceptions::InvalidSchemaError, 'Node does not support block.' if block_given?
|
106
|
+
end
|
107
|
+
|
108
|
+
def resolve_type_klass(type)
|
109
|
+
klass = NodeResolver.resolve(type)
|
110
|
+
unless klass
|
111
|
+
fail Exceptions::InvalidSchemaError, "No validation class found for type #{type.inspect}."
|
112
|
+
end
|
113
|
+
|
114
|
+
return klass
|
115
|
+
end
|
116
|
+
|
117
|
+
def validate(data, collector)
|
118
|
+
validate_custom_check(data, collector)
|
119
|
+
end
|
120
|
+
|
121
|
+
def type_matches?(data)
|
122
|
+
self.class.type_matches?(data.class) && type_filter_matches?(data)
|
123
|
+
end
|
124
|
+
|
125
|
+
def type_filter_matches?(data)
|
126
|
+
!option?(:if) || option(:if).call(data)
|
127
|
+
end
|
128
|
+
|
129
|
+
protected
|
130
|
+
|
131
|
+
def validate_custom_check(data, collector)
|
132
|
+
if option?(:check) && (check_result = option(:check).call(data)) != true
|
133
|
+
if check_result.is_a?(String)
|
134
|
+
collector.error "Custom :check failed: #{check_result}."
|
135
|
+
else
|
136
|
+
collector.error 'Custom :check failed.'
|
137
|
+
end
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module Schemacop::V2
|
2
|
+
class NodeSupportingField < NodeWithBlock
|
3
|
+
block_method :req?
|
4
|
+
block_method :req!
|
5
|
+
block_method :req
|
6
|
+
block_method :opt?
|
7
|
+
block_method :opt!
|
8
|
+
block_method :opt
|
9
|
+
|
10
|
+
attr_reader :fields
|
11
|
+
|
12
|
+
def initialize(options = {}, &block)
|
13
|
+
@fields = {}
|
14
|
+
super
|
15
|
+
exec_block(&block)
|
16
|
+
end
|
17
|
+
|
18
|
+
def req?(*args, **kwargs, &block)
|
19
|
+
kwargs ||= {}
|
20
|
+
kwargs[:required] = true
|
21
|
+
kwargs[:allow_nil] = true
|
22
|
+
field(*args, **kwargs, &block)
|
23
|
+
end
|
24
|
+
|
25
|
+
def req!(*args, **kwargs, &block)
|
26
|
+
kwargs ||= {}
|
27
|
+
kwargs[:required] = true
|
28
|
+
kwargs[:allow_nil] = false
|
29
|
+
field(*args, **kwargs, &block)
|
30
|
+
end
|
31
|
+
|
32
|
+
alias req req!
|
33
|
+
|
34
|
+
def opt?(*args, **kwargs, &block)
|
35
|
+
kwargs ||= {}
|
36
|
+
kwargs[:required] = false
|
37
|
+
kwargs[:allow_nil] = true
|
38
|
+
field(*args, **kwargs, &block)
|
39
|
+
end
|
40
|
+
|
41
|
+
def opt!(*args, **kwargs, &block)
|
42
|
+
kwargs ||= {}
|
43
|
+
kwargs[:required] = false
|
44
|
+
kwargs[:allow_nil] = false
|
45
|
+
field(*args, **kwargs, &block)
|
46
|
+
end
|
47
|
+
|
48
|
+
alias opt opt?
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
def field(*args, **kwargs, &block)
|
53
|
+
name = args.shift
|
54
|
+
required = kwargs.delete(:required)
|
55
|
+
allow_nil = kwargs.delete(:allow_nil)
|
56
|
+
|
57
|
+
if @fields[name]
|
58
|
+
@fields[name].type(*args, **kwargs, &block)
|
59
|
+
elsif args.any?
|
60
|
+
@fields[name] = FieldNode.new(name, required) do
|
61
|
+
type(*args, **kwargs, &block)
|
62
|
+
end
|
63
|
+
else
|
64
|
+
@fields[name] = FieldNode.new(name, required, &block)
|
65
|
+
end
|
66
|
+
|
67
|
+
@fields[name].type(:nil) if allow_nil
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Schemacop
|
1
|
+
module Schemacop::V2
|
2
2
|
class NodeSupportingType < NodeWithBlock
|
3
3
|
block_method :type
|
4
4
|
|
@@ -14,6 +14,7 @@ module Schemacop
|
|
14
14
|
|
15
15
|
if @types.none?
|
16
16
|
fail Exceptions::InvalidSchemaError, 'Block must contain a type definition or not be given at all.' if block_given?
|
17
|
+
|
17
18
|
type :object
|
18
19
|
end
|
19
20
|
|
@@ -32,7 +33,7 @@ module Schemacop
|
|
32
33
|
super
|
33
34
|
rescue NoMethodError
|
34
35
|
@types = []
|
35
|
-
type :hash,
|
36
|
+
type :hash, &block
|
36
37
|
end
|
37
38
|
|
38
39
|
# required signature:
|
@@ -46,8 +47,8 @@ module Schemacop
|
|
46
47
|
# happens in here directly and not in the constructor. This way we can
|
47
48
|
# always call 'type', even if we don't have one and the type is auto-guessed
|
48
49
|
# as it formerly was the case in the constructor.
|
49
|
-
def type(*args, &block)
|
50
|
-
options =
|
50
|
+
def type(*args, **kwargs, &block)
|
51
|
+
options = kwargs
|
51
52
|
types = [*args.shift]
|
52
53
|
subtypes = args
|
53
54
|
|
@@ -72,7 +73,7 @@ module Schemacop
|
|
72
73
|
end
|
73
74
|
|
74
75
|
child = klass.new do
|
75
|
-
self.type(*subtypes, options, &block)
|
76
|
+
self.type(*subtypes, **options, &block)
|
76
77
|
end
|
77
78
|
|
78
79
|
# child = klass.build(options)
|
@@ -101,16 +102,18 @@ module Schemacop
|
|
101
102
|
def cast!(data, collector)
|
102
103
|
@types.each do |type|
|
103
104
|
next unless type.option?(:cast) && !type.type_matches?(data) && type.type_filter_matches?(data)
|
105
|
+
|
104
106
|
caster = Caster.new(type.option(:cast), data, type.class.klasses.first)
|
105
107
|
|
106
108
|
next unless caster.castable?
|
109
|
+
|
107
110
|
begin
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
111
|
+
data = caster.cast
|
112
|
+
collector.override_value(data)
|
113
|
+
return data
|
114
|
+
rescue Exceptions::InvalidSchemaError => e
|
115
|
+
collector.error e.message
|
116
|
+
end
|
114
117
|
end
|
115
118
|
|
116
119
|
return data
|
@@ -1,4 +1,4 @@
|
|
1
|
-
module Schemacop
|
1
|
+
module Schemacop::V2
|
2
2
|
class NodeWithBlock < Node
|
3
3
|
class_attribute :block_methods
|
4
4
|
self.block_methods = [].freeze
|
@@ -9,7 +9,8 @@ module Schemacop
|
|
9
9
|
|
10
10
|
def exec_block(&block)
|
11
11
|
return unless block_given?
|
12
|
-
|
12
|
+
|
13
|
+
se = Schemacop::ScopedEnv.new(self, self.class.block_methods)
|
13
14
|
se.instance_exec(&block)
|
14
15
|
end
|
15
16
|
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Schemacop
|
2
|
+
module V2
|
3
|
+
class ArrayValidator < NodeSupportingType
|
4
|
+
register symbols: :array, klasses: Array
|
5
|
+
|
6
|
+
option :min # Minimal number of elements
|
7
|
+
option :max # Maximal number of elements
|
8
|
+
option :nil # Whether to allow nil values
|
9
|
+
|
10
|
+
def initialize(*args)
|
11
|
+
super
|
12
|
+
type(:nil) if option(:nil)
|
13
|
+
end
|
14
|
+
|
15
|
+
def validate(data, collector)
|
16
|
+
validate_custom_check(data, collector)
|
17
|
+
|
18
|
+
if option?(:min) && data.size < option(:min)
|
19
|
+
collector.error "Array must have more (>=) than #{option(:min)} elements."
|
20
|
+
end
|
21
|
+
if option?(:max) && data.size > option(:max)
|
22
|
+
collector.error "Array must have less (<=) than #{option(:max)} elements."
|
23
|
+
end
|
24
|
+
data.each_with_index do |entry, index|
|
25
|
+
collector.path("[#{index}]", index, :array) do
|
26
|
+
validate_types(entry, collector)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Schemacop
|
2
|
+
module V2
|
3
|
+
class HashValidator < NodeSupportingField
|
4
|
+
register symbols: :hash, klasses: Hash
|
5
|
+
|
6
|
+
option :allow_obsolete_keys
|
7
|
+
|
8
|
+
def validate(data, collector)
|
9
|
+
super
|
10
|
+
|
11
|
+
if data.is_a? ActiveSupport::HashWithIndifferentAccess
|
12
|
+
allowed_fields = @fields.keys.map { |k| k.is_a?(String) ? k.to_sym : k }
|
13
|
+
data_keys = data.keys.map { |k| k.is_a?(String) ? k.to_sym : k }
|
14
|
+
|
15
|
+
# If the same key is specified in the schema as string and symbol, we
|
16
|
+
# definitely expect a Ruby hash and not one with indifferent access
|
17
|
+
if @fields.keys.length != Set.new(allowed_fields).length
|
18
|
+
fail Exceptions::ValidationError, 'Hash expected, but got ActiveSupport::HashWithIndifferentAccess.'
|
19
|
+
end
|
20
|
+
else
|
21
|
+
allowed_fields = @fields.keys
|
22
|
+
data_keys = data.keys
|
23
|
+
end
|
24
|
+
|
25
|
+
obsolete_keys = data_keys - allowed_fields
|
26
|
+
|
27
|
+
if !option?(:allow_obsolete_keys) && obsolete_keys.any?
|
28
|
+
collector.error "Obsolete keys: #{obsolete_keys.inspect}."
|
29
|
+
end
|
30
|
+
|
31
|
+
@fields.each_value do |field|
|
32
|
+
field.validate(data, collector)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Schemacop
|
2
|
+
module V2
|
3
|
+
class NumberValidator < Node
|
4
|
+
register symbols: :number, klasses: [Integer, Float]
|
5
|
+
|
6
|
+
option :min
|
7
|
+
option :max
|
8
|
+
|
9
|
+
def validate(data, collector)
|
10
|
+
super
|
11
|
+
|
12
|
+
if option?(:min) && data < option(:min)
|
13
|
+
collector.error "Value must be >= #{option(:min)}."
|
14
|
+
end
|
15
|
+
if option?(:max) && data > option(:max)
|
16
|
+
collector.error "Value must be <= #{option(:max)}."
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Schemacop
|
2
|
+
module V2
|
3
|
+
class ObjectValidator < Node
|
4
|
+
register symbols: :object, klasses: BasicObject
|
5
|
+
|
6
|
+
option :classes
|
7
|
+
option :strict
|
8
|
+
|
9
|
+
def type_label
|
10
|
+
"#{super} (#{classes.join(', ')})"
|
11
|
+
end
|
12
|
+
|
13
|
+
def type_matches?(data)
|
14
|
+
if option(:strict).is_a?(FalseClass)
|
15
|
+
sub_or_class = classes.map { |klass| data.class <= klass }.include?(true)
|
16
|
+
super && (classes.empty? || sub_or_class) && !data.nil?
|
17
|
+
else
|
18
|
+
super && (classes.empty? || classes.include?(data.class)) && !data.nil?
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
private
|
23
|
+
|
24
|
+
def classes
|
25
|
+
[*option(:classes)]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|