json-schema 2.4.1 → 2.5.0

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.
Files changed (88) hide show
  1. checksums.yaml +6 -14
  2. data/README.textile +58 -7
  3. data/lib/json-schema.rb +3 -1
  4. data/lib/json-schema/attributes/additionalitems.rb +14 -11
  5. data/lib/json-schema/attributes/additionalproperties.rb +33 -43
  6. data/lib/json-schema/attributes/anyof.rb +4 -0
  7. data/lib/json-schema/attributes/dependencies.rb +31 -19
  8. data/lib/json-schema/attributes/disallow.rb +2 -3
  9. data/lib/json-schema/attributes/divisibleby.rb +11 -7
  10. data/lib/json-schema/attributes/enum.rb +14 -16
  11. data/lib/json-schema/attributes/format.rb +4 -7
  12. data/lib/json-schema/attributes/formats/date_time_v4.rb +5 -8
  13. data/lib/json-schema/attributes/formats/ip.rb +41 -0
  14. data/lib/json-schema/attributes/formats/uri.rb +10 -8
  15. data/lib/json-schema/attributes/items.rb +15 -16
  16. data/lib/json-schema/attributes/limit.rb +179 -0
  17. data/lib/json-schema/attributes/maxdecimal.rb +7 -6
  18. data/lib/json-schema/attributes/multipleof.rb +4 -11
  19. data/lib/json-schema/attributes/not.rb +1 -1
  20. data/lib/json-schema/attributes/oneof.rb +15 -6
  21. data/lib/json-schema/attributes/pattern.rb +7 -6
  22. data/lib/json-schema/attributes/patternproperties.rb +9 -12
  23. data/lib/json-schema/attributes/properties.rb +55 -39
  24. data/lib/json-schema/attributes/properties_optional.rb +13 -12
  25. data/lib/json-schema/attributes/ref.rb +4 -4
  26. data/lib/json-schema/attributes/required.rb +16 -13
  27. data/lib/json-schema/attributes/type.rb +13 -18
  28. data/lib/json-schema/attributes/type_v4.rb +11 -18
  29. data/lib/json-schema/attributes/uniqueitems.rb +5 -7
  30. data/lib/json-schema/schema.rb +8 -8
  31. data/lib/json-schema/schema/#validator.rb# +37 -0
  32. data/lib/json-schema/schema/reader.rb +113 -0
  33. data/lib/json-schema/util/uri.rb +16 -0
  34. data/lib/json-schema/validator.rb +123 -128
  35. data/lib/json-schema/validators/draft1.rb +1 -1
  36. data/lib/json-schema/validators/draft2.rb +1 -1
  37. data/lib/json-schema/validators/draft3.rb +1 -1
  38. data/lib/json-schema/validators/draft4.rb +1 -1
  39. data/lib/json-schema/validators/hyper-draft4.rb +1 -1
  40. data/test/schemas/address_microformat.json +18 -0
  41. data/test/schemas/definition_schema.json +15 -0
  42. data/test/schemas/ref john with spaces schema.json +11 -0
  43. data/test/schemas/relative_definition_schema.json +8 -0
  44. data/test/test_all_of_ref_schema.rb +12 -15
  45. data/test/test_any_of_ref_schema.rb +7 -9
  46. data/test/test_bad_schema_ref.rb +18 -12
  47. data/test/test_common_test_suite.rb +45 -29
  48. data/test/test_custom_format.rb +2 -3
  49. data/test/test_definition.rb +15 -0
  50. data/test/test_extended_schema.rb +25 -31
  51. data/test/test_extends_and_additionalProperties.rb +23 -21
  52. data/test/test_files_v3.rb +14 -23
  53. data/test/test_fragment_resolution.rb +6 -7
  54. data/test/test_fragment_validation_with_ref.rb +2 -8
  55. data/test/test_full_validation.rb +2 -3
  56. data/test/test_helper.rb +46 -1
  57. data/test/test_initialize_data.rb +118 -0
  58. data/test/test_jsonschema_draft1.rb +48 -600
  59. data/test/test_jsonschema_draft2.rb +48 -699
  60. data/test/test_jsonschema_draft3.rb +91 -861
  61. data/test/test_jsonschema_draft4.rb +173 -812
  62. data/test/test_list_option.rb +6 -7
  63. data/test/{test_merge_misisng_values.rb → test_merge_missing_values.rb} +2 -3
  64. data/test/test_minitems.rb +2 -4
  65. data/test/test_one_of.rb +9 -19
  66. data/test/test_ruby_schema.rb +5 -14
  67. data/test/test_schema_loader.rb +74 -0
  68. data/test/test_schema_type_attribute.rb +2 -3
  69. data/test/test_schema_validation.rb +4 -5
  70. data/test/test_stringify.rb +2 -3
  71. data/test/test_uri_related.rb +67 -0
  72. data/test/test_validator.rb +53 -0
  73. metadata +129 -51
  74. data/lib/json-schema/attributes/dependencies_v4.rb +0 -27
  75. data/lib/json-schema/attributes/formats/ip4.rb +0 -20
  76. data/lib/json-schema/attributes/formats/ip6.rb +0 -20
  77. data/lib/json-schema/attributes/maximum.rb +0 -17
  78. data/lib/json-schema/attributes/maximum_inclusive.rb +0 -17
  79. data/lib/json-schema/attributes/maxitems.rb +0 -14
  80. data/lib/json-schema/attributes/maxlength.rb +0 -16
  81. data/lib/json-schema/attributes/maxproperties.rb +0 -14
  82. data/lib/json-schema/attributes/minimum.rb +0 -17
  83. data/lib/json-schema/attributes/minimum_inclusive.rb +0 -17
  84. data/lib/json-schema/attributes/minitems.rb +0 -14
  85. data/lib/json-schema/attributes/minlength.rb +0 -16
  86. data/lib/json-schema/attributes/minproperties.rb +0 -14
  87. data/lib/json-schema/attributes/properties_v4.rb +0 -58
  88. data/lib/json-schema/uri/file.rb +0 -36
@@ -0,0 +1,41 @@
1
+ require 'json-schema/attributes/format'
2
+ require 'ipaddr'
3
+ require 'socket'
4
+
5
+ module JSON
6
+ class Schema
7
+ class IPFormat < FormatAttribute
8
+ def self.validate(current_schema, data, fragments, processor, validator, options = {})
9
+ return unless data.is_a?(String)
10
+
11
+ begin
12
+ ip = IPAddr.new(data)
13
+ rescue ArgumentError => e
14
+ raise e unless e.message == 'invalid address'
15
+ end
16
+
17
+ family = ip_version == 6 ? Socket::AF_INET6 : Socket::AF_INET
18
+ unless ip && ip.family == family
19
+ error_message = "The property '#{build_fragment(fragments)}' must be a valid IPv#{ip_version} address"
20
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
21
+ end
22
+ end
23
+
24
+ def self.ip_version
25
+ raise NotImplementedError
26
+ end
27
+ end
28
+
29
+ class IP4Format < IPFormat
30
+ def self.ip_version
31
+ 4
32
+ end
33
+ end
34
+
35
+ class IP6Format < IPFormat
36
+ def self.ip_version
37
+ 6
38
+ end
39
+ end
40
+ end
41
+ end
@@ -1,16 +1,18 @@
1
1
  require 'json-schema/attribute'
2
- require 'uri'
2
+ require 'addressable/uri'
3
3
  module JSON
4
4
  class Schema
5
5
  class UriFormat < FormatAttribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(String)
8
- error_message = "The property '#{build_fragment(fragments)}' must be a valid URI"
9
- begin
10
- URI.parse(URI.escape(data))
11
- rescue URI::InvalidURIError
12
- validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
13
- end
7
+ return unless data.is_a?(String)
8
+ error_message = "The property '#{build_fragment(fragments)}' must be a valid URI"
9
+ begin
10
+ # TODO
11
+ # Addressable only throws an exception on to_s for invalid URI strings, although it
12
+ # probably should throughout parse already - https://github.com/sporkmonger/addressable/issues/177
13
+ Addressable::URI.parse(data).to_s
14
+ rescue Addressable::URI::InvalidURIError
15
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
14
16
  end
15
17
  end
16
18
  end
@@ -4,22 +4,21 @@ module JSON
4
4
  class Schema
5
5
  class ItemsAttribute < Attribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(Array)
8
- if current_schema.schema['items'].is_a?(Hash)
9
- data.each_with_index do |item,i|
10
- schema = JSON::Schema.new(current_schema.schema['items'],current_schema.uri,validator)
11
- fragments << i.to_s
12
- schema.validate(item,fragments, processor, options)
13
- fragments.pop
14
- end
15
- elsif current_schema.schema['items'].is_a?(Array)
16
- current_schema.schema['items'].each_with_index do |item_schema,i|
17
- schema = JSON::Schema.new(item_schema,current_schema.uri,validator)
18
- fragments << i.to_s
19
- schema.validate(data[i],fragments, processor, options)
20
- fragments.pop
21
- end
22
- end
7
+ return unless data.is_a?(Array)
8
+
9
+ items = current_schema.schema['items']
10
+ case items
11
+ when Hash
12
+ schema = JSON::Schema.new(items, current_schema.uri, validator)
13
+ data.each_with_index do |item, i|
14
+ schema.validate(item, fragments + [i.to_s], processor, options)
15
+ end
16
+
17
+ when Array
18
+ items.each_with_index do |item_schema, i|
19
+ schema = JSON::Schema.new(item_schema, current_schema.uri, validator)
20
+ schema.validate(data[i], fragments + [i.to_s], processor, options)
21
+ end
23
22
  end
24
23
  end
25
24
  end
@@ -0,0 +1,179 @@
1
+ require 'json-schema/attribute'
2
+
3
+ module JSON
4
+ class Schema
5
+ class LimitAttribute < Attribute
6
+ def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
+ schema = current_schema.schema
8
+ return unless data.is_a?(acceptable_type) && invalid?(schema, value(data))
9
+
10
+ property = build_fragment(fragments)
11
+ description = error_message(schema)
12
+ message = format("The property '%s' %s", property, description)
13
+ validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
14
+ end
15
+
16
+ def self.invalid?(schema, data)
17
+ exclusive = exclusive?(schema)
18
+ limit = limit(schema)
19
+
20
+ if limit_name.start_with?('max')
21
+ exclusive ? data >= limit : data > limit
22
+ else
23
+ exclusive ? data <= limit : data < limit
24
+ end
25
+ end
26
+
27
+ def self.limit(schema)
28
+ schema[limit_name]
29
+ end
30
+
31
+ def self.exclusive?(schema)
32
+ false
33
+ end
34
+
35
+ def self.value(data)
36
+ data
37
+ end
38
+
39
+ def self.acceptable_type
40
+ raise NotImplementedError
41
+ end
42
+
43
+ def self.error_message(schema)
44
+ raise NotImplementedError
45
+ end
46
+
47
+ def self.limit_name
48
+ raise NotImplementedError
49
+ end
50
+ end
51
+
52
+ class MinLengthAttribute < LimitAttribute
53
+ def self.acceptable_type
54
+ String
55
+ end
56
+
57
+ def self.limit_name
58
+ 'minLength'
59
+ end
60
+
61
+ def self.error_message(schema)
62
+ "was not of a minimum string length of #{limit(schema)}"
63
+ end
64
+
65
+ def self.value(data)
66
+ data.length
67
+ end
68
+ end
69
+
70
+ class MaxLengthAttribute < MinLengthAttribute
71
+ def self.limit_name
72
+ 'maxLength'
73
+ end
74
+
75
+ def self.error_message(schema)
76
+ "was not of a maximum string length of #{limit(schema)}"
77
+ end
78
+ end
79
+
80
+ class MinItemsAttribute < LimitAttribute
81
+ def self.acceptable_type
82
+ Array
83
+ end
84
+
85
+ def self.value(data)
86
+ data.length
87
+ end
88
+
89
+ def self.limit_name
90
+ 'minItems'
91
+ end
92
+
93
+ def self.error_message(schema)
94
+ "did not contain a minimum number of items #{limit(schema)}"
95
+ end
96
+ end
97
+
98
+ class MaxItemsAttribute < MinItemsAttribute
99
+ def self.limit_name
100
+ 'maxItems'
101
+ end
102
+
103
+ def self.error_message(schema)
104
+ "had more items than the allowed #{limit(schema)}"
105
+ end
106
+ end
107
+
108
+ class MinPropertiesAttribute < LimitAttribute
109
+ def self.acceptable_type
110
+ Hash
111
+ end
112
+
113
+ def self.value(data)
114
+ data.size
115
+ end
116
+
117
+ def self.limit_name
118
+ 'minProperties'
119
+ end
120
+
121
+ def self.error_message(schema)
122
+ "did not contain a minimum number of properties #{limit(schema)}"
123
+ end
124
+ end
125
+
126
+ class MaxPropertiesAttribute < MinPropertiesAttribute
127
+ def self.limit_name
128
+ 'maxProperties'
129
+ end
130
+
131
+ def self.error_message(schema)
132
+ "had more properties than the allowed #{limit(schema)}"
133
+ end
134
+ end
135
+
136
+ class NumericLimitAttribute < LimitAttribute
137
+ def self.acceptable_type
138
+ Numeric
139
+ end
140
+
141
+ def self.error_message(schema)
142
+ exclusivity = exclusive?(schema) ? 'exclusively' : 'inclusively'
143
+ format("did not have a %s value of %s, %s", limit_name, limit(schema), exclusivity)
144
+ end
145
+ end
146
+
147
+ class MaximumAttribute < NumericLimitAttribute
148
+ def self.limit_name
149
+ 'maximum'
150
+ end
151
+
152
+ def self.exclusive?(schema)
153
+ schema['exclusiveMaximum']
154
+ end
155
+ end
156
+
157
+ class MaximumInclusiveAttribute < MaximumAttribute
158
+ def self.exclusive?(schema)
159
+ schema['maximumCanEqual'] == false
160
+ end
161
+ end
162
+
163
+ class MinimumAttribute < NumericLimitAttribute
164
+ def self.limit_name
165
+ 'minimum'
166
+ end
167
+
168
+ def self.exclusive?(schema)
169
+ schema['exclusiveMinimum']
170
+ end
171
+ end
172
+
173
+ class MinimumInclusiveAttribute < MinimumAttribute
174
+ def self.exclusive?(schema)
175
+ schema['minimumCanEqual'] == false
176
+ end
177
+ end
178
+ end
179
+ end
@@ -4,12 +4,13 @@ module JSON
4
4
  class Schema
5
5
  class MaxDecimalAttribute < Attribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(Numeric)
8
- s = data.to_s.split(".")[1]
9
- if s && s.length > current_schema.schema['maxDecimal']
10
- message = "The property '#{build_fragment(fragments)}' had more decimal places than the allowed #{current_schema.schema['maxDecimal']}"
11
- validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
12
- end
7
+ return unless data.is_a?(Numeric)
8
+
9
+ max_decimal_places = current_schema.schema['maxDecimal']
10
+ s = data.to_s.split(".")[1]
11
+ if s && s.length > max_decimal_places
12
+ message = "The property '#{build_fragment(fragments)}' had more decimal places than the allowed #{max_decimal_places}"
13
+ validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
13
14
  end
14
15
  end
15
16
  end
@@ -1,17 +1,10 @@
1
- require 'json-schema/attribute'
1
+ require 'json-schema/attributes/divisibleby'
2
2
 
3
3
  module JSON
4
4
  class Schema
5
- class MultipleOfAttribute < Attribute
6
- def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(Numeric)
8
- if current_schema.schema['multipleOf'] == 0 ||
9
- current_schema.schema['multipleOf'] == 0.0 ||
10
- (BigDecimal.new(data.to_s) % BigDecimal.new(current_schema.schema['multipleOf'].to_s)).to_f != 0
11
- message = "The property '#{build_fragment(fragments)}' was not divisible by #{current_schema.schema['multipleOf']}"
12
- validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
13
- end
14
- end
5
+ class MultipleOfAttribute < DivisibleByAttribute
6
+ def self.keyword
7
+ 'multipleOf'
15
8
  end
16
9
  end
17
10
  end
@@ -4,10 +4,10 @@ module JSON
4
4
  class Schema
5
5
  class NotAttribute < Attribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
-
8
7
  schema = JSON::Schema.new(current_schema.schema['not'],current_schema.uri,validator)
9
8
  failed = true
10
9
  errors_copy = processor.validation_errors.clone
10
+
11
11
  begin
12
12
  schema.validate(data,fragments,processor,options)
13
13
  # If we're recording errors, we don't throw an exception. Instead, check the errors array length
@@ -5,25 +5,34 @@ module JSON
5
5
  class OneOfAttribute < Attribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
7
  validation_errors = 0
8
- current_schema.schema['oneOf'].each do |element|
8
+ one_of = current_schema.schema['oneOf']
9
+
10
+ original_data = data.is_a?(Hash) ? data.clone : data
11
+ success_data = nil
12
+
13
+ one_of.each do |element|
9
14
  schema = JSON::Schema.new(element,current_schema.uri,validator)
10
15
 
11
16
  begin
12
17
  # need to raise exceptions on error because
13
18
  # schema.validate doesn't reliably return true/false
14
19
  schema.validate(data,fragments,processor,options.merge(:record_errors => false))
20
+ success_data = data.is_a?(Hash) ? data.clone : data
15
21
  rescue ValidationError
16
22
  validation_errors += 1
17
23
  end
18
24
 
25
+ data = original_data
26
+ end
27
+
28
+ if validation_errors == one_of.length - 1
29
+ data = success_data
30
+ return
19
31
  end
20
32
 
21
- case validation_errors
22
- when current_schema.schema['oneOf'].length - 1 # correct, matched only one
23
- message = nil
24
- when current_schema.schema['oneOf'].length # didn't match any
33
+ if validation_errors == one_of.length
25
34
  message = "The property '#{build_fragment(fragments)}' of type #{data.class} did not match any of the required schemas"
26
- else # too many matches
35
+ else
27
36
  message = "The property '#{build_fragment(fragments)}' of type #{data.class} matched more than one of the required schemas"
28
37
  end
29
38
 
@@ -4,12 +4,13 @@ module JSON
4
4
  class Schema
5
5
  class PatternAttribute < Attribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(String)
8
- r = Regexp.new(current_schema.schema['pattern'])
9
- if (r.match(data)).nil?
10
- message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match the regex '#{current_schema.schema['pattern']}'"
11
- validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
12
- end
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])
13
14
  end
14
15
  end
15
16
  end
@@ -4,19 +4,16 @@ module JSON
4
4
  class Schema
5
5
  class PatternPropertiesAttribute < Attribute
6
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(Hash)
8
- current_schema.schema['patternProperties'].each do |property,property_schema|
9
- r = Regexp.new(property)
7
+ return unless data.is_a?(Hash)
10
8
 
11
- # Check each key in the data hash to see if it matches the regex
12
- data.each do |key,value|
13
- if r.match(key)
14
- schema = JSON::Schema.new(property_schema,current_schema.uri,validator)
15
- fragments << key
16
- schema.validate(data[key],fragments,processor,options)
17
- fragments.pop
18
- end
19
- end
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)
20
17
  end
21
18
  end
22
19
  end
@@ -3,55 +3,71 @@ require 'json-schema/attribute'
3
3
  module JSON
4
4
  class Schema
5
5
  class PropertiesAttribute < Attribute
6
+ def self.required?(schema, options)
7
+ schema.fetch('required') { options[:strict] }
8
+ end
9
+
6
10
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
7
- if data.is_a?(Hash)
8
- current_schema.schema['properties'].each do |property,property_schema|
9
- if !data.has_key?(property.to_s) &&
10
- property_schema['default'] &&
11
- !property_schema['readonly'] &&
12
- options[:insert_defaults]
13
- default = property_schema['default']
14
- data[property.to_s] = (default.is_a?(Hash) ? default.clone : default)
15
- end
11
+ return unless data.is_a?(Hash)
16
12
 
17
- if property_schema.fetch('required') { options[:strict] } && !data.has_key?(property.to_s)
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])
20
- end
13
+ schema = current_schema.schema
14
+ schema['properties'].each do |property, property_schema|
15
+ property = property.to_s
21
16
 
22
- if data.has_key?(property.to_s)
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
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)
28
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
29
41
 
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) && !match
44
- else
45
- !current_schema.schema['properties'].has_key?(k.to_s)
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
46
49
  end
47
50
  end
48
51
 
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
52
+ !schema['properties'].has_key?(k) && !match
53
+ else
54
+ !schema['properties'].has_key?(k)
53
55
  end
54
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
55
71
  end
56
72
  end
57
73
  end
OSZAR »