json-schema-pvdgm 2.3.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 +7 -0
- data/LICENSE.md +19 -0
- data/README.textile +354 -0
- data/lib/json-schema.rb +25 -0
- data/lib/json-schema/attributes/additionalitems.rb +23 -0
- data/lib/json-schema/attributes/additionalproperties.rb +67 -0
- data/lib/json-schema/attributes/allof.rb +37 -0
- data/lib/json-schema/attributes/anyof.rb +41 -0
- data/lib/json-schema/attributes/dependencies.rb +30 -0
- data/lib/json-schema/attributes/dependencies_v4.rb +20 -0
- data/lib/json-schema/attributes/disallow.rb +11 -0
- data/lib/json-schema/attributes/divisibleby.rb +16 -0
- data/lib/json-schema/attributes/enum.rb +24 -0
- data/lib/json-schema/attributes/extends.rb +49 -0
- data/lib/json-schema/attributes/format.rb +123 -0
- data/lib/json-schema/attributes/items.rb +25 -0
- data/lib/json-schema/attributes/maxdecimal.rb +15 -0
- data/lib/json-schema/attributes/maximum.rb +15 -0
- data/lib/json-schema/attributes/maximum_inclusive.rb +15 -0
- data/lib/json-schema/attributes/maxitems.rb +12 -0
- data/lib/json-schema/attributes/maxlength.rb +14 -0
- data/lib/json-schema/attributes/maxproperties.rb +12 -0
- data/lib/json-schema/attributes/minimum.rb +15 -0
- data/lib/json-schema/attributes/minimum_inclusive.rb +15 -0
- data/lib/json-schema/attributes/minitems.rb +12 -0
- data/lib/json-schema/attributes/minlength.rb +14 -0
- data/lib/json-schema/attributes/minproperties.rb +12 -0
- data/lib/json-schema/attributes/multipleof.rb +16 -0
- data/lib/json-schema/attributes/not.rb +28 -0
- data/lib/json-schema/attributes/oneof.rb +32 -0
- data/lib/json-schema/attributes/pattern.rb +15 -0
- data/lib/json-schema/attributes/patternproperties.rb +23 -0
- data/lib/json-schema/attributes/properties.rb +58 -0
- data/lib/json-schema/attributes/properties_optional.rb +23 -0
- data/lib/json-schema/attributes/properties_v4.rb +57 -0
- data/lib/json-schema/attributes/ref.rb +70 -0
- data/lib/json-schema/attributes/required.rb +23 -0
- data/lib/json-schema/attributes/type.rb +102 -0
- data/lib/json-schema/attributes/type_v4.rb +54 -0
- data/lib/json-schema/attributes/uniqueitems.rb +16 -0
- data/lib/json-schema/model_validator.rb +85 -0
- data/lib/json-schema/schema.rb +73 -0
- data/lib/json-schema/uri/file.rb +36 -0
- data/lib/json-schema/uri/uuid.rb +285 -0
- data/lib/json-schema/util/array_set.rb +14 -0
- data/lib/json-schema/util/hash.rb +8 -0
- data/lib/json-schema/validator.rb +672 -0
- data/lib/json-schema/validators/draft1.rb +32 -0
- data/lib/json-schema/validators/draft2.rb +33 -0
- data/lib/json-schema/validators/draft3.rb +38 -0
- data/lib/json-schema/validators/draft4.rb +45 -0
- data/resources/draft-01.json +155 -0
- data/resources/draft-02.json +166 -0
- data/resources/draft-03.json +174 -0
- data/resources/draft-04.json +150 -0
- data/test/data/all_of_ref_data.json +3 -0
- data/test/data/any_of_ref_data.json +7 -0
- data/test/data/bad_data_1.json +3 -0
- data/test/data/good_data_1.json +3 -0
- data/test/data/one_of_ref_links_data.json +5 -0
- data/test/schemas/all_of_ref_base_schema.json +6 -0
- data/test/schemas/all_of_ref_schema.json +7 -0
- data/test/schemas/any_of_ref_jane_schema.json +4 -0
- data/test/schemas/any_of_ref_jimmy_schema.json +4 -0
- data/test/schemas/any_of_ref_john_schema.json +4 -0
- data/test/schemas/any_of_ref_schema.json +15 -0
- data/test/schemas/extends_and_additionalProperties-1-filename.schema.json +34 -0
- data/test/schemas/extends_and_additionalProperties-1-ref.schema.json +34 -0
- data/test/schemas/extends_and_additionalProperties-2-filename.schema.json +33 -0
- data/test/schemas/extends_and_additionalProperties-2-ref.schema.json +33 -0
- data/test/schemas/good_schema_1.json +10 -0
- data/test/schemas/good_schema_2.json +10 -0
- data/test/schemas/good_schema_extends1.json +10 -0
- data/test/schemas/good_schema_extends2.json +13 -0
- data/test/schemas/inner.schema.json +21 -0
- data/test/schemas/one_of_ref_links_schema.json +16 -0
- data/test/schemas/self_link_schema.json +17 -0
- data/test/schemas/up_link_schema.json +17 -0
- data/test/test_all_of_ref_schema.rb +11 -0
- data/test/test_any_of_ref_schema.rb +11 -0
- data/test/test_bad_schema_ref.rb +33 -0
- data/test/test_extended_schema.rb +68 -0
- data/test/test_extends_and_additionalProperties.rb +50 -0
- data/test/test_files_v3.rb +52 -0
- data/test/test_fragment_resolution.rb +31 -0
- data/test/test_full_validation.rb +209 -0
- data/test/test_jsonschema_draft1.rb +701 -0
- data/test/test_jsonschema_draft2.rb +773 -0
- data/test/test_jsonschema_draft3.rb +1236 -0
- data/test/test_jsonschema_draft4.rb +1356 -0
- data/test/test_model_validator.rb +52 -0
- data/test/test_one_of.rb +42 -0
- data/test/test_ruby_schema.rb +38 -0
- data/test/test_schema_type_attribute.rb +21 -0
- data/test/test_schema_validation.rb +85 -0
- metadata +180 -0
@@ -0,0 +1,14 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MaxLengthAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(String)
|
6
|
+
if data.length > current_schema.schema['maxLength']
|
7
|
+
message = "The property '#{build_fragment(fragments)}' was not of a maximum string length of #{current_schema.schema['maxLength']}"
|
8
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :max_length })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MaxPropertiesAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash) && (data.size > current_schema.schema['maxProperties'])
|
6
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a minimum number of properties #{current_schema.schema['maxProperties']}"
|
7
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :max_properties })
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MinimumAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Numeric)
|
6
|
+
if (current_schema.schema['exclusiveMinimum'] ? data <= current_schema.schema['minimum'] : data < current_schema.schema['minimum'])
|
7
|
+
message = "The property '#{build_fragment(fragments)}' did not have a minimum value of #{current_schema.schema['minimum']}, "
|
8
|
+
message += current_schema.schema['exclusiveMinimum'] ? 'exclusively' : 'inclusively'
|
9
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :minimum })
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MinimumInclusiveAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Numeric)
|
6
|
+
if (current_schema.schema['minimumCanEqual'] == false ? data <= current_schema.schema['minimum'] : data < current_schema.schema['minimum'])
|
7
|
+
message = "The property '#{build_fragment(fragments)}' did not have a minimum value of #{current_schema.schema['minimum']}, "
|
8
|
+
message += current_schema.schema['exclusiveMinimum'] ? 'exclusively' : 'inclusively'
|
9
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :minimum_inclusive })
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MinItemsAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Array) && (data.compact.size < current_schema.schema['minItems'])
|
6
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a minimum number of items #{current_schema.schema['minItems']}"
|
7
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :min_items })
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MinLengthAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(String)
|
6
|
+
if data.length < current_schema.schema['minLength']
|
7
|
+
message = "The property '#{build_fragment(fragments)}' was not of a minimum string length of #{current_schema.schema['minLength']}"
|
8
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :min_length })
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MinPropertiesAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash) && (data.size < current_schema.schema['minProperties'])
|
6
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a minimum number of properties #{current_schema.schema['minProperties']}"
|
7
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :min_properties })
|
8
|
+
end
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class MultipleOfAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Numeric)
|
6
|
+
if current_schema.schema['multipleOf'] == 0 ||
|
7
|
+
current_schema.schema['multipleOf'] == 0.0 ||
|
8
|
+
(BigDecimal.new(data.to_s) % BigDecimal.new(current_schema.schema['multipleOf'].to_s)).to_f != 0
|
9
|
+
message = "The property '#{build_fragment(fragments)}' was not divisible by #{current_schema.schema['multipleOf']}"
|
10
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :multiple_of })
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class NotAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
|
6
|
+
schema = JSON::Schema.new(current_schema.schema['not'],current_schema.uri,validator)
|
7
|
+
failed = true
|
8
|
+
errors_copy = processor.validation_errors.clone
|
9
|
+
begin
|
10
|
+
schema.validate(data,fragments,processor,options)
|
11
|
+
# If we're recording errors, we don't throw an exception. Instead, check the errors array length
|
12
|
+
if options[:record_errors] && errors_copy.length != processor.validation_errors.length
|
13
|
+
processor.validation_errors.replace(errors_copy)
|
14
|
+
else
|
15
|
+
message = "The property '#{build_fragment(fragments)}' of type #{data.class} matched the disallowed schema"
|
16
|
+
failed = false
|
17
|
+
end
|
18
|
+
rescue
|
19
|
+
# Yay, we failed validation.
|
20
|
+
end
|
21
|
+
|
22
|
+
unless failed
|
23
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :not })
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class OneOfAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
validation_errors = 0
|
6
|
+
current_schema.schema['oneOf'].each do |element|
|
7
|
+
schema = JSON::Schema.new(element,current_schema.uri,validator)
|
8
|
+
|
9
|
+
begin
|
10
|
+
# need to raise exceptions on error because
|
11
|
+
# schema.validate doesn't reliably return true/false
|
12
|
+
schema.validate(data,fragments,processor,options.merge(:record_errors => false))
|
13
|
+
rescue ValidationError
|
14
|
+
validation_errors += 1
|
15
|
+
end
|
16
|
+
|
17
|
+
end
|
18
|
+
|
19
|
+
case validation_errors
|
20
|
+
when current_schema.schema['oneOf'].length - 1 # correct, matched only one
|
21
|
+
message = nil
|
22
|
+
when current_schema.schema['oneOf'].length # didn't match any
|
23
|
+
message = "The property '#{build_fragment(fragments)}' of type #{data.class} did not match any of the required schemas"
|
24
|
+
else # too many matches
|
25
|
+
message = "The property '#{build_fragment(fragments)}' of type #{data.class} matched more than one of the required schemas"
|
26
|
+
end
|
27
|
+
|
28
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :one_of }) if message
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class PatternAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(String)
|
6
|
+
r = Regexp.new(current_schema.schema['pattern'])
|
7
|
+
if (r.match(data)).nil?
|
8
|
+
message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match the regex '#{current_schema.schema['pattern']}'"
|
9
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: last_fragment_as_symbol(fragments), failure: :pattern })
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class PatternPropertiesAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash)
|
6
|
+
current_schema.schema['patternProperties'].each do |property,property_schema|
|
7
|
+
r = Regexp.new(property)
|
8
|
+
|
9
|
+
# Check each key in the data hash to see if it matches the regex
|
10
|
+
data.each do |key,value|
|
11
|
+
if r.match(key)
|
12
|
+
schema = JSON::Schema.new(property_schema,current_schema.uri,validator)
|
13
|
+
fragments << key
|
14
|
+
schema.validate(data[key],fragments,processor,options)
|
15
|
+
fragments.pop
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class PropertiesAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash)
|
6
|
+
current_schema.schema['properties'].each do |property,property_schema|
|
7
|
+
if !data.has_key?(property.to_s) &&
|
8
|
+
!data.has_key?(property.to_sym) &&
|
9
|
+
property_schema['default'] &&
|
10
|
+
!property_schema['readonly'] &&
|
11
|
+
options[:insert_defaults]
|
12
|
+
default = property_schema['default']
|
13
|
+
data[property.to_s] = (default.is_a?(Hash) ? default.clone : default)
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
if (property_schema['required'] || options[:strict] == true) && !data.has_key?(property.to_s) && !data.has_key?(property.to_sym)
|
18
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
19
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: property.to_sym, failure: :properties })
|
20
|
+
end
|
21
|
+
|
22
|
+
if data.has_key?(property.to_s) || data.has_key?(property.to_sym)
|
23
|
+
schema = JSON::Schema.new(property_schema,current_schema.uri,validator)
|
24
|
+
fragments << property.to_s
|
25
|
+
schema.validate(data[property.to_s],fragments,processor,options)
|
26
|
+
fragments.pop
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# When strict is true, ensure no undefined properties exist in the data
|
31
|
+
if (options[:strict] == true && !current_schema.schema.has_key?('additionalProperties'))
|
32
|
+
diff = data.select do |k,v|
|
33
|
+
if current_schema.schema.has_key?('patternProperties')
|
34
|
+
match = false
|
35
|
+
current_schema.schema['patternProperties'].each do |property,property_schema|
|
36
|
+
r = Regexp.new(property)
|
37
|
+
if r.match(k)
|
38
|
+
match = true
|
39
|
+
break
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
!current_schema.schema['properties'].has_key?(k.to_s) && !current_schema.schema['properties'].has_key?(k.to_sym) && !match
|
44
|
+
else
|
45
|
+
!current_schema.schema['properties'].has_key?(k.to_s) && !current_schema.schema['properties'].has_key?(k.to_sym)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if diff.size > 0
|
50
|
+
message = "The property '#{build_fragment(fragments)}' contained undefined properties: '#{diff.keys.join(", ")}'"
|
51
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class PropertiesOptionalAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash)
|
6
|
+
current_schema.schema['properties'].each do |property,property_schema|
|
7
|
+
if ((property_schema['optional'].nil? || property_schema['optional'] == false) && !data.has_key?(property.to_s) && !data.has_key?(property.to_sym))
|
8
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
9
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: property.to_sym, failure: :properties_optional })
|
10
|
+
end
|
11
|
+
|
12
|
+
if data.has_key?(property.to_s) || data.has_key?(property.to_sym)
|
13
|
+
schema = JSON::Schema.new(property_schema,current_schema.uri,validator)
|
14
|
+
fragments << property
|
15
|
+
schema.validate(data[property],fragments,processor,options)
|
16
|
+
fragments.pop
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class PropertiesV4Attribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash)
|
6
|
+
current_schema.schema['properties'].each do |property,property_schema|
|
7
|
+
if !data.has_key?(property.to_s) &&
|
8
|
+
!data.has_key?(property.to_sym) &&
|
9
|
+
property_schema['default'] &&
|
10
|
+
!property_schema['readonly'] &&
|
11
|
+
options[:insert_defaults]
|
12
|
+
default = property_schema['default']
|
13
|
+
data[property.to_s] = (default.is_a?(Hash) ? default.clone : default)
|
14
|
+
end
|
15
|
+
|
16
|
+
if (options[:strict] == true && !data.has_key?(property.to_s) && !data.has_key?(property.to_sym))
|
17
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
18
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: property.to_sym, failure: :properties })
|
19
|
+
end
|
20
|
+
|
21
|
+
if data.has_key?(property.to_s) || data.has_key?(property.to_sym)
|
22
|
+
schema = JSON::Schema.new(property_schema,current_schema.uri,validator)
|
23
|
+
fragments << property.to_s
|
24
|
+
schema.validate(data[property.to_s],fragments,processor,options)
|
25
|
+
fragments.pop
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
# When strict is true, ensure no undefined properties exist in the data
|
31
|
+
if (options[:strict] == true && !current_schema.schema.has_key?('additionalProperties'))
|
32
|
+
diff = data.select do |k,v|
|
33
|
+
if current_schema.schema.has_key?('patternProperties')
|
34
|
+
match = false
|
35
|
+
current_schema.schema['patternProperties'].each do |property,property_schema|
|
36
|
+
r = Regexp.new(property)
|
37
|
+
if r.match(k)
|
38
|
+
match = true
|
39
|
+
break
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
!current_schema.schema['properties'].has_key?(k.to_s) && !current_schema.schema['properties'].has_key?(k.to_sym) && !match
|
44
|
+
else
|
45
|
+
!current_schema.schema['properties'].has_key?(k.to_s) && !current_schema.schema['properties'].has_key?(k.to_sym)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
if diff.size > 0
|
50
|
+
message = "The property '#{build_fragment(fragments)}' contained undefined properties: '#{diff.keys.join(", ")}'"
|
51
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class RefAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
uri,schema = get_referenced_uri_and_schema(current_schema.schema, current_schema, validator)
|
6
|
+
|
7
|
+
if schema
|
8
|
+
schema.validate(data, fragments, processor, options)
|
9
|
+
elsif uri
|
10
|
+
message = "The referenced schema '#{uri.to_s}' cannot be found"
|
11
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
12
|
+
else
|
13
|
+
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
14
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.get_referenced_uri_and_schema(s, current_schema, validator)
|
19
|
+
uri,schema = nil,nil
|
20
|
+
|
21
|
+
temp_uri = URI.parse(s['$ref'])
|
22
|
+
if temp_uri.relative?
|
23
|
+
temp_uri = current_schema.uri.clone
|
24
|
+
# Check for absolute path
|
25
|
+
path = s['$ref'].split("#")[0]
|
26
|
+
if path.nil? || path == ''
|
27
|
+
temp_uri.path = current_schema.uri.path
|
28
|
+
elsif path[0,1] == "/"
|
29
|
+
temp_uri.path = Pathname.new(path).cleanpath.to_s
|
30
|
+
else
|
31
|
+
temp_uri = current_schema.uri.merge(path)
|
32
|
+
end
|
33
|
+
temp_uri.fragment = s['$ref'].split("#")[1]
|
34
|
+
end
|
35
|
+
temp_uri.fragment = "" if temp_uri.fragment.nil?
|
36
|
+
|
37
|
+
# Grab the parent schema from the schema list
|
38
|
+
schema_key = temp_uri.to_s.split("#")[0] + "#"
|
39
|
+
|
40
|
+
ref_schema = JSON::Validator.schemas[schema_key]
|
41
|
+
|
42
|
+
if ref_schema
|
43
|
+
# Perform fragment resolution to retrieve the appropriate level for the schema
|
44
|
+
target_schema = ref_schema.schema
|
45
|
+
fragments = temp_uri.fragment.split("/")
|
46
|
+
fragment_path = ''
|
47
|
+
fragments.each do |fragment|
|
48
|
+
if fragment && fragment != ''
|
49
|
+
if target_schema.is_a?(Array)
|
50
|
+
target_schema = target_schema[fragment.to_i]
|
51
|
+
else
|
52
|
+
target_schema = target_schema[fragment]
|
53
|
+
end
|
54
|
+
fragment_path = fragment_path + "/#{fragment}"
|
55
|
+
if target_schema.nil?
|
56
|
+
raise SchemaError.new("The fragment '#{fragment_path}' does not exist on schema #{ref_schema.uri.to_s}")
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
# We have the schema finally, build it and validate!
|
62
|
+
uri = temp_uri
|
63
|
+
schema = JSON::Schema.new(target_schema,temp_uri,validator)
|
64
|
+
end
|
65
|
+
|
66
|
+
[uri,schema]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class RequiredAttribute < Attribute
|
4
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
5
|
+
if data.is_a?(Hash)
|
6
|
+
current_schema.schema['required'].each do |property,property_schema|
|
7
|
+
if !data.has_key?(property.to_s) && !data.has_key?(property.to_sym)
|
8
|
+
prop_defaults = options[:insert_defaults] &&
|
9
|
+
current_schema.schema['properties'] &&
|
10
|
+
current_schema.schema['properties'][property] &&
|
11
|
+
!current_schema.schema['properties'][property]["default"].nil? &&
|
12
|
+
!current_schema.schema['properties'][property]["readonly"]
|
13
|
+
if !prop_defaults
|
14
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
15
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors], { property: property.to_sym, failure: :required })
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|