json-schema-ouidou 2.9.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.
- checksums.yaml +7 -0
- data/LICENSE.md +19 -0
- data/README.md +496 -0
- data/lib/json-schema/attribute.rb +57 -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 +38 -0
- data/lib/json-schema/attributes/dependencies_v4.rb +11 -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 +48 -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 +25 -0
- data/lib/json-schema/attributes/formats/date_time.rb +34 -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 +18 -0
- data/lib/json-schema/attributes/items.rb +27 -0
- data/lib/json-schema/attributes/limit.rb +52 -0
- data/lib/json-schema/attributes/limits/items.rb +15 -0
- data/lib/json-schema/attributes/limits/length.rb +15 -0
- data/lib/json-schema/attributes/limits/max_items.rb +15 -0
- data/lib/json-schema/attributes/limits/max_length.rb +15 -0
- data/lib/json-schema/attributes/limits/max_properties.rb +15 -0
- data/lib/json-schema/attributes/limits/maximum.rb +15 -0
- data/lib/json-schema/attributes/limits/maximum_inclusive.rb +11 -0
- data/lib/json-schema/attributes/limits/min_items.rb +15 -0
- data/lib/json-schema/attributes/limits/min_length.rb +15 -0
- data/lib/json-schema/attributes/limits/min_properties.rb +15 -0
- data/lib/json-schema/attributes/limits/minimum.rb +15 -0
- data/lib/json-schema/attributes/limits/minimum_inclusive.rb +11 -0
- data/lib/json-schema/attributes/limits/numeric.rb +16 -0
- data/lib/json-schema/attributes/limits/properties.rb +15 -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 +66 -0
- data/lib/json-schema/attributes/properties_optional.rb +26 -0
- data/lib/json-schema/attributes/properties_v4.rb +13 -0
- data/lib/json-schema/attributes/ref.rb +61 -0
- data/lib/json-schema/attributes/required.rb +28 -0
- data/lib/json-schema/attributes/type.rb +73 -0
- data/lib/json-schema/attributes/type_v4.rb +29 -0
- data/lib/json-schema/attributes/uniqueitems.rb +20 -0
- data/lib/json-schema/errors/custom_format_error.rb +6 -0
- data/lib/json-schema/errors/json_load_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/schema_parse_error.rb +8 -0
- data/lib/json-schema/errors/uri_error.rb +6 -0
- data/lib/json-schema/errors/validation_error.rb +46 -0
- data/lib/json-schema/schema/reader.rb +140 -0
- data/lib/json-schema/schema/validator.rb +40 -0
- data/lib/json-schema/schema.rb +62 -0
- data/lib/json-schema/util/array_set.rb +20 -0
- data/lib/json-schema/util/uri.rb +110 -0
- data/lib/json-schema/util/uuid.rb +284 -0
- data/lib/json-schema/validator.rb +609 -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/draft6.rb +56 -0
- data/lib/json-schema/validators/hyper-draft1.rb +13 -0
- data/lib/json-schema/validators/hyper-draft2.rb +13 -0
- data/lib/json-schema/validators/hyper-draft3.rb +13 -0
- data/lib/json-schema/validators/hyper-draft4.rb +13 -0
- data/lib/json-schema/validators/hyper-draft6.rb +13 -0
- data/lib/json-schema.rb +18 -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/resources/draft-06.json +150 -0
- metadata +197 -0
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class AllOfAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
# Create an hash to hold errors that are generated during validation
|
8
|
+
errors = Hash.new { |hsh, k| hsh[k] = [] }
|
9
|
+
valid = true
|
10
|
+
|
11
|
+
current_schema.schema['allOf'].each_with_index do |element, schema_index|
|
12
|
+
schema = JSON::Schema.new(element,current_schema.uri,validator)
|
13
|
+
|
14
|
+
# We're going to add a little cruft here to try and maintain any validation errors that occur in the allOf
|
15
|
+
# We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto an error array
|
16
|
+
pre_validation_error_count = validation_errors(processor).count
|
17
|
+
|
18
|
+
begin
|
19
|
+
schema.validate(data,fragments,processor,options)
|
20
|
+
rescue ValidationError
|
21
|
+
valid = false
|
22
|
+
end
|
23
|
+
|
24
|
+
diff = validation_errors(processor).count - pre_validation_error_count
|
25
|
+
while diff > 0
|
26
|
+
diff = diff - 1
|
27
|
+
errors["allOf ##{schema_index}"].push(validation_errors(processor).pop)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
if !valid || !errors.empty?
|
32
|
+
message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match all of the required schemas"
|
33
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
34
|
+
validation_errors(processor).last.sub_errors = errors
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class AnyOfAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
# Create a hash to hold errors that are generated during validation
|
8
|
+
errors = Hash.new { |hsh, k| hsh[k] = [] }
|
9
|
+
valid = false
|
10
|
+
|
11
|
+
original_data = data.is_a?(Hash) ? data.clone : data
|
12
|
+
|
13
|
+
current_schema.schema['anyOf'].each_with_index do |element, schema_index|
|
14
|
+
schema = JSON::Schema.new(element,current_schema.uri,validator)
|
15
|
+
|
16
|
+
# We're going to add a little cruft here to try and maintain any validation errors that occur in the anyOf
|
17
|
+
# We'll handle this by keeping an error count before and after validation, extracting those errors and pushing them onto a union error
|
18
|
+
pre_validation_error_count = validation_errors(processor).count
|
19
|
+
|
20
|
+
begin
|
21
|
+
schema.validate(data,fragments,processor,options)
|
22
|
+
valid = true
|
23
|
+
rescue ValidationError
|
24
|
+
# We don't care that these schemas don't validate - we only care that one validated
|
25
|
+
end
|
26
|
+
|
27
|
+
diff = validation_errors(processor).count - pre_validation_error_count
|
28
|
+
valid = false if diff > 0
|
29
|
+
while diff > 0
|
30
|
+
diff = diff - 1
|
31
|
+
errors["anyOf ##{schema_index}"].push(validation_errors(processor).pop)
|
32
|
+
end
|
33
|
+
|
34
|
+
break if valid
|
35
|
+
|
36
|
+
data = original_data
|
37
|
+
end
|
38
|
+
|
39
|
+
if !valid
|
40
|
+
message = "The property '#{build_fragment(fragments)}' of type #{type_of_data(data)} did not match one or more of the required schemas"
|
41
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
42
|
+
validation_errors(processor).last.sub_errors = errors
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class DependenciesAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(Hash)
|
8
|
+
|
9
|
+
current_schema.schema['dependencies'].each do |property, dependency_value|
|
10
|
+
next unless data.has_key?(property.to_s)
|
11
|
+
next unless accept_value?(dependency_value)
|
12
|
+
|
13
|
+
case dependency_value
|
14
|
+
when String
|
15
|
+
validate_dependency(current_schema, data, property, dependency_value, fragments, processor, self, options)
|
16
|
+
when Array
|
17
|
+
dependency_value.each do |value|
|
18
|
+
validate_dependency(current_schema, data, property, value, fragments, processor, self, options)
|
19
|
+
end
|
20
|
+
else
|
21
|
+
schema = JSON::Schema.new(dependency_value, current_schema.uri, validator)
|
22
|
+
schema.validate(data, fragments, processor, options)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def self.validate_dependency(schema, data, property, value, fragments, processor, attribute, options)
|
28
|
+
return if data.key?(value.to_s)
|
29
|
+
message = "The property '#{build_fragment(fragments)}' has a property '#{property}' that depends on a missing property '#{value}'"
|
30
|
+
validation_error(processor, message, fragments, schema, attribute, options[:record_errors])
|
31
|
+
end
|
32
|
+
|
33
|
+
def self.accept_value?(value)
|
34
|
+
value.is_a?(String) || value.is_a?(Array) || value.is_a?(Hash)
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class DisallowAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless type = validator.attributes['type']
|
8
|
+
type.validate(current_schema, data, fragments, processor, validator, options.merge(:disallow => true))
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class DivisibleByAttribute < Attribute
|
6
|
+
def self.keyword
|
7
|
+
'divisibleBy'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
11
|
+
return unless data.is_a?(Numeric)
|
12
|
+
|
13
|
+
factor = current_schema.schema[keyword]
|
14
|
+
|
15
|
+
if factor == 0 || factor == 0.0 || (BigDecimal(data.to_s) % BigDecimal(factor.to_s)).to_f != 0
|
16
|
+
message = "The property '#{build_fragment(fragments)}' was not divisible by #{factor}"
|
17
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class EnumAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
enum = current_schema.schema['enum']
|
8
|
+
return if enum.include?(data)
|
9
|
+
|
10
|
+
values = enum.map { |val|
|
11
|
+
case val
|
12
|
+
when nil then 'null'
|
13
|
+
when Array then 'array'
|
14
|
+
when Hash then 'object'
|
15
|
+
else val.to_s
|
16
|
+
end
|
17
|
+
}.join(', ')
|
18
|
+
|
19
|
+
message = "The property '#{build_fragment(fragments)}' value #{data.inspect} did not match one of the following values: #{values}"
|
20
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
require 'json-schema/attributes/ref'
|
3
|
+
|
4
|
+
module JSON
|
5
|
+
class Schema
|
6
|
+
class ExtendsAttribute < Attribute
|
7
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
8
|
+
schemas = current_schema.schema['extends']
|
9
|
+
schemas = [schemas] if !schemas.is_a?(Array)
|
10
|
+
schemas.each do |s|
|
11
|
+
uri,schema = get_extended_uri_and_schema(s, current_schema, validator)
|
12
|
+
if schema
|
13
|
+
schema.validate(data, fragments, processor, options)
|
14
|
+
elsif uri
|
15
|
+
message = "The extended schema '#{uri.to_s}' cannot be found"
|
16
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
17
|
+
else
|
18
|
+
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
19
|
+
validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.get_extended_uri_and_schema(s, current_schema, validator)
|
25
|
+
uri,schema = nil,nil
|
26
|
+
|
27
|
+
if s.is_a?(Hash)
|
28
|
+
uri = current_schema.uri
|
29
|
+
if s['$ref']
|
30
|
+
ref_uri,ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator)
|
31
|
+
if ref_schema
|
32
|
+
if s.size == 1 # Check if anything else apart from $ref
|
33
|
+
uri,schema = ref_uri,ref_schema
|
34
|
+
else
|
35
|
+
s = s.dup
|
36
|
+
s.delete '$ref'
|
37
|
+
s = ref_schema.schema.merge(s)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
schema ||= JSON::Schema.new(s,uri,validator)
|
42
|
+
end
|
43
|
+
|
44
|
+
[uri,schema]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -0,0 +1,14 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class FormatAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data_valid_for_type?(data, current_schema.schema['type'])
|
8
|
+
format = current_schema.schema['format'].to_s
|
9
|
+
validator = validator.formats[format]
|
10
|
+
validator.validate(current_schema, data, fragments, processor, validator, options) unless validator.nil?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'json-schema/attributes/format'
|
2
|
+
require 'json-schema/errors/custom_format_error'
|
3
|
+
|
4
|
+
module JSON
|
5
|
+
class Schema
|
6
|
+
class CustomFormat < FormatAttribute
|
7
|
+
def initialize(validation_proc)
|
8
|
+
@validation_proc = validation_proc
|
9
|
+
end
|
10
|
+
|
11
|
+
def validate(current_schema, data, fragments, processor, validator, options = {})
|
12
|
+
begin
|
13
|
+
@validation_proc.call data
|
14
|
+
rescue JSON::Schema::CustomFormatError => e
|
15
|
+
message = "The property '#{self.class.build_fragment(fragments)}' #{e.message}"
|
16
|
+
self.class.validation_error(processor, message, fragments, current_schema, self, options[:record_errors])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
require 'json-schema/attributes/format'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class DateFormat < FormatAttribute
|
6
|
+
REGEXP = /\A\d{4}-\d{2}-\d{2}\z/
|
7
|
+
|
8
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
9
|
+
if data.is_a?(String)
|
10
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a date in the format of YYYY-MM-DD"
|
11
|
+
if REGEXP.match(data)
|
12
|
+
begin
|
13
|
+
Date.parse(data)
|
14
|
+
rescue ArgumentError => e
|
15
|
+
raise e unless e.message == 'invalid date'
|
16
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
17
|
+
end
|
18
|
+
else
|
19
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'json-schema/attributes/format'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class DateTimeFormat < FormatAttribute
|
6
|
+
REGEXP = /\A\d{4}-\d{2}-\d{2}T(\d{2}):(\d{2}):(\d{2})([\.,]\d+)?(Z|[+-](\d{2})(:?\d{2})?)?\z/
|
7
|
+
|
8
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
9
|
+
# Timestamp in restricted ISO-8601 YYYY-MM-DDThh:mm:ssZ with optional decimal fraction of the second
|
10
|
+
if data.is_a?(String)
|
11
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a date/time in the ISO-8601 format of YYYY-MM-DDThh:mm:ssZ or YYYY-MM-DDThh:mm:ss.ssZ"
|
12
|
+
if (m = REGEXP.match(data))
|
13
|
+
parts = data.split("T")
|
14
|
+
|
15
|
+
begin
|
16
|
+
Date.parse(parts[0])
|
17
|
+
rescue ArgumentError => e
|
18
|
+
raise e unless e.message == 'invalid date'
|
19
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
20
|
+
return
|
21
|
+
end
|
22
|
+
|
23
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m.length < 4
|
24
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[1].to_i > 23
|
25
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[2].to_i > 59
|
26
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[3].to_i > 59
|
27
|
+
else
|
28
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json-schema/attributes/format'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class DateTimeV4Format < FormatAttribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
7
|
+
return unless data.is_a?(String)
|
8
|
+
DateTime.rfc3339(data)
|
9
|
+
rescue ArgumentError
|
10
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a valid RFC3339 date/time string"
|
11
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -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
|
@@ -0,0 +1,22 @@
|
|
1
|
+
require 'json-schema/attributes/format'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class TimeFormat < FormatAttribute
|
6
|
+
REGEXP = /\A(\d{2}):(\d{2}):(\d{2})\z/
|
7
|
+
|
8
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
9
|
+
if data.is_a?(String)
|
10
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a time in the format of hh:mm:ss"
|
11
|
+
if (m = REGEXP.match(data))
|
12
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[1].to_i > 23
|
13
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[2].to_i > 59
|
14
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors]) and return if m[3].to_i > 59
|
15
|
+
else
|
16
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'json-schema/attributes/format'
|
2
|
+
require 'json-schema/errors/uri_error'
|
3
|
+
|
4
|
+
module JSON
|
5
|
+
class Schema
|
6
|
+
class UriFormat < FormatAttribute
|
7
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
8
|
+
return unless data.is_a?(String)
|
9
|
+
error_message = "The property '#{build_fragment(fragments)}' must be a valid URI"
|
10
|
+
begin
|
11
|
+
JSON::Util::URI.parse(data)
|
12
|
+
rescue JSON::Schema::UriError
|
13
|
+
validation_error(processor, error_message, fragments, current_schema, self, options[:record_errors])
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'json-schema/attribute'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class ItemsAttribute < Attribute
|
6
|
+
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
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
|
+
break if i >= data.length
|
20
|
+
schema = JSON::Schema.new(item_schema, current_schema.uri, validator)
|
21
|
+
schema.validate(data[i], fragments + [i.to_s], processor, options)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,52 @@
|
|
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
|
+
end
|
52
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json-schema/attributes/limits/items'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class MaxItemsAttribute < ItemsLimitAttribute
|
6
|
+
def self.limit_name
|
7
|
+
'maxItems'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.error_message(schema)
|
11
|
+
"had more items than the allowed #{limit(schema)}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json-schema/attributes/limits/length'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class MaxLengthAttribute < LengthLimitAttribute
|
6
|
+
def self.limit_name
|
7
|
+
'maxLength'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.error_message(schema)
|
11
|
+
"was not of a maximum string length of #{limit(schema)}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json-schema/attributes/limits/properties'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class MaxPropertiesAttribute < PropertiesLimitAttribute
|
6
|
+
def self.limit_name
|
7
|
+
'maxProperties'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.error_message(schema)
|
11
|
+
"had more properties than the allowed #{limit(schema)}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json-schema/attributes/limits/numeric'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class MaximumAttribute < NumericLimitAttribute
|
6
|
+
def self.limit_name
|
7
|
+
'maximum'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.exclusive?(schema)
|
11
|
+
schema['exclusiveMaximum']
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'json-schema/attributes/limits/items'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
class Schema
|
5
|
+
class MinItemsAttribute < ItemsLimitAttribute
|
6
|
+
def self.limit_name
|
7
|
+
'minItems'
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.error_message(schema)
|
11
|
+
"did not contain a minimum number of items #{limit(schema)}"
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|