json-schema 2.2.5 → 2.3.0

Sign up to get free protection for your applications and to get access to all the features.
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