json_schema_tools 0.3.2 → 0.3.3
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/CHANGELOG.md +5 -1
- data/lib/schema_tools/ref_resolver.rb +18 -6
- data/lib/schema_tools/schema.rb +42 -16
- data/lib/schema_tools/version.rb +1 -1
- data/spec/fixtures/circular_references_twice.json +10 -0
- data/spec/fixtures_broken/circular_references.json +9 -0
- data/spec/fixtures_broken/circular_references_multi.json +14 -0
- data/spec/fixtures_broken/circular_references_multi_file_one.json +14 -0
- data/spec/fixtures_broken/circular_references_multi_file_two.json +14 -0
- data/spec/schema_tools/circuluar_ref_spec.rb +28 -0
- data/spec/schema_tools/reader_spec.rb +1 -0
- data/spec/schema_tools/ref_resolver_spec.rb +0 -1
- metadata +8 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
OWMzMmM0YmMzMDY4YmVhMjQ4MjI4Nzk1MGQwNTVjYzFiYTNlM2Q0ZQ==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
NDU3MjkxYTUxNjNlMWNkOGE5MGJkZGNkOTUxOGE3OThjMDM3NDIzNQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
NDBhMzllODdmMzgxOWQ3OWExM2IzZjU4YjIwYWZhODgyMzk5ZDU3NjUwNmY1
|
10
|
+
Mjg3ODcxZjEzMGE3N2JkODY1ZmMxOWI1MDFkMDVlODc0ODRlNDU2Mjc4NTAw
|
11
|
+
OGQ0NDQxOThkZGNkZjliMTYwMGY2ZDQ4ZmY2NDM3NjQ2YjU0YmI=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
NTNkOTU5YmU0OGQzNDMyYzAyZWQ1Mjc3ZGRkNWIzOGQ0MjU0NzcxOGRkODNj
|
14
|
+
NTcxNzEwZDAxNTAxMTk5Mzk4OGM1Y2U3NWEwMWY0NmY1NjZhZTQyNTA3ODYx
|
15
|
+
NDU1NWUxYzYzZWU4NTkyNjgwNzYwYzZjZDVmZGFkMjNjNWQyNjc=
|
data/CHANGELOG.md
CHANGED
@@ -1,13 +1,17 @@
|
|
1
1
|
# Changelog JSON Schema Tools
|
2
2
|
|
3
3
|
|
4
|
+
2014-10
|
5
|
+
|
6
|
+
* handle circular dependencies in $ref arguments, so schema.to_h always resolves $refs properly
|
7
|
+
|
4
8
|
2014-09
|
5
9
|
|
6
10
|
* add Schema class to represent a single schema, replaces simple Hash usage. Potentially breaks usage if you've gone crazy with Hash methods in your client.
|
7
11
|
|
8
12
|
2014-09
|
9
13
|
|
10
|
-
*
|
14
|
+
* refactor Reader to de-reference all pointers when initialized
|
11
15
|
* remove :exclude_root option for object to schema_hash BREAKING change if you want nesting define your schema accordingly
|
12
16
|
* add :links option for object to schema_hash, to include the links inline in an object
|
13
17
|
* support items definition for array type properties - BREAKING you must change old simple property definitions
|
@@ -1,6 +1,7 @@
|
|
1
1
|
# encoding: utf-8
|
2
2
|
|
3
3
|
require 'json'
|
4
|
+
require 'uri'
|
4
5
|
|
5
6
|
module SchemaTools
|
6
7
|
class RefResolver
|
@@ -13,7 +14,7 @@ module SchemaTools
|
|
13
14
|
# http://tools.ietf.org/html/draft-ietf-appsawg-json-pointer-07
|
14
15
|
#
|
15
16
|
# @param [String] json_pointer the JSON Pointer expression to evaluate
|
16
|
-
# @param [
|
17
|
+
# @param [Schema] relative_to if the pointer refers to a local schema, this is this
|
17
18
|
# the hash to evaluate it against. If the pointer contains a uri to a
|
18
19
|
# referenced schema, an attempt is made to load
|
19
20
|
def self.load_json_pointer json_pointer, relative_to = nil
|
@@ -26,14 +27,25 @@ module SchemaTools
|
|
26
27
|
uri = $1.strip
|
27
28
|
pointer = $2
|
28
29
|
schema = {}
|
29
|
-
|
30
|
+
unless uri.empty?
|
30
31
|
uri = URI.parse(uri)
|
31
32
|
raise "must currently be a relative uri: #{json_pointer}" if uri.absolute?
|
32
33
|
# TODO use locale tools instance or base path from global SchemaTools.schema_path
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
34
|
+
base_dir = relative_to ? relative_to.absolute_dir : SchemaTools.schema_path
|
35
|
+
path = File.join(base_dir, uri.path)
|
36
|
+
unless File.exist?(path)
|
37
|
+
# try to find in main-dir and subdirs of global schema path and if
|
38
|
+
# present a schema's absolute dir
|
39
|
+
filename = uri.path.split('/').last
|
40
|
+
search_dirs = [File.join(SchemaTools.schema_path, filename),
|
41
|
+
File.join(SchemaTools.schema_path, '**/*', filename)]
|
42
|
+
if relative_to
|
43
|
+
search_dirs += [ File.join(relative_to.absolute_dir, filename),
|
44
|
+
File.join(relative_to.absolute_dir, '**/*', filename) ]
|
45
|
+
end
|
46
|
+
recursive_search = Dir.glob(search_dirs)[0]
|
47
|
+
# if still not found keep orig path to throw error on open
|
48
|
+
path = recursive_search || path
|
37
49
|
end
|
38
50
|
open (path) {|f| schema = JSON.parse(f.read) }
|
39
51
|
end
|
data/lib/schema_tools/schema.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
|
+
module SchemaTools
|
1
2
|
|
3
|
+
class CircularReferenceException < ::Exception
|
4
|
+
def initialize fn, offending_ref, stack
|
5
|
+
@fn = fn
|
6
|
+
@stack = stack
|
7
|
+
@offending_ref = offending_ref
|
8
|
+
end
|
9
|
+
|
10
|
+
def to_s
|
11
|
+
"circular reference: #{@fn} $ref: #{@offending_ref} refers to itself:\n #{@stack.join("\n")}"
|
12
|
+
end
|
13
|
+
end
|
2
14
|
|
3
|
-
module SchemaTools
|
4
15
|
# Internal representation of a Schema. This is basically a wrapper around a
|
5
16
|
# HashWithIndifferentAccess ( for historical purposes ) as well as information
|
6
17
|
# concerning where the Schema was loaded from in order to resolve relative paths.
|
7
|
-
|
8
18
|
class Schema
|
9
19
|
#@param [String|Hash] name_or_hash Schema may be initialized with either a filename or a hash
|
10
20
|
def initialize(name_or_hash)
|
@@ -115,31 +125,47 @@ module SchemaTools
|
|
115
125
|
# "$ref" param and resolve it. Other params are checked for nested hashes
|
116
126
|
# and those are processed.
|
117
127
|
# @param [HashWithIndifferentAccess] schema - single schema
|
118
|
-
def resolve_refs schema = nil
|
128
|
+
def resolve_refs schema = nil, stack = []
|
119
129
|
schema ||= @hash
|
120
|
-
|
121
|
-
def resolve_reference hash
|
122
|
-
json_pointer = hash["$ref"]
|
123
|
-
values_from_pointer = RefResolver.load_json_pointer json_pointer, self
|
124
|
-
hash.merge!(values_from_pointer) { |key, old, new| old }
|
125
|
-
hash.delete("$ref")
|
126
|
-
end
|
127
|
-
|
128
130
|
keys = schema.keys # in case you are wondering: RuntimeError: can't add a new key into hash during iteration
|
129
131
|
keys.each do |k|
|
130
132
|
v = schema[k]
|
131
133
|
if k == "$ref"
|
132
|
-
resolve_reference schema
|
133
|
-
|
134
|
-
|
134
|
+
resolve_reference schema, stack
|
135
|
+
#stack.clear # ref resolved, reset stack
|
136
|
+
elsif v.is_a?(::Hash) || v.is_a?(ActiveSupport::HashWithIndifferentAccess)
|
137
|
+
resolve_refs v, stack
|
135
138
|
elsif v.is_a?(Array)
|
136
|
-
v.each do |
|
137
|
-
|
139
|
+
v.each do |element|
|
140
|
+
case element
|
141
|
+
when ::Hash, ActiveSupport::HashWithIndifferentAccess, ::Array
|
142
|
+
resolve_refs element, stack
|
143
|
+
end
|
138
144
|
end
|
139
145
|
end
|
140
146
|
end
|
147
|
+
schema
|
148
|
+
end
|
141
149
|
|
150
|
+
#
|
151
|
+
# @param [Hash] hash schema
|
152
|
+
def resolve_reference(hash, stack=[])
|
153
|
+
json_pointer = hash["$ref"]
|
154
|
+
if stack.include? json_pointer
|
155
|
+
# we should probably also have a "too many levels of $ref exception or something ..."
|
156
|
+
raise CircularReferenceException.new( absolute_filename, json_pointer, stack )
|
157
|
+
else
|
158
|
+
stack.push json_pointer
|
159
|
+
end
|
160
|
+
values_from_pointer = RefResolver.load_json_pointer(json_pointer, self)
|
161
|
+
# recurse to resolve possible refs in object properties
|
162
|
+
resolve_refs(values_from_pointer, stack)
|
163
|
+
|
164
|
+
hash.merge!(values_from_pointer) { |key, old, new| old }
|
165
|
+
hash.delete("$ref")
|
166
|
+
stack.pop
|
142
167
|
end
|
168
|
+
|
143
169
|
end
|
144
170
|
end
|
145
171
|
|
data/lib/schema_tools/version.rb
CHANGED
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"type" : "object",
|
3
|
+
"one": {
|
4
|
+
"$ref":"./circular_references_multi.json#two"
|
5
|
+
},
|
6
|
+
"two": {
|
7
|
+
"$ref":"./circular_references_multi.json#three"
|
8
|
+
},
|
9
|
+
"three" : {
|
10
|
+
"something_else" : {
|
11
|
+
"$ref": "./circular_references_multi.json#one"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"type" : "object",
|
3
|
+
"one": {
|
4
|
+
"$ref":"./circular_references_multi_file_two.json#one"
|
5
|
+
},
|
6
|
+
"two": {
|
7
|
+
"$ref":"./circular_references_multi_file_two.json#two"
|
8
|
+
},
|
9
|
+
"three" : {
|
10
|
+
"something_else" : {
|
11
|
+
"$ref": "./circular_references_multi_file_two.json#three"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,14 @@
|
|
1
|
+
{
|
2
|
+
"type" : "object",
|
3
|
+
"one": {
|
4
|
+
"$ref":"./circular_references_multi_file_one.json#two"
|
5
|
+
},
|
6
|
+
"two": {
|
7
|
+
"$ref":"./circular_references_multi_file_one.json#three"
|
8
|
+
},
|
9
|
+
"three" : {
|
10
|
+
"something_else" : {
|
11
|
+
"$ref": "./circular_references_multi_file_one.json#one"
|
12
|
+
}
|
13
|
+
}
|
14
|
+
}
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe SchemaTools::Reader do
|
4
|
+
BROKEN_SCHEMA_PATH = File.expand_path('../../fixtures_broken', __FILE__)
|
5
|
+
context 'circular references' do
|
6
|
+
it 'should raise exception for circular $refs' do
|
7
|
+
expect{
|
8
|
+
schema = SchemaTools::Schema.new("#{BROKEN_SCHEMA_PATH}/circular_references.json")
|
9
|
+
}.to raise_exception(SchemaTools::CircularReferenceException)
|
10
|
+
end
|
11
|
+
it 'should raise exception for more complex circular $refs' do
|
12
|
+
expect{
|
13
|
+
schema = SchemaTools::Schema.new("#{BROKEN_SCHEMA_PATH}/circular_references_multi.json")
|
14
|
+
}.to raise_exception(SchemaTools::CircularReferenceException)
|
15
|
+
end
|
16
|
+
it 'should raise exception for way multi file circular $refs' do
|
17
|
+
expect {
|
18
|
+
schema = SchemaTools::Schema.new("#{BROKEN_SCHEMA_PATH}/circular_references_multi_file_one.json")
|
19
|
+
}.to raise_exception
|
20
|
+
end
|
21
|
+
it 'should not raise exception if same $ref is used twice in one file' do
|
22
|
+
expect {
|
23
|
+
SchemaTools::Reader.read(:circular_references_twice)
|
24
|
+
}.to_not raise_exception
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json_schema_tools
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Georg Leciejewski
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2014-10-
|
11
|
+
date: 2014-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: json
|
@@ -98,6 +98,7 @@ files:
|
|
98
98
|
- lib/schema_tools/version.rb
|
99
99
|
- spec/fixtures/address.json
|
100
100
|
- spec/fixtures/basic_definitions.json
|
101
|
+
- spec/fixtures/circular_references_twice.json
|
101
102
|
- spec/fixtures/client.json
|
102
103
|
- spec/fixtures/contact.json
|
103
104
|
- spec/fixtures/includes_basic_definitions.json
|
@@ -107,6 +108,11 @@ files:
|
|
107
108
|
- spec/fixtures/one_of_definition.json
|
108
109
|
- spec/fixtures/page.json
|
109
110
|
- spec/fixtures/relative_paths/includes_relative_path.json
|
111
|
+
- spec/fixtures_broken/circular_references.json
|
112
|
+
- spec/fixtures_broken/circular_references_multi.json
|
113
|
+
- spec/fixtures_broken/circular_references_multi_file_one.json
|
114
|
+
- spec/fixtures_broken/circular_references_multi_file_two.json
|
115
|
+
- spec/schema_tools/circuluar_ref_spec.rb
|
110
116
|
- spec/schema_tools/cleaner_spec.rb
|
111
117
|
- spec/schema_tools/hash_spec.rb
|
112
118
|
- spec/schema_tools/klass_factory_spec.rb
|