json-schema 2.2.5 → 2.3.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 (70) hide show
  1. checksums.yaml +8 -8
  2. data/README.textile +1 -1
  3. data/lib/json-schema.rb +1 -0
  4. data/lib/json-schema/attribute.rb +43 -0
  5. data/lib/json-schema/attributes/additionalitems.rb +3 -1
  6. data/lib/json-schema/attributes/additionalproperties.rb +1 -0
  7. data/lib/json-schema/attributes/allof.rb +6 -4
  8. data/lib/json-schema/attributes/anyof.rb +7 -5
  9. data/lib/json-schema/attributes/dependencies.rb +3 -1
  10. data/lib/json-schema/attributes/dependencies_v4.rb +3 -1
  11. data/lib/json-schema/attributes/disallow.rb +3 -1
  12. data/lib/json-schema/attributes/divisibleby.rb +3 -1
  13. data/lib/json-schema/attributes/enum.rb +3 -1
  14. data/lib/json-schema/attributes/extends.rb +1 -0
  15. data/lib/json-schema/attributes/format.rb +6 -112
  16. data/lib/json-schema/attributes/formats/custom.rb +22 -0
  17. data/lib/json-schema/attributes/formats/date.rb +25 -0
  18. data/lib/json-schema/attributes/formats/date_time.rb +35 -0
  19. data/lib/json-schema/attributes/formats/ip4.rb +22 -0
  20. data/lib/json-schema/attributes/formats/ip6.rb +30 -0
  21. data/lib/json-schema/attributes/formats/time.rb +22 -0
  22. data/lib/json-schema/attributes/formats/uri.rb +18 -0
  23. data/lib/json-schema/attributes/items.rb +3 -1
  24. data/lib/json-schema/attributes/maxdecimal.rb +3 -1
  25. data/lib/json-schema/attributes/maximum.rb +3 -1
  26. data/lib/json-schema/attributes/maximum_inclusive.rb +2 -0
  27. data/lib/json-schema/attributes/maxitems.rb +2 -0
  28. data/lib/json-schema/attributes/maxlength.rb +3 -1
  29. data/lib/json-schema/attributes/maxproperties.rb +3 -1
  30. data/lib/json-schema/attributes/minimum.rb +3 -1
  31. data/lib/json-schema/attributes/minimum_inclusive.rb +3 -1
  32. data/lib/json-schema/attributes/minitems.rb +4 -2
  33. data/lib/json-schema/attributes/minlength.rb +3 -1
  34. data/lib/json-schema/attributes/minproperties.rb +3 -1
  35. data/lib/json-schema/attributes/multipleof.rb +3 -1
  36. data/lib/json-schema/attributes/not.rb +3 -1
  37. data/lib/json-schema/attributes/oneof.rb +2 -0
  38. data/lib/json-schema/attributes/pattern.rb +3 -1
  39. data/lib/json-schema/attributes/patternproperties.rb +3 -1
  40. data/lib/json-schema/attributes/properties.rb +4 -2
  41. data/lib/json-schema/attributes/properties_optional.rb +3 -1
  42. data/lib/json-schema/attributes/properties_v4.rb +2 -0
  43. data/lib/json-schema/attributes/ref.rb +3 -0
  44. data/lib/json-schema/attributes/required.rb +2 -0
  45. data/lib/json-schema/attributes/type.rb +6 -20
  46. data/lib/json-schema/attributes/type_v4.rb +3 -21
  47. data/lib/json-schema/attributes/uniqueitems.rb +3 -1
  48. data/lib/json-schema/errors/custom_format_error.rb +6 -0
  49. data/lib/json-schema/errors/json_parse_error.rb +6 -0
  50. data/lib/json-schema/errors/schema_error.rb +6 -0
  51. data/lib/json-schema/errors/validation_error.rb +46 -0
  52. data/lib/json-schema/schema.rb +1 -5
  53. data/lib/json-schema/schema/validator.rb +31 -0
  54. data/lib/json-schema/validator.rb +61 -126
  55. data/lib/json-schema/validators/draft1.rb +14 -1
  56. data/lib/json-schema/validators/draft2.rb +14 -1
  57. data/lib/json-schema/validators/draft3.rb +14 -2
  58. data/lib/json-schema/validators/draft4.rb +12 -1
  59. data/test/test_all_of_ref_schema.rb +29 -2
  60. data/test/test_any_of_ref_schema.rb +26 -0
  61. data/test/test_bad_schema_ref.rb +2 -2
  62. data/test/test_common_test_suite.rb +53 -0
  63. data/test/test_custom_format.rb +117 -0
  64. data/test/test_jsonschema_draft1.rb +12 -0
  65. data/test/test_jsonschema_draft2.rb +12 -0
  66. data/test/test_jsonschema_draft3.rb +31 -0
  67. data/test/test_jsonschema_draft4.rb +14 -48
  68. data/test/test_minitems.rb +18 -0
  69. metadata +21 -4
  70. data/test/test_suite.rb +0 -71
@@ -0,0 +1,22 @@
1
+ require 'json-schema/attribute'
2
+ require 'uri'
3
+ module JSON
4
+ class Schema
5
+ class IP4Format < FormatAttribute
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 IPv4 address"
9
+ r = Regexp.new('^(\d+){1,3}\.(\d+){1,3}\.(\d+){1,3}\.(\d+){1,3}$')
10
+ if (m = r.match(data))
11
+ 1.upto(4) do |x|
12
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[x].to_i > 255
13
+ end
14
+ else
15
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
16
+ return
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,30 @@
1
+ require 'json-schema/attribute'
2
+ require 'uri'
3
+ module JSON
4
+ class Schema
5
+ class IP6Format < FormatAttribute
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 IPv6 address"
9
+ r = Regexp.new('^[a-f0-9:]+$')
10
+ if (r.match(data))
11
+ # All characters are valid, now validate structure
12
+ parts = data.split(":")
13
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if parts.length > 8
14
+ condensed_zeros = false
15
+ parts.each do |part|
16
+ if part.length == 0
17
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if condensed_zeros
18
+ condensed_zeros = true
19
+ end
20
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if part.length > 4
21
+ end
22
+ else
23
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
24
+ return
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,22 @@
1
+ require 'json-schema/attribute'
2
+ require 'uri'
3
+ module JSON
4
+ class Schema
5
+ class TimeFormat < FormatAttribute
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 time in the format of hh:mm:ss"
9
+ r = Regexp.new('^(\d\d):(\d\d):(\d\d)$')
10
+ if (m = r.match(data))
11
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[1].to_i > 23
12
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[2].to_i > 59
13
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[3].to_i > 59
14
+ else
15
+ validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
16
+ return
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,18 @@
1
+ require 'json-schema/attribute'
2
+ require 'uri'
3
+ module JSON
4
+ class Schema
5
+ class UriFormat < FormatAttribute
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
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class ItemsAttribute < Attribute
@@ -22,4 +24,4 @@ module JSON
22
24
  end
23
25
  end
24
26
  end
25
- end
27
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MaxDecimalAttribute < Attribute
@@ -12,4 +14,4 @@ module JSON
12
14
  end
13
15
  end
14
16
  end
15
- end
17
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MaximumAttribute < Attribute
@@ -12,4 +14,4 @@ module JSON
12
14
  end
13
15
  end
14
16
  end
15
- end
17
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MaximumInclusiveAttribute < Attribute
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MaxItemsAttribute < Attribute
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MaxLengthAttribute < Attribute
@@ -11,4 +13,4 @@ module JSON
11
13
  end
12
14
  end
13
15
  end
14
- end
16
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MaxPropertiesAttribute < Attribute
@@ -9,4 +11,4 @@ module JSON
9
11
  end
10
12
  end
11
13
  end
12
- end
14
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MinimumAttribute < Attribute
@@ -12,4 +14,4 @@ module JSON
12
14
  end
13
15
  end
14
16
  end
15
- end
17
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MinimumInclusiveAttribute < Attribute
@@ -12,4 +14,4 @@ module JSON
12
14
  end
13
15
  end
14
16
  end
15
- end
17
+ end
@@ -1,12 +1,14 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MinItemsAttribute < Attribute
4
6
  def self.validate(current_schema, data, fragments, processor, validator, options = {})
5
- if data.is_a?(Array) && (data.compact.size < current_schema.schema['minItems'])
7
+ if data.is_a?(Array) && (data.size < current_schema.schema['minItems'])
6
8
  message = "The property '#{build_fragment(fragments)}' did not contain a minimum number of items #{current_schema.schema['minItems']}"
7
9
  validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
8
10
  end
9
11
  end
10
12
  end
11
13
  end
12
- end
14
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MinLengthAttribute < Attribute
@@ -11,4 +13,4 @@ module JSON
11
13
  end
12
14
  end
13
15
  end
14
- end
16
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MinPropertiesAttribute < Attribute
@@ -9,4 +11,4 @@ module JSON
9
11
  end
10
12
  end
11
13
  end
12
- end
14
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class MultipleOfAttribute < Attribute
@@ -13,4 +15,4 @@ module JSON
13
15
  end
14
16
  end
15
17
  end
16
- end
18
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class NotAttribute < Attribute
@@ -25,4 +27,4 @@ module JSON
25
27
  end
26
28
  end
27
29
  end
28
- end
30
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class OneOfAttribute < Attribute
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class PatternAttribute < Attribute
@@ -12,4 +14,4 @@ module JSON
12
14
  end
13
15
  end
14
16
  end
15
- end
17
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class PatternPropertiesAttribute < Attribute
@@ -20,4 +22,4 @@ module JSON
20
22
  end
21
23
  end
22
24
  end
23
- end
25
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class PropertiesAttribute < Attribute
@@ -13,8 +15,8 @@ module JSON
13
15
  data[property.to_s] = (default.is_a?(Hash) ? default.clone : default)
14
16
  end
15
17
 
16
-
17
- if (property_schema['required'] || options[:strict] == true) && !data.has_key?(property.to_s) && !data.has_key?(property.to_sym)
18
+ if property_schema.fetch('required') { options[:strict] } &&
19
+ !data.has_key?(property.to_s) && !data.has_key?(property.to_sym)
18
20
  message = "The property '#{build_fragment(fragments)}' did not contain a required property of '#{property}'"
19
21
  validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
20
22
  end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class PropertiesOptionalAttribute < Attribute
@@ -20,4 +22,4 @@ module JSON
20
22
  end
21
23
  end
22
24
  end
23
- end
25
+ end
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class PropertiesV4Attribute < Attribute
@@ -1,3 +1,6 @@
1
+ require 'json-schema/attribute'
2
+ require 'json-schema/errors/schema_error'
3
+
1
4
  module JSON
2
5
  class Schema
3
6
  class RefAttribute < Attribute
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class RequiredAttribute < Attribute
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class TypeAttribute < Attribute
@@ -15,10 +17,10 @@ module JSON
15
17
  end
16
18
  valid = false
17
19
 
18
- # Create an array to hold errors that are generated during union validation
19
- union_errors = []
20
+ # Create a hash to hold errors that are generated during union validation
21
+ union_errors = Hash.new { |hsh, k| hsh[k] = [] }
20
22
 
21
- types.each do |type|
23
+ types.each_with_index do |type, type_index|
22
24
  if type.is_a?(String)
23
25
  valid = data_valid_for_type?(data, type)
24
26
  elsif type.is_a?(Hash) && union
@@ -40,7 +42,7 @@ module JSON
40
42
  valid = false if diff > 0
41
43
  while diff > 0
42
44
  diff = diff - 1
43
- union_errors.push(validation_errors(processor).pop)
45
+ union_errors["type ##{type_index}"].push(validation_errors(processor).pop)
44
46
  end
45
47
  end
46
48
 
@@ -70,22 +72,6 @@ module JSON
70
72
  end
71
73
  end
72
74
 
73
- TYPE_CLASS_MAPPINGS = {
74
- "string" => String,
75
- "number" => Numeric,
76
- "integer" => Integer,
77
- "boolean" => [TrueClass, FalseClass],
78
- "object" => Hash,
79
- "array" => Array,
80
- "null" => NilClass,
81
- "any" => Object
82
- }
83
-
84
- def self.data_valid_for_type?(data, type)
85
- valid_classes = TYPE_CLASS_MAPPINGS.fetch(type) { return true }
86
- Array(valid_classes).any? { |c| data.is_a?(c) }
87
- end
88
-
89
75
  # Lookup Schema type of given class instance
90
76
  def self.type_of_data(data)
91
77
  type, klass = TYPE_CLASS_MAPPINGS.map { |k,v| [k,v] }.sort_by { |i|
@@ -1,3 +1,5 @@
1
+ require 'json-schema/attribute'
2
+
1
3
  module JSON
2
4
  class Schema
3
5
  class TypeV4Attribute < Attribute
@@ -10,9 +12,6 @@ module JSON
10
12
  end
11
13
  valid = false
12
14
 
13
- # Create an array to hold errors that are generated during union validation
14
- union_errors = []
15
-
16
15
  types.each do |type|
17
16
  valid = data_valid_for_type?(data, type)
18
17
  break if valid
@@ -24,7 +23,6 @@ module JSON
24
23
  types.each {|type| message += type.is_a?(String) ? " #{type}," : " (schema)," }
25
24
  message.chop!
26
25
  validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
27
- validation_errors(processor).last.sub_errors = union_errors
28
26
  else
29
27
  message = "The property '#{build_fragment(fragments)}' of type #{data.class} did not match the following type:"
30
28
  types.each {|type| message += type.is_a?(String) ? " #{type}," : " (schema)," }
@@ -33,22 +31,6 @@ module JSON
33
31
  end
34
32
  end
35
33
  end
36
-
37
- TYPE_CLASS_MAPPINGS = {
38
- "string" => String,
39
- "number" => Numeric,
40
- "integer" => Integer,
41
- "boolean" => [TrueClass, FalseClass],
42
- "object" => Hash,
43
- "array" => Array,
44
- "null" => NilClass,
45
- "any" => Object
46
- }
47
-
48
- def self.data_valid_for_type?(data, type)
49
- valid_classes = TYPE_CLASS_MAPPINGS.fetch(type) { return true }
50
- Array(valid_classes).any? { |c| data.is_a?(c) }
51
- end
52
34
  end
53
35
  end
54
- end
36
+ end