openc-json_schema 0.0.3 → 0.0.4
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/.gitignore +1 -0
- data/Gemfile +4 -0
- data/Gemfile.lock +16 -4
- data/lib/openc/json_schema.rb +2 -2
- data/lib/openc/json_schema/validator.rb +74 -34
- data/lib/openc/json_schema/version.rb +1 -1
- data/openc-json_schema.gemspec +1 -1
- data/spec/openc_json_schema_spec.rb +112 -1
- data/spec/schemas/fff.json +7 -0
- data/spec/schemas/iii.json +7 -0
- data/spec/schemas/includes/ggg.json +6 -0
- data/spec/schemas/includes/hhh.json +8 -0
- data/spec/schemas/includes/jjj.json +6 -0
- data/spec/schemas/includes/mmm.json +6 -0
- data/spec/schemas/kkk.json +8 -0
- data/spec/schemas/lll.json +11 -0
- data/spec/spec_helper.rb +7 -6
- metadata +18 -16
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
YmE0MDA3M2IxMWZhMTlhZGU5MDdhNmMzNzJmMjA3MzYzZGI5MjE5Mg==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
YjQyN2Q2YWYyMjgyYmJiZWJlN2YxMDk3MzU4ZWUzM2E5ZWMzZGI5ZA==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MTBjYTFhZTIyOWMyNzUzOTZkNTJkZTI5OTU2NzY4NWU0N2FiNzkxNWJiNjQ3
|
10
|
+
MTViOTg0ODVjZjg0YTY3MjdiMzExMzZjMjQxNDQyOWE2ZDJlNzI1NTk4Mjg2
|
11
|
+
ODI3YmRkZGJlMzg3NmMzZTBkNmM5ZTFmYTJkOTI0MmI4Njc5Yjg=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
OTBjNjliN2EzOWUzZmRhMDcyMzk0ZDkyMzc4OWFkNzZjMzFhNjUxYTM0ZTNh
|
14
|
+
MjFiODNlYTVlMTVkYzdhMDgxNjY0MzllMThjZTRkOGFjM2ZhYTMxMWQ4NTA1
|
15
|
+
N2RmNmVjNWJlYWJkNmRkMGM2N2VhZTZlNzMwYjQ0YWFhMjk1ZWQ=
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
@@ -2,3 +2,7 @@ source 'https://rubygems.org'
|
|
2
2
|
|
3
3
|
# Specify your gem's dependencies in openc-json-schema.gemspec
|
4
4
|
gemspec
|
5
|
+
|
6
|
+
gem 'json-schema', :git => 'git://github.com/ruby-json-schema/json-schema.git', :ref => 'aded4d798a48545184dae7ae0a3bb41ec2794c88'
|
7
|
+
|
8
|
+
gem 'simplecov', :require => false
|
data/Gemfile.lock
CHANGED
@@ -1,16 +1,22 @@
|
|
1
|
+
GIT
|
2
|
+
remote: git://github.com/ruby-json-schema/json-schema.git
|
3
|
+
revision: aded4d798a48545184dae7ae0a3bb41ec2794c88
|
4
|
+
ref: aded4d798a48545184dae7ae0a3bb41ec2794c88
|
5
|
+
specs:
|
6
|
+
json-schema (2.5.0)
|
7
|
+
addressable (~> 2.3)
|
8
|
+
|
1
9
|
PATH
|
2
10
|
remote: .
|
3
11
|
specs:
|
4
|
-
openc-json_schema (0.0.
|
5
|
-
json-schema (= 2.5.0)
|
12
|
+
openc-json_schema (0.0.4)
|
6
13
|
|
7
14
|
GEM
|
8
15
|
remote: https://rubygems.org/
|
9
16
|
specs:
|
10
17
|
addressable (2.3.7)
|
11
18
|
diff-lcs (1.2.5)
|
12
|
-
|
13
|
-
addressable (~> 2.3)
|
19
|
+
multi_json (1.10.1)
|
14
20
|
rake (10.4.2)
|
15
21
|
rspec (3.1.0)
|
16
22
|
rspec-core (~> 3.1.0)
|
@@ -24,12 +30,18 @@ GEM
|
|
24
30
|
rspec-mocks (3.1.3)
|
25
31
|
rspec-support (~> 3.1.0)
|
26
32
|
rspec-support (3.1.2)
|
33
|
+
simplecov (0.7.1)
|
34
|
+
multi_json (~> 1.0)
|
35
|
+
simplecov-html (~> 0.7.1)
|
36
|
+
simplecov-html (0.7.1)
|
27
37
|
|
28
38
|
PLATFORMS
|
29
39
|
ruby
|
30
40
|
|
31
41
|
DEPENDENCIES
|
32
42
|
bundler (~> 1.7)
|
43
|
+
json-schema!
|
33
44
|
openc-json_schema!
|
34
45
|
rake (~> 10.0)
|
35
46
|
rspec (~> 3.0)
|
47
|
+
simplecov
|
data/lib/openc/json_schema.rb
CHANGED
@@ -7,8 +7,8 @@ module Openc
|
|
7
7
|
module JsonSchema
|
8
8
|
extend self
|
9
9
|
|
10
|
-
def validate(
|
11
|
-
Validator.validate(
|
10
|
+
def validate(schema_path, record)
|
11
|
+
Validator.validate(schema_path, record)
|
12
12
|
end
|
13
13
|
end
|
14
14
|
end
|
@@ -3,64 +3,100 @@ module Openc
|
|
3
3
|
module Validator
|
4
4
|
extend self
|
5
5
|
|
6
|
-
def validate(
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
end
|
16
|
-
|
17
|
-
# We must change directory for the relative paths in schemas to make sense.
|
18
|
-
errors = Dir.chdir(schema_dir) do
|
19
|
-
JSON::Validator.fully_validate(schema, record, :errors_as_objects => true)
|
20
|
-
end
|
6
|
+
def validate(schema_path, record)
|
7
|
+
validator = JSON::Validator.new(
|
8
|
+
schema_path,
|
9
|
+
record,
|
10
|
+
:record_errors => true,
|
11
|
+
:errors_as_objects => true,
|
12
|
+
:validate_schema => true
|
13
|
+
)
|
14
|
+
errors = validator.validate
|
21
15
|
|
22
16
|
# For now, we just handle the first error.
|
23
17
|
error = errors[0]
|
24
18
|
return if error.nil?
|
25
19
|
|
26
|
-
|
27
|
-
|
28
|
-
match = error[:message].match(/required property of '(.*)'/)
|
29
|
-
missing_property = match[1]
|
30
|
-
path = fragment_to_path("#{error[:fragment]}/#{missing_property}")
|
20
|
+
convert_error(extract_error(error, record, validator))
|
21
|
+
end
|
31
22
|
|
32
|
-
|
33
|
-
|
23
|
+
def extract_error(error, record, validator)
|
24
|
+
if error[:failed_attribute] == 'OneOf'
|
34
25
|
if error[:message].match(/did not match any/)
|
35
26
|
path_elements = fragment_to_path(error[:fragment]).split('.')
|
36
27
|
|
37
|
-
|
38
|
-
|
28
|
+
json_schema = validator.instance_variable_get(:@base_schema)
|
29
|
+
schema = json_schema.schema
|
39
30
|
|
40
31
|
path_elements.each do |element|
|
41
|
-
|
42
|
-
|
32
|
+
record = record[element]
|
33
|
+
schema = schema['properties'][element]
|
34
|
+
|
35
|
+
if (ref = schema['$ref'])
|
36
|
+
schema_uri = validator.absolutize_ref_uri(ref, json_schema.uri)
|
37
|
+
json_schema = JSON::Validator.schema_reader.read(schema_uri)
|
38
|
+
schema = json_schema.schema
|
39
|
+
end
|
43
40
|
end
|
44
41
|
|
45
|
-
one_of_schemas =
|
42
|
+
one_of_schemas = schema['oneOf']
|
46
43
|
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
44
|
+
schemas_for_type_with_ix = case record
|
45
|
+
when Hash
|
46
|
+
one_of_schemas.each_with_index.reject {|s, ix| s['properties'].nil?}
|
47
|
+
when String
|
48
|
+
one_of_schemas.each_with_index.select {|s, ix| s['type'] == 'string' || (s['type'].nil? && s['properties'].nil?)}
|
49
|
+
when Integer
|
50
|
+
one_of_schemas.each_with_index.select {|s, ix| s['type'] == 'integer'}
|
51
|
+
when Array
|
52
|
+
one_of_schemas.each_with_index.select {|s, ix| s['type'] == 'array'}
|
53
|
+
else
|
54
|
+
raise "Unexpected type: #{record}"
|
55
|
+
end
|
51
56
|
|
52
|
-
|
53
|
-
|
54
|
-
|
57
|
+
case schemas_for_type_with_ix.size
|
58
|
+
when 0
|
59
|
+
return error
|
60
|
+
when 1
|
61
|
+
ix = schemas_for_type_with_ix[0][1]
|
62
|
+
return error[:errors][:"oneof_#{ix}"][0]
|
63
|
+
else
|
64
|
+
if record.is_a?(Hash)
|
65
|
+
schemas_for_type_with_ix.each do |s, ix|
|
66
|
+
s['properties'].each do |k, v|
|
67
|
+
next if v['enum'].nil?
|
68
|
+
|
69
|
+
if v['enum'].include?(record[k])
|
70
|
+
return error[:errors][:"oneof_#{ix}"][0]
|
71
|
+
end
|
55
72
|
end
|
56
73
|
end
|
74
|
+
else
|
75
|
+
return error
|
57
76
|
end
|
58
77
|
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
error
|
82
|
+
end
|
83
|
+
|
84
|
+
def convert_error(error)
|
85
|
+
case error[:failed_attribute]
|
86
|
+
when 'Required'
|
87
|
+
match = error[:message].match(/required property of '(.*)'/)
|
88
|
+
missing_property = match[1]
|
89
|
+
path = fragment_to_path("#{error[:fragment]}/#{missing_property}")
|
59
90
|
|
91
|
+
{:type => :missing, :path => path}
|
92
|
+
when 'OneOf'
|
93
|
+
if error[:message].match(/did not match any/)
|
60
94
|
{:type => :one_of_no_matches, :path => fragment_to_path(error[:fragment])}
|
61
95
|
else
|
62
96
|
{:type => :one_of_many_matches, :path => fragment_to_path(error[:fragment])}
|
63
97
|
end
|
98
|
+
when 'AnyOf'
|
99
|
+
{:type => :any_of_no_matches, :path => fragment_to_path(error[:fragment])}
|
64
100
|
when 'MinLength'
|
65
101
|
match = error[:message].match(/minimum string length of (\d+) in/)
|
66
102
|
min_length = match[1].to_i
|
@@ -77,6 +113,10 @@ module Openc
|
|
77
113
|
match = error[:message].match(/the following values: ([\w\s,]+) in schema/)
|
78
114
|
allowed_values = match[1].split(',').map(&:strip)
|
79
115
|
{:type => :enum_mismatch, :path => fragment_to_path(error[:fragment]), :allowed_values => allowed_values}
|
116
|
+
when 'AdditionalProperties'
|
117
|
+
match = error[:message].match(/contains additional properties \["(.*)"\] outside of the schema/)
|
118
|
+
extra_properties = match[1].split('", "')
|
119
|
+
{:type => :extra_properties, :path => fragment_to_path(error[:fragment]), :extra_properties => extra_properties}
|
80
120
|
else
|
81
121
|
if error[:message].match(/must be of format yyyy-mm-dd/)
|
82
122
|
{:type => :format_mismatch, :path => fragment_to_path(error[:fragment]), :expected_format => 'yyyy-mm-dd'}
|
data/openc-json_schema.gemspec
CHANGED
@@ -277,6 +277,25 @@ describe Openc::JsonSchema do
|
|
277
277
|
)
|
278
278
|
end
|
279
279
|
|
280
|
+
specify 'when additional properties are present but disallowed' do
|
281
|
+
schema = {
|
282
|
+
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
283
|
+
'type' => 'object',
|
284
|
+
'properties' => {
|
285
|
+
'aaa' => {'type' => 'number'}
|
286
|
+
},
|
287
|
+
'additionalProperties' => false
|
288
|
+
}
|
289
|
+
|
290
|
+
record = {'aaa' => 1, 'bbb' => 2, 'ccc' => 3}
|
291
|
+
|
292
|
+
expect([schema, record]).to fail_validation_with(
|
293
|
+
:type => :extra_properties,
|
294
|
+
:path => '',
|
295
|
+
:extra_properties => ['bbb', 'ccc']
|
296
|
+
)
|
297
|
+
end
|
298
|
+
|
280
299
|
specify 'when property of wrong format' do
|
281
300
|
schema = {
|
282
301
|
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
@@ -329,7 +348,72 @@ describe Openc::JsonSchema do
|
|
329
348
|
end
|
330
349
|
end
|
331
350
|
|
332
|
-
|
351
|
+
context 'when schema includes nested $refs' do
|
352
|
+
specify 'when data is valid' do
|
353
|
+
schema_path = 'spec/schemas/fff.json'
|
354
|
+
record = {'fff' => {'ggg' => {'hhh' => 123}}}
|
355
|
+
expect([schema_path, record]).to be_valid
|
356
|
+
end
|
357
|
+
|
358
|
+
specify 'when data is invalid' do
|
359
|
+
schema_path = 'spec/schemas/fff.json'
|
360
|
+
record = {'fff' => {'ggg' => {'hhh' => '123'}}}
|
361
|
+
expect([schema_path, record]).to fail_validation_with(
|
362
|
+
:type => :type_mismatch,
|
363
|
+
:path => 'fff.ggg.hhh',
|
364
|
+
:allowed_types => ['number']
|
365
|
+
)
|
366
|
+
end
|
367
|
+
|
368
|
+
context 'and schema is an included schema' do
|
369
|
+
specify 'when data is valid' do
|
370
|
+
schema_path = 'spec/schemas/includes/ggg.json'
|
371
|
+
record = {'ggg' => {'hhh' => 123}}
|
372
|
+
expect([schema_path, record]).to be_valid
|
373
|
+
end
|
374
|
+
|
375
|
+
specify 'when data is invalid' do
|
376
|
+
schema_path = 'spec/schemas/includes/ggg.json'
|
377
|
+
record = {'ggg' => {'hhh' => '123'}}
|
378
|
+
expect([schema_path, record]).to fail_validation_with(
|
379
|
+
:type => :type_mismatch,
|
380
|
+
:path => 'ggg.hhh',
|
381
|
+
:allowed_types => ['number']
|
382
|
+
)
|
383
|
+
end
|
384
|
+
end
|
385
|
+
|
386
|
+
context 'and there is a $ref to something in an outer directory' do
|
387
|
+
specify 'when data is valid' do
|
388
|
+
schema_path = 'spec/schemas/iii.json'
|
389
|
+
record = {'iii' => {'jjj' => {'kkk' => 123}}}
|
390
|
+
expect([schema_path, record]).to be_valid
|
391
|
+
end
|
392
|
+
|
393
|
+
specify 'when data is invalid' do
|
394
|
+
schema_path = 'spec/schemas/iii.json'
|
395
|
+
record = {'iii' => {'jjj' => {'kkk' => '123'}}}
|
396
|
+
expect([schema_path, record]).to fail_validation_with(
|
397
|
+
:type => :type_mismatch,
|
398
|
+
:path => 'iii.jjj.kkk',
|
399
|
+
:allowed_types => ['number']
|
400
|
+
)
|
401
|
+
end
|
402
|
+
end
|
403
|
+
end
|
404
|
+
|
405
|
+
specify 'when schema includes oneOfs which contain $refs directly' do
|
406
|
+
schema_path = 'spec/schemas/lll.json'
|
407
|
+
record = {
|
408
|
+
'mmm' => []
|
409
|
+
}
|
410
|
+
expect([schema_path, record]).to fail_validation_with(
|
411
|
+
:type => :one_of_no_matches,
|
412
|
+
:path => 'mmm'
|
413
|
+
)
|
414
|
+
end
|
415
|
+
|
416
|
+
specify 'when schema includes oneOfs which contain $refs indirectly' do
|
333
417
|
schema_path = 'spec/schemas/ccc.json'
|
334
418
|
record = {
|
335
419
|
'ccc' => {
|
@@ -345,5 +429,32 @@ describe Openc::JsonSchema do
|
|
345
429
|
:allowed_types => ['number'],
|
346
430
|
)
|
347
431
|
end
|
432
|
+
|
433
|
+
specify '' do
|
434
|
+
schema = {
|
435
|
+
'$schema' => 'http://json-schema.org/draft-04/schema#',
|
436
|
+
'type' => 'object',
|
437
|
+
'properties' => {
|
438
|
+
'aaa' => {
|
439
|
+
'oneOf' => [
|
440
|
+
{
|
441
|
+
'type' => 'string',
|
442
|
+
'format' => 'date'
|
443
|
+
},
|
444
|
+
{
|
445
|
+
'type' => 'integer',
|
446
|
+
'maxLength' => 2
|
447
|
+
}
|
448
|
+
]
|
449
|
+
}
|
450
|
+
}
|
451
|
+
}
|
452
|
+
record = {'aaa' => 'not-a-date'}
|
453
|
+
expect([schema, record]).to fail_validation_with(
|
454
|
+
:type => :format_mismatch,
|
455
|
+
:path => 'aaa',
|
456
|
+
:expected_format => 'yyyy-mm-dd'
|
457
|
+
)
|
458
|
+
end
|
348
459
|
end
|
349
460
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,3 +1,6 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
SimpleCov.start
|
3
|
+
|
1
4
|
require 'openc/json_schema'
|
2
5
|
|
3
6
|
def get_error(schema_or_path, record)
|
@@ -5,17 +8,15 @@ def get_error(schema_or_path, record)
|
|
5
8
|
when Hash
|
6
9
|
json_data = schema_or_path.to_json
|
7
10
|
filename = Digest::MD5.hexdigest(json_data) + '.json'
|
8
|
-
|
9
|
-
File.open(
|
10
|
-
schema_or_filename = schema_or_path
|
11
|
+
schema_path = File.join('spec', 'tmp', filename)
|
12
|
+
File.open(schema_path, 'w') {|f| f.write(json_data)}
|
11
13
|
when String
|
12
|
-
|
13
|
-
schema_dir = File.dirname(schema_or_path)
|
14
|
+
schema_path = schema_or_path
|
14
15
|
else
|
15
16
|
raise
|
16
17
|
end
|
17
18
|
|
18
|
-
error = Openc::JsonSchema.validate(
|
19
|
+
error = Openc::JsonSchema.validate(schema_path, record)
|
19
20
|
end
|
20
21
|
|
21
22
|
RSpec::Matchers.define(:fail_validation_with) do |expected|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: openc-json_schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OpenCorporates
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-02-
|
11
|
+
date: 2015-02-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -52,20 +52,6 @@ dependencies:
|
|
52
52
|
- - ~>
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: '3.0'
|
55
|
-
- !ruby/object:Gem::Dependency
|
56
|
-
name: json-schema
|
57
|
-
requirement: !ruby/object:Gem::Requirement
|
58
|
-
requirements:
|
59
|
-
- - '='
|
60
|
-
- !ruby/object:Gem::Version
|
61
|
-
version: 2.5.0
|
62
|
-
type: :runtime
|
63
|
-
prerelease: false
|
64
|
-
version_requirements: !ruby/object:Gem::Requirement
|
65
|
-
requirements:
|
66
|
-
- - '='
|
67
|
-
- !ruby/object:Gem::Version
|
68
|
-
version: 2.5.0
|
69
55
|
description:
|
70
56
|
email: info@opencorporates.com
|
71
57
|
executables: []
|
@@ -87,9 +73,17 @@ files:
|
|
87
73
|
- spec/openc_json_schema_spec.rb
|
88
74
|
- spec/schemas/aaa.json
|
89
75
|
- spec/schemas/ccc.json
|
76
|
+
- spec/schemas/fff.json
|
77
|
+
- spec/schemas/iii.json
|
90
78
|
- spec/schemas/includes/bbb.json
|
91
79
|
- spec/schemas/includes/ddd.json
|
92
80
|
- spec/schemas/includes/eee.json
|
81
|
+
- spec/schemas/includes/ggg.json
|
82
|
+
- spec/schemas/includes/hhh.json
|
83
|
+
- spec/schemas/includes/jjj.json
|
84
|
+
- spec/schemas/includes/mmm.json
|
85
|
+
- spec/schemas/kkk.json
|
86
|
+
- spec/schemas/lll.json
|
93
87
|
- spec/spec_helper.rb
|
94
88
|
- spec/tmp/.gitkeep
|
95
89
|
homepage:
|
@@ -120,9 +114,17 @@ test_files:
|
|
120
114
|
- spec/openc_json_schema_spec.rb
|
121
115
|
- spec/schemas/aaa.json
|
122
116
|
- spec/schemas/ccc.json
|
117
|
+
- spec/schemas/fff.json
|
118
|
+
- spec/schemas/iii.json
|
123
119
|
- spec/schemas/includes/bbb.json
|
124
120
|
- spec/schemas/includes/ddd.json
|
125
121
|
- spec/schemas/includes/eee.json
|
122
|
+
- spec/schemas/includes/ggg.json
|
123
|
+
- spec/schemas/includes/hhh.json
|
124
|
+
- spec/schemas/includes/jjj.json
|
125
|
+
- spec/schemas/includes/mmm.json
|
126
|
+
- spec/schemas/kkk.json
|
127
|
+
- spec/schemas/lll.json
|
126
128
|
- spec/spec_helper.rb
|
127
129
|
- spec/tmp/.gitkeep
|
128
130
|
has_rdoc:
|