json-schema-openc-fork 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +15 -0
- data/LICENSE.md +19 -0
- data/README.textile +452 -0
- data/lib/json-schema.rb +19 -0
- data/lib/json-schema/attribute.rb +43 -0
- data/lib/json-schema/attributes/additionalitems.rb +28 -0
- data/lib/json-schema/attributes/additionalproperties.rb +58 -0
- data/lib/json-schema/attributes/allof.rb +39 -0
- data/lib/json-schema/attributes/anyof.rb +47 -0
- data/lib/json-schema/attributes/dependencies.rb +44 -0
- data/lib/json-schema/attributes/disallow.rb +12 -0
- data/lib/json-schema/attributes/divisibleby.rb +22 -0
- data/lib/json-schema/attributes/enum.rb +24 -0
- data/lib/json-schema/attributes/extends.rb +50 -0
- data/lib/json-schema/attributes/format.rb +14 -0
- data/lib/json-schema/attributes/formats/custom.rb +21 -0
- data/lib/json-schema/attributes/formats/date.rb +24 -0
- data/lib/json-schema/attributes/formats/date_time.rb +36 -0
- data/lib/json-schema/attributes/formats/date_time_v4.rb +15 -0
- data/lib/json-schema/attributes/formats/ip.rb +41 -0
- data/lib/json-schema/attributes/formats/time.rb +22 -0
- data/lib/json-schema/attributes/formats/uri.rb +20 -0
- data/lib/json-schema/attributes/items.rb +26 -0
- data/lib/json-schema/attributes/limit.rb +179 -0
- data/lib/json-schema/attributes/maxdecimal.rb +18 -0
- data/lib/json-schema/attributes/multipleof.rb +11 -0
- data/lib/json-schema/attributes/not.rb +30 -0
- data/lib/json-schema/attributes/oneof.rb +56 -0
- data/lib/json-schema/attributes/pattern.rb +18 -0
- data/lib/json-schema/attributes/patternproperties.rb +22 -0
- data/lib/json-schema/attributes/properties.rb +74 -0
- data/lib/json-schema/attributes/properties_optional.rb +26 -0
- data/lib/json-schema/attributes/ref.rb +74 -0
- data/lib/json-schema/attributes/required.rb +28 -0
- data/lib/json-schema/attributes/type.rb +83 -0
- data/lib/json-schema/attributes/type_v4.rb +29 -0
- data/lib/json-schema/attributes/uniqueitems.rb +16 -0
- data/lib/json-schema/errors/custom_format_error.rb +6 -0
- data/lib/json-schema/errors/json_parse_error.rb +6 -0
- data/lib/json-schema/errors/schema_error.rb +6 -0
- data/lib/json-schema/errors/validation_error.rb +46 -0
- data/lib/json-schema/schema.rb +63 -0
- data/lib/json-schema/schema/reader.rb +113 -0
- data/lib/json-schema/schema/validator.rb +36 -0
- data/lib/json-schema/util/array_set.rb +14 -0
- data/lib/json-schema/util/uri.rb +16 -0
- data/lib/json-schema/util/uuid.rb +285 -0
- data/lib/json-schema/validator.rb +592 -0
- data/lib/json-schema/validators/draft1.rb +45 -0
- data/lib/json-schema/validators/draft2.rb +46 -0
- data/lib/json-schema/validators/draft3.rb +50 -0
- data/lib/json-schema/validators/draft4.rb +56 -0
- data/lib/json-schema/validators/hyper-draft4.rb +14 -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/address_microformat.json +18 -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/definition_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/ref john with spaces schema.json +11 -0
- data/test/schemas/relative_definition_schema.json +8 -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 +35 -0
- data/test/test_any_of_ref_schema.rb +35 -0
- data/test/test_bad_schema_ref.rb +39 -0
- data/test/test_common_test_suite.rb +66 -0
- data/test/test_custom_format.rb +116 -0
- data/test/test_definition.rb +15 -0
- data/test/test_extended_schema.rb +62 -0
- data/test/test_extends_and_additionalProperties.rb +52 -0
- data/test/test_files_v3.rb +43 -0
- data/test/test_fragment_resolution.rb +30 -0
- data/test/test_fragment_validation_with_ref.rb +34 -0
- data/test/test_full_validation.rb +208 -0
- data/test/test_helper.rb +47 -0
- data/test/test_initialize_data.rb +118 -0
- data/test/test_jsonschema_draft1.rb +171 -0
- data/test/test_jsonschema_draft2.rb +142 -0
- data/test/test_jsonschema_draft3.rb +502 -0
- data/test/test_jsonschema_draft4.rb +704 -0
- data/test/test_list_option.rb +21 -0
- data/test/test_merge_missing_values.rb +45 -0
- data/test/test_minitems.rb +16 -0
- data/test/test_one_of.rb +85 -0
- data/test/test_ruby_schema.rb +59 -0
- data/test/test_schema_loader.rb +74 -0
- data/test/test_schema_type_attribute.rb +20 -0
- data/test/test_schema_validation.rb +185 -0
- data/test/test_stringify.rb +48 -0
- data/test/test_uri_related.rb +67 -0
- data/test/test_validator.rb +53 -0
- metadata +284 -0
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class PatternAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(String)
|
8
|
+
|
9
|
+
pattern = current_schema.schema['pattern']
|
10
|
+
regexp = Regexp.new(pattern)
|
11
|
+
unless regexp.match(data)
|
12
|
+
message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match the regex '#{pattern}'"
|
13
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class PatternPropertiesAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Hash)
|
8
|
+
|
9
|
+
current_schema.schema['patternProperties'].each do |property, property_schema|
|
10
|
+
regexp = Regexp.new(property)
|
11
|
+
|
12
|
+
# Check each key in the data hash to see if it matches the regex
|
13
|
+
data.each do |key, value|
|
14
|
+
next unless regexp.match(key)
|
15
|
+
schema = JSON::Schema.new(property_schema, current_schema.uri, validator)
|
16
|
+
schema.validate(data[key], fragments + [key], processor, options)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class PropertiesAttribute < Attribute
|
6
|
+
def self.required?(schema, options)
|
7
|
+
schema.fetch('required') { options[:strict] }
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
11
|
+
return unless data.is_a?(Hash)
|
12
|
+
|
13
|
+
schema = current_schema.schema
|
14
|
+
schema['properties'].each do |property, property_schema|
|
15
|
+
property = property.to_s
|
16
|
+
|
17
|
+
if !data.key?(property) &&
|
18
|
+
options[:insert_defaults] &&
|
19
|
+
property_schema['default'] &&
|
20
|
+
!property_schema['readonly']
|
21
|
+
default = property_schema['default']
|
22
|
+
data[property] = default.is_a?(Hash) ? default.clone : default
|
23
|
+
end
|
24
|
+
|
25
|
+
if required?(property_schema, options) && !data.has_key?(property)
|
26
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
27
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
28
|
+
end
|
29
|
+
|
30
|
+
if data.has_key?(property)
|
31
|
+
expected_schema = JSON::Schema.new(property_schema, current_schema.uri, validator)
|
32
|
+
expected_schema.validate(data[property], fragments + [property], processor, options)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# When strict is true, ensure no undefined properties exist in the data
|
37
|
+
return unless options[:strict] == true && !schema.key?('additionalProperties')
|
38
|
+
|
39
|
+
diff = data.select do |k, v|
|
40
|
+
k = k.to_s
|
41
|
+
|
42
|
+
if schema.has_key?('patternProperties')
|
43
|
+
match = false
|
44
|
+
schema['patternProperties'].each do |property, property_schema|
|
45
|
+
regexp = Regexp.new(property)
|
46
|
+
if regexp.match(k)
|
47
|
+
match = true
|
48
|
+
break
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
!schema['properties'].has_key?(k) && !match
|
53
|
+
else
|
54
|
+
!schema['properties'].has_key?(k)
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
if diff.size > 0
|
59
|
+
properties = data.to_a.map { |(key, _)| key }.join(', ')
|
60
|
+
message = "The property '#{build_fragment(fragments)}' contained undefined properties: '#{properties}'"
|
61
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
class PropertiesV4Attribute < PropertiesAttribute
|
67
|
+
# draft4 relies on its own RequiredAttribute validation at a higher level, rather than
|
68
|
+
# as an attribute of individual properties.
|
69
|
+
def self.required?(schema, options)
|
70
|
+
options[:strict] == true
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class PropertiesOptionalAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Hash)
|
8
|
+
|
9
|
+
schema = current_schema.schema
|
10
|
+
schema['properties'].each do |property, property_schema|
|
11
|
+
property = property.to_s
|
12
|
+
|
13
|
+
if !property_schema['optional'] && !data.key?(property)
|
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])
|
16
|
+
end
|
17
|
+
|
18
|
+
if data.has_key?(property)
|
19
|
+
expected_schema = JSON::Schema.new(property_schema, current_schema.uri, validator)
|
20
|
+
expected_schema.validate(data[property], fragments + [property], processor, options)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
require 'json-schema/errors/schema_error'
|
3
|
+
|
4
|
+
module JSON
|
5
|
+
class Schema
|
6
|
+
class RefAttribute < Attribute
|
7
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
8
|
+
uri,schema = get_referenced_uri_and_schema(current_schema.schema, current_schema, validator)
|
9
|
+
|
10
|
+
if schema
|
11
|
+
schema.validate(data, fragments, processor, options)
|
12
|
+
elsif uri
|
13
|
+
message = "The referenced schema '#{uri.to_s}' cannot be found"
|
14
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
15
|
+
else
|
16
|
+
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
17
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.get_referenced_uri_and_schema(s, current_schema, validator)
|
22
|
+
uri,schema = nil,nil
|
23
|
+
|
24
|
+
temp_uri = Addressable::URI.parse(s['$ref'])
|
25
|
+
if temp_uri.relative?
|
26
|
+
temp_uri = current_schema.uri.clone
|
27
|
+
# Check for absolute path
|
28
|
+
path = s['$ref'].split("#")[0]
|
29
|
+
if path.nil? || path == ''
|
30
|
+
temp_uri.path = current_schema.uri.path
|
31
|
+
elsif path[0,1] == "/"
|
32
|
+
temp_uri.path = Pathname.new(path).cleanpath.to_s
|
33
|
+
else
|
34
|
+
temp_uri = current_schema.uri.join(path)
|
35
|
+
end
|
36
|
+
temp_uri.fragment = s['$ref'].split("#")[1]
|
37
|
+
end
|
38
|
+
temp_uri.fragment = "" if temp_uri.fragment.nil?
|
39
|
+
|
40
|
+
# Grab the parent schema from the schema list
|
41
|
+
schema_key = temp_uri.to_s.split("#")[0] + "#"
|
42
|
+
|
43
|
+
ref_schema = JSON::Validator.schema_for_uri(schema_key)
|
44
|
+
|
45
|
+
if ref_schema
|
46
|
+
# Perform fragment resolution to retrieve the appropriate level for the schema
|
47
|
+
target_schema = ref_schema.schema
|
48
|
+
fragments = temp_uri.fragment.split("/")
|
49
|
+
fragment_path = ''
|
50
|
+
fragments.each do |fragment|
|
51
|
+
if fragment && fragment != ''
|
52
|
+
fragment = Addressable::URI.unescape(fragment.gsub('~0', '~').gsub('~1', '/'))
|
53
|
+
if target_schema.is_a?(Array)
|
54
|
+
target_schema = target_schema[fragment.to_i]
|
55
|
+
else
|
56
|
+
target_schema = target_schema[fragment]
|
57
|
+
end
|
58
|
+
fragment_path = fragment_path + "/#{fragment}"
|
59
|
+
if target_schema.nil?
|
60
|
+
raise SchemaError.new("The fragment '#{fragment_path}' does not exist on schema #{ref_schema.uri.to_s}")
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# We have the schema finally, build it and validate!
|
66
|
+
uri = temp_uri
|
67
|
+
schema = JSON::Schema.new(target_schema,temp_uri,validator)
|
68
|
+
end
|
69
|
+
|
70
|
+
[uri,schema]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class RequiredAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Hash)
|
8
|
+
|
9
|
+
schema = current_schema.schema
|
10
|
+
defined_properties = schema['properties']
|
11
|
+
|
12
|
+
schema['required'].each do |property, property_schema|
|
13
|
+
next if data.has_key?(property.to_s)
|
14
|
+
prop_defaults = options[:insert_defaults] &&
|
15
|
+
defined_properties &&
|
16
|
+
defined_properties[property] &&
|
17
|
+
!defined_properties[property]["default"].nil? &&
|
18
|
+
!defined_properties[property]["readonly"]
|
19
|
+
|
20
|
+
if !prop_defaults
|
21
|
+
message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
|
22
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class TypeAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
union = true
|
8
|
+
if options[:disallow]
|
9
|
+
types = current_schema.schema['disallow']
|
10
|
+
else
|
11
|
+
types = current_schema.schema['type']
|
12
|
+
end
|
13
|
+
|
14
|
+
if !types.is_a?(Array)
|
15
|
+
types = [types]
|
16
|
+
union = false
|
17
|
+
end
|
18
|
+
valid = false
|
19
|
+
|
20
|
+
# Create a hash to hold errors that are generated during union validation
|
21
|
+
union_errors = Hash.new { |hsh, k| hsh[k] = [] }
|
22
|
+
|
23
|
+
types.each_with_index do |type, type_index|
|
24
|
+
if type.is_a?(String)
|
25
|
+
valid = data_valid_for_type?(data, type)
|
26
|
+
elsif type.is_a?(Hash) && union
|
27
|
+
# Validate as a schema
|
28
|
+
schema = JSON::Schema.new(type,current_schema.uri,validator)
|
29
|
+
|
30
|
+
# We're going to add a little cruft here to try and maintain any validation errors that occur in this union type
|
31
|
+
# We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto a union error
|
32
|
+
pre_validation_error_count = validation_errors(processor).count
|
33
|
+
|
34
|
+
begin
|
35
|
+
schema.validate(data,fragments,processor,options.merge(:disallow => false))
|
36
|
+
valid = true
|
37
|
+
rescue ValidationError
|
38
|
+
# We don't care that these schemas don't validate - we only care that one validated
|
39
|
+
end
|
40
|
+
|
41
|
+
diff = validation_errors(processor).count - pre_validation_error_count
|
42
|
+
valid = false if diff > 0
|
43
|
+
while diff > 0
|
44
|
+
diff = diff - 1
|
45
|
+
union_errors["type ##{type_index}"].push(validation_errors(processor).pop)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
break if valid
|
50
|
+
end
|
51
|
+
|
52
|
+
if options[:disallow]
|
53
|
+
return if !valid
|
54
|
+
message = "The property '#{build_fragment(fragments)}' matched one or more of the following types: #{list_types(types)}"
|
55
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
56
|
+
elsif !valid
|
57
|
+
if union
|
58
|
+
message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match one or more of the following types: #{list_types(types)}"
|
59
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
60
|
+
validation_errors(processor).last.sub_errors = union_errors
|
61
|
+
else
|
62
|
+
message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match the following type: #{list_types(types)}"
|
63
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def self.list_types(types)
|
69
|
+
types.map { |type| type.is_a?(String) ? type : '(schema)' }.join(', ')
|
70
|
+
end
|
71
|
+
|
72
|
+
# Lookup Schema type of given class instance
|
73
|
+
def self.type_of_data(data)
|
74
|
+
type, _ = TYPE_CLASS_MAPPINGS.map { |k,v| [k,v] }.sort_by { |(_, v)|
|
75
|
+
-Array(v).map { |klass| klass.ancestors.size }.max
|
76
|
+
}.find { |(_, v)|
|
77
|
+
Array(v).any? { |klass| data.kind_of?(klass) }
|
78
|
+
}
|
79
|
+
type
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class TypeV4Attribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
union = true
|
8
|
+
types = current_schema.schema['type']
|
9
|
+
if !types.is_a?(Array)
|
10
|
+
types = [types]
|
11
|
+
union = false
|
12
|
+
end
|
13
|
+
|
14
|
+
return if types.any? { |type| data_valid_for_type?(data, type) }
|
15
|
+
|
16
|
+
types = types.map { |type| type.is_a?(String) ? type : '(schema)' }.join(', ')
|
17
|
+
message = format(
|
18
|
+
"The property '%s' of type %s did not match %s: %s",
|
19
|
+
build_fragment(fragments),
|
20
|
+
data.class,
|
21
|
+
union ? 'one or more of the following types' : 'the following type',
|
22
|
+
types
|
23
|
+
)
|
24
|
+
|
25
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class UniqueItemsAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Array)
|
8
|
+
|
9
|
+
if data.clone.uniq!
|
10
|
+
message = "The property '#{build_fragment(fragments)}' contained duplicated array values"
|
11
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class ValidationError < StandardError
|
4
|
+
INDENT = " "
|
5
|
+
attr_accessor :fragments, :schema, :failed_attribute, :sub_errors, :message
|
6
|
+
|
7
|
+
def initialize(message, fragments, failed_attribute, schema)
|
8
|
+
@fragments = fragments.clone
|
9
|
+
@schema = schema
|
10
|
+
@sub_errors = {}
|
11
|
+
@failed_attribute = failed_attribute
|
12
|
+
@message = message
|
13
|
+
super(message_with_schema)
|
14
|
+
end
|
15
|
+
|
16
|
+
def to_string(subschema_level = 0)
|
17
|
+
if @sub_errors.empty?
|
18
|
+
subschema_level == 0 ? message_with_schema : message
|
19
|
+
else
|
20
|
+
messages = ["#{message}. The schema specific errors were:\n"]
|
21
|
+
@sub_errors.each do |subschema, errors|
|
22
|
+
messages.push "- #{subschema}:"
|
23
|
+
messages.concat Array(errors).map { |e| "#{INDENT}- #{e.to_string(subschema_level + 1)}" }
|
24
|
+
end
|
25
|
+
messages.map { |m| (INDENT * subschema_level) + m }.join("\n")
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def to_hash
|
30
|
+
base = {:schema => @schema.uri, :fragment => ::JSON::Schema::Attribute.build_fragment(fragments), :message => message_with_schema, :failed_attribute => @failed_attribute.to_s.split(":").last.split("Attribute").first}
|
31
|
+
if !@sub_errors.empty?
|
32
|
+
base[:errors] = @sub_errors.inject({}) do |hsh, (subschema, errors)|
|
33
|
+
subschema_sym = subschema.downcase.gsub(/\W+/, '_').to_sym
|
34
|
+
hsh[subschema_sym] = Array(errors).map{|e| e.to_hash}
|
35
|
+
hsh
|
36
|
+
end
|
37
|
+
end
|
38
|
+
base
|
39
|
+
end
|
40
|
+
|
41
|
+
def message_with_schema
|
42
|
+
"#{message} in schema #{schema.uri}"
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|