json-schema 1.0.8 → 1.0.9
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.
- data/README.textile +1 -1
- data/lib/json-schema/attributes/additionalproperties.rb +34 -11
- data/lib/json-schema/attributes/extends.rb +30 -48
- data/lib/json-schema/attributes/ref.rb +23 -8
- data/lib/json-schema/validator.rb +1 -1
- data/test/schemas/extends_and_additionalProperties-1-filename.schema.json +34 -0
- data/test/schemas/extends_and_additionalProperties-1-ref.schema.json +34 -0
- data/test/schemas/extends_and_additionalProperties-2-filename.schema.json +33 -0
- data/test/schemas/extends_and_additionalProperties-2-ref.schema.json +33 -0
- data/test/schemas/inner.schema.json +21 -0
- data/test/test_extends_and_additionalProperties.rb +50 -0
- metadata +16 -3
data/README.textile
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'extends'
|
2
|
+
|
1
3
|
module JSON
|
2
4
|
class Schema
|
3
5
|
class AdditionalPropertiesAttribute < Attribute
|
@@ -5,6 +7,28 @@ module JSON
|
|
5
7
|
if data.is_a?(Hash)
|
6
8
|
extra_properties = data.keys
|
7
9
|
|
10
|
+
extra_properties = remove_valid_properties(extra_properties, current_schema, validator)
|
11
|
+
|
12
|
+
addprop= current_schema.schema['additionalProperties']
|
13
|
+
if addprop.is_a?(Hash)
|
14
|
+
matching_properties= extra_properties # & addprop.keys
|
15
|
+
matching_properties.each do |key|
|
16
|
+
schema = JSON::Schema.new(addprop[key] || addprop, current_schema.uri, validator)
|
17
|
+
fragments << key
|
18
|
+
schema.validate(data[key],fragments,options)
|
19
|
+
fragments.pop
|
20
|
+
end
|
21
|
+
extra_properties -= matching_properties
|
22
|
+
end
|
23
|
+
if !extra_properties.empty? and (addprop == false or (addprop.is_a?(Hash) and !addprop.empty?))
|
24
|
+
message = "The property '#{build_fragment(fragments)}' contains additional properties #{extra_properties.inspect} outside of the schema when none are allowed"
|
25
|
+
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.remove_valid_properties(extra_properties, current_schema, validator)
|
31
|
+
|
8
32
|
if current_schema.schema['properties']
|
9
33
|
extra_properties = extra_properties - current_schema.schema['properties'].keys
|
10
34
|
end
|
@@ -21,19 +45,18 @@ module JSON
|
|
21
45
|
end
|
22
46
|
end
|
23
47
|
|
24
|
-
if current_schema.schema['
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
schema.validate(data[key],fragments,options)
|
32
|
-
fragments.pop
|
48
|
+
if schemas= current_schema.schema['extends']
|
49
|
+
schemas = [schemas] if !schemas.is_a?(Array)
|
50
|
+
schemas.each do |schema_value|
|
51
|
+
temp_uri,extended_schema= JSON::Schema::ExtendsAttribute.get_extended_uri_and_schema(schema_value, current_schema, validator)
|
52
|
+
if extended_schema
|
53
|
+
extra_properties= remove_valid_properties(extra_properties, extended_schema, validator)
|
54
|
+
end
|
33
55
|
end
|
34
56
|
end
|
35
|
-
|
57
|
+
|
58
|
+
extra_properties
|
36
59
|
end
|
37
60
|
end
|
38
61
|
end
|
39
|
-
end
|
62
|
+
end
|
@@ -1,3 +1,5 @@
|
|
1
|
+
require_relative 'ref'
|
2
|
+
|
1
3
|
module JSON
|
2
4
|
class Schema
|
3
5
|
class ExtendsAttribute < Attribute
|
@@ -5,63 +7,43 @@ module JSON
|
|
5
7
|
schemas = current_schema.schema['extends']
|
6
8
|
schemas = [schemas] if !schemas.is_a?(Array)
|
7
9
|
schemas.each do |s|
|
8
|
-
|
9
|
-
|
10
|
+
uri,schema = get_extended_uri_and_schema(s, current_schema, validator)
|
11
|
+
if schema
|
10
12
|
schema.validate(data, fragments, options)
|
11
|
-
elsif
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
temp_uri.path = Pathname.new(path).cleanpath.to_s
|
21
|
-
else
|
22
|
-
temp_uri = current_schema.uri.merge(path)
|
23
|
-
end
|
24
|
-
temp_uri.fragment = s.split("#")[1]
|
25
|
-
end
|
26
|
-
temp_uri.fragment = "" if temp_uri.fragment.nil?
|
13
|
+
elsif uri
|
14
|
+
message = "The extended schema '#{uri.to_s}' cannot be found"
|
15
|
+
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
16
|
+
else
|
17
|
+
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
18
|
+
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
27
22
|
|
28
|
-
|
29
|
-
|
23
|
+
def self.get_extended_uri_and_schema(s, current_schema, validator)
|
24
|
+
uri,schema = nil,nil
|
30
25
|
|
31
|
-
|
26
|
+
s = {'$ref' => s} if s.is_a?(String)
|
32
27
|
|
28
|
+
if s.is_a?(Hash)
|
29
|
+
uri = current_schema.uri
|
30
|
+
if s['$ref']
|
31
|
+
ref_uri,ref_schema = JSON::Schema::RefAttribute.get_referenced_uri_and_schema(s, current_schema, validator)
|
33
32
|
if ref_schema
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
if target_schema.is_a?(Array)
|
41
|
-
target_schema = target_schema[fragment.to_i]
|
42
|
-
else
|
43
|
-
target_schema = target_schema[fragment]
|
44
|
-
end
|
45
|
-
fragment_path = fragment_path + "/#{fragment}"
|
46
|
-
if target_schema.nil?
|
47
|
-
raise SchemaError.new("The fragment '#{fragment_path}' does not exist on schema #{ref_schema.uri.to_s}")
|
48
|
-
end
|
49
|
-
end
|
33
|
+
if s.size == 1 # Check if anything else apart from $ref
|
34
|
+
uri,schema = ref_uri,ref_schema
|
35
|
+
else
|
36
|
+
s = s.dup
|
37
|
+
s.delete '$ref'
|
38
|
+
s = ref_schema.schema.merge(s)
|
50
39
|
end
|
51
|
-
|
52
|
-
# We have the schema finally, build it and validate!
|
53
|
-
schema = JSON::Schema.new(target_schema,temp_uri,validator)
|
54
|
-
schema.validate(data, fragments, options)
|
55
|
-
else
|
56
|
-
message = "The extended schema '#{temp_uri.to_s}' cannot be found"
|
57
|
-
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
58
40
|
end
|
59
|
-
else
|
60
|
-
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
61
|
-
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
62
41
|
end
|
42
|
+
schema ||= JSON::Schema.new(s,uri,validator)
|
63
43
|
end
|
44
|
+
|
45
|
+
[uri,schema]
|
64
46
|
end
|
65
47
|
end
|
66
48
|
end
|
67
|
-
end
|
49
|
+
end
|
@@ -1,12 +1,28 @@
|
|
1
1
|
module JSON
|
2
2
|
class Schema
|
3
3
|
class RefAttribute < Attribute
|
4
|
-
def self.validate(current_schema, data, fragments, validator, options = {})
|
5
|
-
|
4
|
+
def self.validate(current_schema, data, fragments, validator, options = {})
|
5
|
+
uri,schema = get_referenced_uri_and_schema(current_schema.schema, current_schema, validator)
|
6
|
+
|
7
|
+
if schema
|
8
|
+
schema.validate(data, fragments, options)
|
9
|
+
elsif uri
|
10
|
+
message = "The referenced schema '#{uri.to_s}' cannot be found"
|
11
|
+
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
12
|
+
else
|
13
|
+
message = "The property '#{build_fragment(fragments)}' was not a valid schema"
|
14
|
+
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.get_referenced_uri_and_schema(s, current_schema, validator)
|
19
|
+
uri,schema = nil,nil
|
20
|
+
|
21
|
+
temp_uri = URI.parse(s['$ref'])
|
6
22
|
if temp_uri.relative?
|
7
23
|
temp_uri = current_schema.uri.clone
|
8
24
|
# Check for absolute path
|
9
|
-
path =
|
25
|
+
path = s['$ref'].split("#")[0]
|
10
26
|
if path.nil? || path == ''
|
11
27
|
temp_uri.path = current_schema.uri.path
|
12
28
|
elsif path[0,1] == "/"
|
@@ -14,7 +30,7 @@ module JSON
|
|
14
30
|
else
|
15
31
|
temp_uri = current_schema.uri.merge(path)
|
16
32
|
end
|
17
|
-
temp_uri.fragment =
|
33
|
+
temp_uri.fragment = s['$ref'].split("#")[1]
|
18
34
|
end
|
19
35
|
temp_uri.fragment = "" if temp_uri.fragment.nil?
|
20
36
|
|
@@ -43,12 +59,11 @@ module JSON
|
|
43
59
|
end
|
44
60
|
|
45
61
|
# We have the schema finally, build it and validate!
|
62
|
+
uri = temp_uri
|
46
63
|
schema = JSON::Schema.new(target_schema,temp_uri,validator)
|
47
|
-
schema.validate(data, fragments, options)
|
48
|
-
else
|
49
|
-
message = "The referenced schema '#{temp_uri.to_s}' cannot be found"
|
50
|
-
validation_error(message, fragments, current_schema, self, options[:record_errors])
|
51
64
|
end
|
65
|
+
|
66
|
+
[uri,schema]
|
52
67
|
end
|
53
68
|
end
|
54
69
|
end
|
@@ -407,7 +407,7 @@ module JSON
|
|
407
407
|
|
408
408
|
def parse(s)
|
409
409
|
if defined?(MultiJson)
|
410
|
-
MultiJson.respond_to?(:
|
410
|
+
MultiJson.respond_to?(:adapter) ? MultiJson.load(s) : MultiJson.decode(s)
|
411
411
|
else
|
412
412
|
case @@json_backend.to_s
|
413
413
|
when 'json'
|
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-03/schema#",
|
3
|
+
"type": "object",
|
4
|
+
"extends": "inner.schema.json",
|
5
|
+
"properties": {
|
6
|
+
"outerA": {
|
7
|
+
"description": "blah",
|
8
|
+
"required": false,
|
9
|
+
"additionalProperties": false,
|
10
|
+
"properties": {
|
11
|
+
"outerA1": {
|
12
|
+
"type":"boolean",
|
13
|
+
"required": false
|
14
|
+
}
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"outerB": {
|
18
|
+
"required": false,
|
19
|
+
"type": "array",
|
20
|
+
"minItems": 1,
|
21
|
+
"maxItems": 50,
|
22
|
+
"items": {
|
23
|
+
"extends": "inner.schema.json",
|
24
|
+
"additionalProperties": false
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"outerC": {
|
28
|
+
"description": "blah",
|
29
|
+
"type":"boolean",
|
30
|
+
"required": false
|
31
|
+
}
|
32
|
+
},
|
33
|
+
"additionalProperties": false
|
34
|
+
}
|
@@ -0,0 +1,34 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-03/schema#",
|
3
|
+
"type": "object",
|
4
|
+
"extends": {"$ref":"inner.schema.json#"},
|
5
|
+
"properties": {
|
6
|
+
"outerA": {
|
7
|
+
"description": "blah",
|
8
|
+
"required": false,
|
9
|
+
"additionalProperties": false,
|
10
|
+
"properties": {
|
11
|
+
"outerA1": {
|
12
|
+
"type":"boolean",
|
13
|
+
"required": false
|
14
|
+
}
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"outerB": {
|
18
|
+
"required": false,
|
19
|
+
"type": "array",
|
20
|
+
"minItems": 1,
|
21
|
+
"maxItems": 50,
|
22
|
+
"items": {
|
23
|
+
"extends": {"$ref":"inner.schema.json#"},
|
24
|
+
"additionalProperties": false
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"outerC": {
|
28
|
+
"description": "blah",
|
29
|
+
"type":"boolean",
|
30
|
+
"required": false
|
31
|
+
}
|
32
|
+
},
|
33
|
+
"additionalProperties": false
|
34
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-03/schema#",
|
3
|
+
"type": "object",
|
4
|
+
"extends": "inner.schema.json",
|
5
|
+
"additionalProperties": {
|
6
|
+
"outerA": {
|
7
|
+
"description": "blah",
|
8
|
+
"required": false,
|
9
|
+
"additionalProperties": false,
|
10
|
+
"properties": {
|
11
|
+
"outerA1": {
|
12
|
+
"type":"boolean",
|
13
|
+
"required": false
|
14
|
+
}
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"outerB": {
|
18
|
+
"required": false,
|
19
|
+
"type": "array",
|
20
|
+
"minItems": 1,
|
21
|
+
"maxItems": 50,
|
22
|
+
"items": {
|
23
|
+
"extends": "inner.schema.json",
|
24
|
+
"additionalProperties": false
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"outerC": {
|
28
|
+
"description": "blah",
|
29
|
+
"type":"boolean",
|
30
|
+
"required": false
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,33 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-03/schema#",
|
3
|
+
"type": "object",
|
4
|
+
"extends": {"$ref":"inner.schema.json#"},
|
5
|
+
"additionalProperties": {
|
6
|
+
"outerA": {
|
7
|
+
"description": "blah",
|
8
|
+
"required": false,
|
9
|
+
"additionalProperties": false,
|
10
|
+
"properties": {
|
11
|
+
"outerA1": {
|
12
|
+
"type":"boolean",
|
13
|
+
"required": false
|
14
|
+
}
|
15
|
+
}
|
16
|
+
},
|
17
|
+
"outerB": {
|
18
|
+
"required": false,
|
19
|
+
"type": "array",
|
20
|
+
"minItems": 1,
|
21
|
+
"maxItems": 50,
|
22
|
+
"items": {
|
23
|
+
"extends": {"$ref":"inner.schema.json#"},
|
24
|
+
"additionalProperties": false
|
25
|
+
}
|
26
|
+
},
|
27
|
+
"outerC": {
|
28
|
+
"description": "blah",
|
29
|
+
"type":"boolean",
|
30
|
+
"required": false
|
31
|
+
}
|
32
|
+
}
|
33
|
+
}
|
@@ -0,0 +1,21 @@
|
|
1
|
+
{
|
2
|
+
"$schema": "http://json-schema.org/draft-03/schema#",
|
3
|
+
"type": "object",
|
4
|
+
"properties": {
|
5
|
+
"innerA": {
|
6
|
+
"description": "blah",
|
7
|
+
"type":"boolean",
|
8
|
+
"required": false
|
9
|
+
},
|
10
|
+
"innerB": {
|
11
|
+
"description": "blah",
|
12
|
+
"type":"boolean",
|
13
|
+
"required": false
|
14
|
+
},
|
15
|
+
"innerC": {
|
16
|
+
"description": "blah",
|
17
|
+
"required": false,
|
18
|
+
"type": "boolean"
|
19
|
+
}
|
20
|
+
}
|
21
|
+
}
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/json-schema'
|
3
|
+
|
4
|
+
class ExtendsNestedTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def assert_validity(valid, schema_name, data, msg=nil)
|
7
|
+
file = File.expand_path("../schemas/#{schema_name}.schema.json",__FILE__)
|
8
|
+
errors = JSON::Validator.fully_validate file, data
|
9
|
+
msg.sub! /\.$/, '' if msg
|
10
|
+
send (valid ? :assert_equal : :refute_equal), [], errors, \
|
11
|
+
"Schema should be #{valid ? :valid : :invalid}#{msg ? ".\n[#{schema_name}] #{msg}" : ''}"
|
12
|
+
end
|
13
|
+
|
14
|
+
def assert_valid(schema_name, data, msg=nil) assert_validity true, schema_name, data, msg end
|
15
|
+
def refute_valid(schema_name, data, msg=nil) assert_validity false, schema_name, data, msg end
|
16
|
+
|
17
|
+
%w[
|
18
|
+
extends_and_additionalProperties-1-filename extends_and_additionalProperties-1-ref
|
19
|
+
extends_and_additionalProperties-2-filename extends_and_additionalProperties-2-ref
|
20
|
+
].each do |schema_name|
|
21
|
+
test_prefix= 'test_' + schema_name.gsub('-','_')
|
22
|
+
class_eval <<-EOB
|
23
|
+
|
24
|
+
def #{test_prefix}_valid_outer
|
25
|
+
assert_valid '#{schema_name}', {"outerC"=>true}, "Outer defn is broken, maybe the outer extends overrode it?"
|
26
|
+
end
|
27
|
+
|
28
|
+
def #{test_prefix}_valid_outer_extended
|
29
|
+
assert_valid '#{schema_name}', {"innerA"=>true}, "Extends at the root level isn't working."
|
30
|
+
end
|
31
|
+
|
32
|
+
def #{test_prefix}_valid_inner
|
33
|
+
assert_valid '#{schema_name}', {"outerB"=>[{"innerA"=>true}]}, "Extends isn't working in the array element defn."
|
34
|
+
end
|
35
|
+
|
36
|
+
def #{test_prefix}_invalid_inner
|
37
|
+
refute_valid '#{schema_name}', {"outerB"=>[{"whaaaaat"=>true}]}, "Array element defn allowing anything when it should only allow what's in inner.schema"
|
38
|
+
end
|
39
|
+
EOB
|
40
|
+
|
41
|
+
if schema_name['extends_and_additionalProperties-1']
|
42
|
+
class_eval <<-EOB
|
43
|
+
def #{test_prefix}_invalid_outer
|
44
|
+
refute_valid '#{schema_name}', {"whaaaaat"=>true}, "Outer defn allowing anything when it shouldn't."
|
45
|
+
end
|
46
|
+
EOB
|
47
|
+
end
|
48
|
+
|
49
|
+
end
|
50
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.9
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-
|
12
|
+
date: 2012-08-29 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description:
|
15
15
|
email: hoxworth@gmail.com
|
@@ -58,6 +58,7 @@ files:
|
|
58
58
|
- README.textile
|
59
59
|
- LICENSE.md
|
60
60
|
- test/test_extended_schema.rb
|
61
|
+
- test/test_extends_and_additionalProperties.rb
|
61
62
|
- test/test_files.rb
|
62
63
|
- test/test_full_validation.rb
|
63
64
|
- test/test_jsonschema_draft1.rb
|
@@ -66,8 +67,13 @@ files:
|
|
66
67
|
- test/test_schema_validation.rb
|
67
68
|
- test/data/bad_data_1.json
|
68
69
|
- test/data/good_data_1.json
|
70
|
+
- test/schemas/extends_and_additionalProperties-1-filename.schema.json
|
71
|
+
- test/schemas/extends_and_additionalProperties-1-ref.schema.json
|
72
|
+
- test/schemas/extends_and_additionalProperties-2-filename.schema.json
|
73
|
+
- test/schemas/extends_and_additionalProperties-2-ref.schema.json
|
69
74
|
- test/schemas/good_schema_1.json
|
70
75
|
- test/schemas/good_schema_2.json
|
76
|
+
- test/schemas/inner.schema.json
|
71
77
|
homepage: http://github.com/hoxworth/json-schema/tree/master
|
72
78
|
licenses: []
|
73
79
|
post_install_message:
|
@@ -88,12 +94,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
88
94
|
version: '0'
|
89
95
|
requirements: []
|
90
96
|
rubyforge_project:
|
91
|
-
rubygems_version: 1.8.
|
97
|
+
rubygems_version: 1.8.24
|
92
98
|
signing_key:
|
93
99
|
specification_version: 3
|
94
100
|
summary: Ruby JSON Schema Validator
|
95
101
|
test_files:
|
96
102
|
- test/test_extended_schema.rb
|
103
|
+
- test/test_extends_and_additionalProperties.rb
|
97
104
|
- test/test_files.rb
|
98
105
|
- test/test_full_validation.rb
|
99
106
|
- test/test_jsonschema_draft1.rb
|
@@ -102,5 +109,11 @@ test_files:
|
|
102
109
|
- test/test_schema_validation.rb
|
103
110
|
- test/data/bad_data_1.json
|
104
111
|
- test/data/good_data_1.json
|
112
|
+
- test/schemas/extends_and_additionalProperties-1-filename.schema.json
|
113
|
+
- test/schemas/extends_and_additionalProperties-1-ref.schema.json
|
114
|
+
- test/schemas/extends_and_additionalProperties-2-filename.schema.json
|
115
|
+
- test/schemas/extends_and_additionalProperties-2-ref.schema.json
|
105
116
|
- test/schemas/good_schema_1.json
|
106
117
|
- test/schemas/good_schema_2.json
|
118
|
+
- test/schemas/inner.schema.json
|
119
|
+
has_rdoc:
|