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.
- checksums.yaml +8 -8
- data/README.textile +1 -1
- data/lib/json-schema.rb +1 -0
- data/lib/json-schema/attribute.rb +43 -0
- data/lib/json-schema/attributes/additionalitems.rb +3 -1
- data/lib/json-schema/attributes/additionalproperties.rb +1 -0
- data/lib/json-schema/attributes/allof.rb +6 -4
- data/lib/json-schema/attributes/anyof.rb +7 -5
- data/lib/json-schema/attributes/dependencies.rb +3 -1
- data/lib/json-schema/attributes/dependencies_v4.rb +3 -1
- data/lib/json-schema/attributes/disallow.rb +3 -1
- data/lib/json-schema/attributes/divisibleby.rb +3 -1
- data/lib/json-schema/attributes/enum.rb +3 -1
- data/lib/json-schema/attributes/extends.rb +1 -0
- data/lib/json-schema/attributes/format.rb +6 -112
- data/lib/json-schema/attributes/formats/custom.rb +22 -0
- data/lib/json-schema/attributes/formats/date.rb +25 -0
- data/lib/json-schema/attributes/formats/date_time.rb +35 -0
- data/lib/json-schema/attributes/formats/ip4.rb +22 -0
- data/lib/json-schema/attributes/formats/ip6.rb +30 -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 +3 -1
- data/lib/json-schema/attributes/maxdecimal.rb +3 -1
- data/lib/json-schema/attributes/maximum.rb +3 -1
- data/lib/json-schema/attributes/maximum_inclusive.rb +2 -0
- data/lib/json-schema/attributes/maxitems.rb +2 -0
- data/lib/json-schema/attributes/maxlength.rb +3 -1
- data/lib/json-schema/attributes/maxproperties.rb +3 -1
- data/lib/json-schema/attributes/minimum.rb +3 -1
- data/lib/json-schema/attributes/minimum_inclusive.rb +3 -1
- data/lib/json-schema/attributes/minitems.rb +4 -2
- data/lib/json-schema/attributes/minlength.rb +3 -1
- data/lib/json-schema/attributes/minproperties.rb +3 -1
- data/lib/json-schema/attributes/multipleof.rb +3 -1
- data/lib/json-schema/attributes/not.rb +3 -1
- data/lib/json-schema/attributes/oneof.rb +2 -0
- data/lib/json-schema/attributes/pattern.rb +3 -1
- data/lib/json-schema/attributes/patternproperties.rb +3 -1
- data/lib/json-schema/attributes/properties.rb +4 -2
- data/lib/json-schema/attributes/properties_optional.rb +3 -1
- data/lib/json-schema/attributes/properties_v4.rb +2 -0
- data/lib/json-schema/attributes/ref.rb +3 -0
- data/lib/json-schema/attributes/required.rb +2 -0
- data/lib/json-schema/attributes/type.rb +6 -20
- data/lib/json-schema/attributes/type_v4.rb +3 -21
- data/lib/json-schema/attributes/uniqueitems.rb +3 -1
- 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 +1 -5
- data/lib/json-schema/schema/validator.rb +31 -0
- data/lib/json-schema/validator.rb +61 -126
- data/lib/json-schema/validators/draft1.rb +14 -1
- data/lib/json-schema/validators/draft2.rb +14 -1
- data/lib/json-schema/validators/draft3.rb +14 -2
- data/lib/json-schema/validators/draft4.rb +12 -1
- data/test/test_all_of_ref_schema.rb +29 -2
- data/test/test_any_of_ref_schema.rb +26 -0
- data/test/test_bad_schema_ref.rb +2 -2
- data/test/test_common_test_suite.rb +53 -0
- data/test/test_custom_format.rb +117 -0
- data/test/test_jsonschema_draft1.rb +12 -0
- data/test/test_jsonschema_draft2.rb +12 -0
- data/test/test_jsonschema_draft3.rb +31 -0
- data/test/test_jsonschema_draft4.rb +14 -48
- data/test/test_minitems.rb +18 -0
- metadata +21 -4
- data/test/test_suite.rb +0 -71
@@ -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
|
data/lib/json-schema/schema.rb
CHANGED
@@ -24,11 +24,7 @@ module JSON
|
|
24
24
|
|
25
25
|
# If there is a $schema on this schema, use it to determine which validator to use
|
26
26
|
if @schema['$schema']
|
27
|
-
|
28
|
-
@validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
29
|
-
if @validator.nil?
|
30
|
-
raise SchemaError.new("This library does not have support for schemas defined by #{u.scheme}://#{u.host}#{u.path}")
|
31
|
-
end
|
27
|
+
@validator = JSON::Validator.validator_for(@schema['$schema'])
|
32
28
|
elsif parent_validator
|
33
29
|
@validator = parent_validator
|
34
30
|
else
|
@@ -0,0 +1,31 @@
|
|
1
|
+
module JSON
|
2
|
+
class Schema
|
3
|
+
class Validator
|
4
|
+
attr_accessor :attributes, :formats, :uri, :names, :metaschema
|
5
|
+
attr_reader :default_formats
|
6
|
+
|
7
|
+
def initialize()
|
8
|
+
@attributes = {}
|
9
|
+
@formats = {}
|
10
|
+
@default_formats = {}
|
11
|
+
@uri = nil
|
12
|
+
@names = []
|
13
|
+
@metaschema = ''
|
14
|
+
end
|
15
|
+
|
16
|
+
def extend_schema_definition(schema_uri)
|
17
|
+
validator = JSON::Validator.validator_for(schema_uri)
|
18
|
+
@attributes.merge!(validator.attributes)
|
19
|
+
end
|
20
|
+
|
21
|
+
def validate(current_schema, data, fragments, processor, options = {})
|
22
|
+
current_schema.schema.each do |attr_name,attribute|
|
23
|
+
if @attributes.has_key?(attr_name.to_s)
|
24
|
+
@attributes[attr_name.to_s].validate(current_schema, data, fragments, processor, self, options)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
data
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -7,100 +7,10 @@ require 'date'
|
|
7
7
|
require 'thread'
|
8
8
|
require 'yaml'
|
9
9
|
|
10
|
-
|
11
|
-
|
12
|
-
class Schema
|
13
|
-
class ValidationError < StandardError
|
14
|
-
attr_accessor :fragments, :schema, :failed_attribute, :sub_errors
|
15
|
-
|
16
|
-
def initialize(message, fragments, failed_attribute, schema)
|
17
|
-
@fragments = fragments.clone
|
18
|
-
@schema = schema
|
19
|
-
@sub_errors = []
|
20
|
-
@failed_attribute = failed_attribute
|
21
|
-
message = "#{message} in schema #{schema.uri}"
|
22
|
-
super(message)
|
23
|
-
end
|
24
|
-
|
25
|
-
def to_string
|
26
|
-
if @sub_errors.empty?
|
27
|
-
message
|
28
|
-
else
|
29
|
-
full_message = message + "\n The schema specific errors were:\n"
|
30
|
-
@sub_errors.each{|e| full_message = full_message + " - " + e.to_string + "\n"}
|
31
|
-
full_message
|
32
|
-
end
|
33
|
-
end
|
34
|
-
|
35
|
-
def to_hash
|
36
|
-
base = {:schema => @schema.uri, :fragment => ::JSON::Schema::Attribute.build_fragment(fragments), :message => message, :failed_attribute => @failed_attribute.to_s.split(":").last.split("Attribute").first}
|
37
|
-
if !@sub_errors.empty?
|
38
|
-
base[:errors] = @sub_errors.map{|e| e.to_hash}
|
39
|
-
end
|
40
|
-
base
|
41
|
-
end
|
42
|
-
end
|
43
|
-
|
44
|
-
class SchemaError < StandardError
|
45
|
-
end
|
46
|
-
|
47
|
-
class JsonParseError < StandardError
|
48
|
-
end
|
49
|
-
|
50
|
-
class Attribute
|
51
|
-
def self.validate(current_schema, data, fragments, processor, validator, options = {})
|
52
|
-
end
|
53
|
-
|
54
|
-
def self.build_fragment(fragments)
|
55
|
-
"#/#{fragments.join('/')}"
|
56
|
-
end
|
57
|
-
|
58
|
-
def self.validation_error(processor, message, fragments, current_schema, failed_attribute, record_errors)
|
59
|
-
error = ValidationError.new(message, fragments, failed_attribute, current_schema)
|
60
|
-
if record_errors
|
61
|
-
processor.validation_error(error)
|
62
|
-
else
|
63
|
-
raise error
|
64
|
-
end
|
65
|
-
end
|
66
|
-
|
67
|
-
def self.validation_errors(validator)
|
68
|
-
validator.validation_errors
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
class Validator
|
73
|
-
attr_accessor :attributes, :uri
|
74
|
-
|
75
|
-
def initialize()
|
76
|
-
@attributes = {}
|
77
|
-
@uri = nil
|
78
|
-
end
|
79
|
-
|
80
|
-
def extend_schema_definition(schema_uri)
|
81
|
-
u = URI.parse(schema_uri)
|
82
|
-
validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
83
|
-
if validator.nil?
|
84
|
-
raise SchemaError.new("Schema not found: #{u.scheme}://#{u.host}#{u.path}")
|
85
|
-
end
|
86
|
-
@attributes.merge!(validator.attributes)
|
87
|
-
end
|
88
|
-
|
89
|
-
def to_s
|
90
|
-
"#{@uri.scheme}://#{uri.host}#{uri.path}"
|
91
|
-
end
|
92
|
-
|
93
|
-
def validate(current_schema, data, fragments, processor, options = {})
|
94
|
-
current_schema.schema.each do |attr_name,attribute|
|
95
|
-
if @attributes.has_key?(attr_name.to_s)
|
96
|
-
@attributes[attr_name.to_s].validate(current_schema, data, fragments, processor, self, options)
|
97
|
-
end
|
98
|
-
end
|
99
|
-
data
|
100
|
-
end
|
101
|
-
end
|
102
|
-
end
|
10
|
+
require 'json-schema/errors/schema_error'
|
11
|
+
require 'json-schema/errors/json_parse_error'
|
103
12
|
|
13
|
+
module JSON
|
104
14
|
|
105
15
|
class Validator
|
106
16
|
|
@@ -123,39 +33,12 @@ module JSON
|
|
123
33
|
@@serializer = nil
|
124
34
|
@@mutex = Mutex.new
|
125
35
|
|
126
|
-
def self.version_string_for(version)
|
127
|
-
# I'm not a fan of this, but it's quick and dirty to get it working for now
|
128
|
-
return "draft-04" unless version
|
129
|
-
case version.to_s
|
130
|
-
when "draft4", "http://json-schema.org/draft-04/schema#"
|
131
|
-
"draft-04"
|
132
|
-
when "draft3", "http://json-schema.org/draft-03/schema#"
|
133
|
-
"draft-03"
|
134
|
-
when "draft2"
|
135
|
-
"draft-02"
|
136
|
-
when "draft1"
|
137
|
-
"draft-01"
|
138
|
-
else
|
139
|
-
raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported")
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def self.metaschema_for(version_string)
|
144
|
-
File.join(Pathname.new(File.dirname(__FILE__)).parent.parent, "resources", "#{version_string}.json").to_s
|
145
|
-
end
|
146
|
-
|
147
36
|
def initialize(schema_data, data, opts={})
|
148
37
|
@options = @@default_opts.clone.merge(opts)
|
149
38
|
@errors = []
|
150
39
|
|
151
|
-
|
152
|
-
|
153
|
-
if @options[:version]
|
154
|
-
version_string = @options[:version] = self.class.version_string_for(@options[:version])
|
155
|
-
u = URI.parse("http://json-schema.org/#{@options[:version]}/schema#")
|
156
|
-
validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
157
|
-
@options[:version] = validator
|
158
|
-
end
|
40
|
+
validator = JSON::Validator.validator_for_name(@options[:version])
|
41
|
+
@options[:version] = validator
|
159
42
|
|
160
43
|
@validation_options = @options[:record_errors] ? {:record_errors => true} : {}
|
161
44
|
@validation_options[:insert_defaults] = true if @options[:insert_defaults]
|
@@ -169,10 +52,11 @@ module JSON
|
|
169
52
|
if @options[:validate_schema]
|
170
53
|
begin
|
171
54
|
if @base_schema.schema["$schema"]
|
172
|
-
|
55
|
+
base_validator = JSON::Validator.validator_for_name(@base_schema.schema["$schema"])
|
173
56
|
end
|
57
|
+
metaschema = base_validator ? base_validator.metaschema : validator.metaschema
|
174
58
|
# Don't clear the cache during metaschema validation!
|
175
|
-
meta_validator = JSON::Validator.new(
|
59
|
+
meta_validator = JSON::Validator.new(metaschema, @base_schema.schema, {:clear_cache => false})
|
176
60
|
meta_validator.validate
|
177
61
|
rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
|
178
62
|
raise $!
|
@@ -414,7 +298,7 @@ module JSON
|
|
414
298
|
|
415
299
|
def fully_validate_schema(schema, opts={})
|
416
300
|
data = schema
|
417
|
-
schema =
|
301
|
+
schema = JSON::Validator.validator_for_name(opts[:version]).metaschema
|
418
302
|
fully_validate(schema, data, opts)
|
419
303
|
end
|
420
304
|
|
@@ -451,14 +335,56 @@ module JSON
|
|
451
335
|
@@default_validator
|
452
336
|
end
|
453
337
|
|
338
|
+
def validator_for_uri(schema_uri)
|
339
|
+
return default_validator unless schema_uri
|
340
|
+
u = URI.parse(schema_uri)
|
341
|
+
validator = validators["#{u.scheme}://#{u.host}#{u.path}"]
|
342
|
+
if validator.nil?
|
343
|
+
raise JSON::Schema::SchemaError.new("Schema not found: #{schema_uri}")
|
344
|
+
else
|
345
|
+
validator
|
346
|
+
end
|
347
|
+
end
|
348
|
+
|
349
|
+
def validator_for_name(schema_name)
|
350
|
+
return default_validator unless schema_name
|
351
|
+
validator = validators_for_names([schema_name]).first
|
352
|
+
if validator.nil?
|
353
|
+
raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported")
|
354
|
+
else
|
355
|
+
validator
|
356
|
+
end
|
357
|
+
end
|
358
|
+
|
359
|
+
alias_method :validator_for, :validator_for_uri
|
360
|
+
|
454
361
|
def register_validator(v)
|
455
|
-
@@validators[v.
|
362
|
+
@@validators["#{v.uri.scheme}://#{v.uri.host}#{v.uri.path}"] = v
|
456
363
|
end
|
457
364
|
|
458
365
|
def register_default_validator(v)
|
459
366
|
@@default_validator = v
|
460
367
|
end
|
461
368
|
|
369
|
+
def register_format_validator(format, validation_proc, versions = ["draft1", "draft2", "draft3", "draft4"])
|
370
|
+
custom_format_validator = JSON::Schema::CustomFormat.new(validation_proc)
|
371
|
+
validators_for_names(versions).each do |validator|
|
372
|
+
validator.formats[format.to_s] = custom_format_validator
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
def deregister_format_validator(format, versions = ["draft1", "draft2", "draft3", "draft4"])
|
377
|
+
validators_for_names(versions).each do |validator|
|
378
|
+
validator.formats[format.to_s] = validator.default_formats[format.to_s]
|
379
|
+
end
|
380
|
+
end
|
381
|
+
|
382
|
+
def restore_default_formats(versions = ["draft1", "draft2", "draft3", "draft4"])
|
383
|
+
validators_for_names(versions).each do |validator|
|
384
|
+
validator.formats = validator.default_formats.clone
|
385
|
+
end
|
386
|
+
end
|
387
|
+
|
462
388
|
def json_backend
|
463
389
|
if defined?(MultiJson)
|
464
390
|
MultiJson.respond_to?(:adapter) ? MultiJson.adapter : MultiJson.engine
|
@@ -539,6 +465,15 @@ module JSON
|
|
539
465
|
}
|
540
466
|
end
|
541
467
|
end
|
468
|
+
|
469
|
+
private
|
470
|
+
|
471
|
+
def validators_for_names(names)
|
472
|
+
names.map! { |name| name.to_s }
|
473
|
+
validators.reduce([]) do |memo, (_, validator)|
|
474
|
+
memo.tap { |m| m << validator if (validator.names & names).any? }
|
475
|
+
end
|
476
|
+
end
|
542
477
|
end
|
543
478
|
|
544
479
|
private
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json-schema/schema/validator'
|
2
|
+
|
1
3
|
module JSON
|
2
4
|
class Schema
|
3
5
|
|
@@ -22,11 +24,22 @@ module JSON
|
|
22
24
|
"items" => JSON::Schema::ItemsAttribute,
|
23
25
|
"extends" => JSON::Schema::ExtendsAttribute
|
24
26
|
}
|
27
|
+
@default_formats = {
|
28
|
+
'date-time' => DateTimeFormat,
|
29
|
+
'date' => DateFormat,
|
30
|
+
'time' => TimeFormat,
|
31
|
+
'ip-address' => IP4Format,
|
32
|
+
'ipv6' => IP6Format,
|
33
|
+
'uri' => UriFormat
|
34
|
+
}
|
35
|
+
@formats = @default_formats.clone
|
25
36
|
@uri = URI.parse("http://json-schema.org/draft-01/schema#")
|
37
|
+
@names = ["draft1"]
|
38
|
+
@metaschema = File.join("resources", "draft-01.json")
|
26
39
|
end
|
27
40
|
|
28
41
|
JSON::Validator.register_validator(self.new)
|
29
42
|
end
|
30
43
|
|
31
44
|
end
|
32
|
-
end
|
45
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json-schema/schema/validator'
|
2
|
+
|
1
3
|
module JSON
|
2
4
|
class Schema
|
3
5
|
|
@@ -23,11 +25,22 @@ module JSON
|
|
23
25
|
"items" => JSON::Schema::ItemsAttribute,
|
24
26
|
"extends" => JSON::Schema::ExtendsAttribute
|
25
27
|
}
|
28
|
+
@default_formats = {
|
29
|
+
'date-time' => DateTimeFormat,
|
30
|
+
'date' => DateFormat,
|
31
|
+
'time' => TimeFormat,
|
32
|
+
'ip-address' => IP4Format,
|
33
|
+
'ipv6' => IP6Format,
|
34
|
+
'uri' => UriFormat
|
35
|
+
}
|
36
|
+
@formats = @default_formats.clone
|
26
37
|
@uri = URI.parse("http://json-schema.org/draft-02/schema#")
|
38
|
+
@names = ["draft2"]
|
39
|
+
@metaschema = File.join("resources", "draft-02.json")
|
27
40
|
end
|
28
41
|
|
29
42
|
JSON::Validator.register_validator(self.new)
|
30
43
|
end
|
31
44
|
|
32
45
|
end
|
33
|
-
end
|
46
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require 'json-schema/schema/validator'
|
2
|
+
|
1
3
|
module JSON
|
2
4
|
class Schema
|
3
5
|
|
@@ -27,12 +29,22 @@ module JSON
|
|
27
29
|
"extends" => JSON::Schema::ExtendsAttribute,
|
28
30
|
"$ref" => JSON::Schema::RefAttribute
|
29
31
|
}
|
32
|
+
@default_formats = {
|
33
|
+
'date-time' => DateTimeFormat,
|
34
|
+
'date' => DateFormat,
|
35
|
+
'ip-address' => IP4Format,
|
36
|
+
'ipv6' => IP6Format,
|
37
|
+
'time' => TimeFormat,
|
38
|
+
'uri' => UriFormat
|
39
|
+
}
|
40
|
+
@formats = @default_formats.clone
|
30
41
|
@uri = URI.parse("http://json-schema.org/draft-03/schema#")
|
42
|
+
@names = ["draft3", "http://json-schema.org/draft-03/schema#"]
|
43
|
+
@metaschema = File.join("resources", "draft-03.json")
|
31
44
|
end
|
32
45
|
|
33
46
|
JSON::Validator.register_validator(self.new)
|
34
|
-
JSON::Validator.register_default_validator(self.new)
|
35
47
|
end
|
36
48
|
|
37
49
|
end
|
38
|
-
end
|
50
|
+
end
|