json-schema 0.9.0 → 0.9.1
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
CHANGED
data/lib/json-schema.rb
CHANGED
@@ -5,5 +5,4 @@ require 'schema'
|
|
5
5
|
require 'validator'
|
6
6
|
Dir[File.join(File.dirname(__FILE__), "json-schema/attributes/*")].each {|file| require file }
|
7
7
|
Dir[File.join(File.dirname(__FILE__), "json-schema/validators/*")].each {|file| require file }
|
8
|
-
require 'uri/file'
|
9
|
-
require 'uri/uuid'
|
8
|
+
require 'uri/file'
|
@@ -3,8 +3,7 @@ module JSON
|
|
3
3
|
class MaximumInclusiveAttribute < Attribute
|
4
4
|
def self.validate(current_schema, data, fragments, validator, options = {})
|
5
5
|
if data.is_a?(Numeric)
|
6
|
-
current_schema.schema['maximumCanEqual']
|
7
|
-
if (current_schema.schema['maximumCanEqual'] ? data > current_schema.schema['maximum'] : data >= current_schema.schema['maximum'])
|
6
|
+
if (current_schema.schema['maximumCanEqual'] == false ? data >= current_schema.schema['maximum'] : data > current_schema.schema['maximum'])
|
8
7
|
message = "The property '#{build_fragment(fragments)}' did not have a maximum value of #{current_schema.schema['maximum']}, "
|
9
8
|
message += current_schema.schema['exclusiveMaximum'] ? 'exclusively' : 'inclusively'
|
10
9
|
raise ValidationError.new(message, fragments, current_schema)
|
@@ -13,4 +12,4 @@ module JSON
|
|
13
12
|
end
|
14
13
|
end
|
15
14
|
end
|
16
|
-
end
|
15
|
+
end
|
@@ -3,8 +3,7 @@ module JSON
|
|
3
3
|
class MinimumInclusiveAttribute < Attribute
|
4
4
|
def self.validate(current_schema, data, fragments, validator, options = {})
|
5
5
|
if data.is_a?(Numeric)
|
6
|
-
current_schema.schema['minimumCanEqual']
|
7
|
-
if (current_schema.schema['minimumCanEqual'] ? data < current_schema.schema['minimum'] : data <= current_schema.schema['minimum'])
|
6
|
+
if (current_schema.schema['minimumCanEqual'] == false ? data <= current_schema.schema['minimum'] : data < current_schema.schema['minimum'])
|
8
7
|
message = "The property '#{build_fragment(fragments)}' did not have a minimum value of #{current_schema.schema['minimum']}, "
|
9
8
|
message += current_schema.schema['exclusiveMinimum'] ? 'exclusively' : 'inclusively'
|
10
9
|
raise ValidationError.new(message, fragments, current_schema)
|
@@ -57,7 +57,7 @@ module JSON
|
|
57
57
|
|
58
58
|
def validate(current_schema, data, fragments)
|
59
59
|
current_schema.schema.each do |attr_name,attribute|
|
60
|
-
|
60
|
+
|
61
61
|
if @attributes.has_key?(attr_name.to_s)
|
62
62
|
@attributes[attr_name.to_s].validate(current_schema, data, fragments, self)
|
63
63
|
end
|
@@ -83,7 +83,7 @@ module JSON
|
|
83
83
|
|
84
84
|
def initialize(schema_data, data, opts={})
|
85
85
|
@options = @@default_opts.clone.merge(opts)
|
86
|
-
|
86
|
+
|
87
87
|
# I'm not a fan of this, but it's quick and dirty to get it working for now
|
88
88
|
if @options[:version]
|
89
89
|
@options[:version] = case @options[:version].to_s
|
@@ -302,12 +302,24 @@ module JSON
|
|
302
302
|
|
303
303
|
|
304
304
|
private
|
305
|
-
|
305
|
+
|
306
|
+
if Gem.available?('uuidtools')
|
307
|
+
require 'uuidtools'
|
308
|
+
@@fake_uri_generator = lambda{|s| UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, s).to_s }
|
309
|
+
else
|
310
|
+
require 'uri/uuid'
|
311
|
+
@@fake_uri_generator = lambda{|s| UUID.create_v5(s,UUID::Nil).to_s }
|
312
|
+
end
|
313
|
+
|
314
|
+
def fake_uri schema
|
315
|
+
@@fake_uri_generator.call(schema)
|
316
|
+
end
|
317
|
+
|
306
318
|
def initialize_schema(schema)
|
307
319
|
if schema.is_a?(String)
|
308
320
|
begin
|
309
321
|
# Build a fake URI for this
|
310
|
-
schema_uri = URI.parse(
|
322
|
+
schema_uri = URI.parse(fake_uri(schema))
|
311
323
|
schema = JSON::Validator.parse(schema)
|
312
324
|
if @options[:list]
|
313
325
|
schema = {"type" => "array", "items" => schema}
|
@@ -340,7 +352,7 @@ module JSON
|
|
340
352
|
if @options[:list]
|
341
353
|
schema = {"type" => "array", "items" => schema}
|
342
354
|
end
|
343
|
-
schema_uri = URI.parse(
|
355
|
+
schema_uri = URI.parse(fake_uri(schema.inspect))
|
344
356
|
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
345
357
|
Validator.add_schema(schema)
|
346
358
|
else
|
@@ -0,0 +1,391 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'pathname'
|
4
|
+
require 'bigdecimal'
|
5
|
+
require 'digest/sha1'
|
6
|
+
require 'date'
|
7
|
+
|
8
|
+
module JSON
|
9
|
+
|
10
|
+
class Schema
|
11
|
+
class ValidationError < Exception
|
12
|
+
attr_reader :fragments, :schema
|
13
|
+
|
14
|
+
def initialize(message, fragments, schema)
|
15
|
+
@fragments = fragments
|
16
|
+
@schema = schema
|
17
|
+
message = "#{message} in schema #{schema.uri}"
|
18
|
+
super(message)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class SchemaError < Exception
|
23
|
+
end
|
24
|
+
|
25
|
+
class JsonParseError < Exception
|
26
|
+
end
|
27
|
+
|
28
|
+
class Attribute
|
29
|
+
def self.validate(current_schema, data, fragments, validator, options = {})
|
30
|
+
end
|
31
|
+
|
32
|
+
def self.build_fragment(fragments)
|
33
|
+
"#/#{fragments.join('/')}"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
class Validator
|
38
|
+
attr_accessor :attributes, :uri
|
39
|
+
|
40
|
+
def initialize()
|
41
|
+
@attributes = {}
|
42
|
+
@uri = nil
|
43
|
+
end
|
44
|
+
|
45
|
+
def extend_schema_definition(schema_uri)
|
46
|
+
u = URI.parse(schema_uri)
|
47
|
+
validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
48
|
+
if validator.nil?
|
49
|
+
raise SchemaError.new("Schema not found: #{u.scheme}://#{u.host}#{u.path}")
|
50
|
+
end
|
51
|
+
@attributes.merge!(validator.attributes)
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_s
|
55
|
+
"#{@uri.scheme}://#{uri.host}#{uri.path}"
|
56
|
+
end
|
57
|
+
|
58
|
+
def validate(current_schema, data, fragments)
|
59
|
+
current_schema.schema.each do |attr_name,attribute|
|
60
|
+
|
61
|
+
if @attributes.has_key?(attr_name.to_s)
|
62
|
+
@attributes[attr_name.to_s].validate(current_schema, data, fragments, self)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
data
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
class Validator
|
72
|
+
|
73
|
+
@@schemas = {}
|
74
|
+
@@cache_schemas = false
|
75
|
+
@@default_opts = {
|
76
|
+
:list => false,
|
77
|
+
:version => nil
|
78
|
+
}
|
79
|
+
@@validators = {}
|
80
|
+
@@default_validator = nil
|
81
|
+
@@available_json_backends = []
|
82
|
+
@@json_backend = nil
|
83
|
+
|
84
|
+
def initialize(schema_data, data, opts={})
|
85
|
+
@options = @@default_opts.clone.merge(opts)
|
86
|
+
|
87
|
+
# I'm not a fan of this, but it's quick and dirty to get it working for now
|
88
|
+
if @options[:version]
|
89
|
+
@options[:version] = case @options[:version].to_s
|
90
|
+
when "draft3"
|
91
|
+
"draft-03"
|
92
|
+
when "draft2"
|
93
|
+
"draft-02"
|
94
|
+
when "draft1"
|
95
|
+
"draft-01"
|
96
|
+
else
|
97
|
+
raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported")
|
98
|
+
end
|
99
|
+
u = URI.parse("http://json-schema.org/#{@options[:version]}/schema#")
|
100
|
+
validator = JSON::Validator.validators["#{u.scheme}://#{u.host}#{u.path}"]
|
101
|
+
@options[:version] = validator
|
102
|
+
end
|
103
|
+
@base_schema = initialize_schema(schema_data)
|
104
|
+
@data = initialize_data(data)
|
105
|
+
build_schemas(@base_schema)
|
106
|
+
end
|
107
|
+
|
108
|
+
|
109
|
+
# Run a simple true/false validation of data against a schema
|
110
|
+
def validate()
|
111
|
+
begin
|
112
|
+
@base_schema.validate(@data,[])
|
113
|
+
Validator.clear_cache
|
114
|
+
rescue JSON::Schema::ValidationError
|
115
|
+
Validator.clear_cache
|
116
|
+
raise $!
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
def load_ref_schema(parent_schema,ref)
|
122
|
+
uri = URI.parse(ref)
|
123
|
+
if uri.relative?
|
124
|
+
uri = parent_schema.uri.clone
|
125
|
+
|
126
|
+
# Check for absolute path
|
127
|
+
path = ref.split("#")[0]
|
128
|
+
|
129
|
+
# This is a self reference and thus the schema does not need to be re-loaded
|
130
|
+
if path.nil? || path == ''
|
131
|
+
return
|
132
|
+
end
|
133
|
+
|
134
|
+
if path && path[0,1] == '/'
|
135
|
+
uri.path = Pathname.new(path).cleanpath.to_s
|
136
|
+
else
|
137
|
+
uri.path = (Pathname.new(parent_schema.uri.path).parent + path).cleanpath.to_s
|
138
|
+
end
|
139
|
+
uri.fragment = nil
|
140
|
+
end
|
141
|
+
|
142
|
+
if Validator.schemas[uri.to_s].nil?
|
143
|
+
begin
|
144
|
+
schema = JSON::Schema.new(JSON::Validator.parse(open(uri.to_s).read), uri, @options[:version])
|
145
|
+
Validator.add_schema(schema)
|
146
|
+
build_schemas(schema)
|
147
|
+
rescue JSON::ParserError
|
148
|
+
# Don't rescue this error, we want JSON formatting issues to bubble up
|
149
|
+
raise $!
|
150
|
+
rescue Exception
|
151
|
+
# Failures will occur when this URI cannot be referenced yet. Don't worry about it,
|
152
|
+
# the proper error will fall out if the ref isn't ever defined
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
|
157
|
+
|
158
|
+
# Build all schemas with IDs, mapping out the namespace
|
159
|
+
def build_schemas(parent_schema)
|
160
|
+
# Check for schemas in union types
|
161
|
+
["type", "disallow"].each do |key|
|
162
|
+
if parent_schema.schema[key] && parent_schema.schema[key].is_a?(Array)
|
163
|
+
parent_schema.schema[key].each_with_index do |type,i|
|
164
|
+
if type.is_a?(Hash)
|
165
|
+
handle_schema(parent_schema, type)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
# All properties are schemas
|
172
|
+
if parent_schema.schema["properties"]
|
173
|
+
parent_schema.schema["properties"].each do |k,v|
|
174
|
+
handle_schema(parent_schema, v)
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
# Items are always schemas
|
179
|
+
if parent_schema.schema["items"]
|
180
|
+
items = parent_schema.schema["items"].clone
|
181
|
+
single = false
|
182
|
+
if !items.is_a?(Array)
|
183
|
+
items = [items]
|
184
|
+
single = true
|
185
|
+
end
|
186
|
+
items.each_with_index do |item,i|
|
187
|
+
handle_schema(parent_schema, item)
|
188
|
+
end
|
189
|
+
end
|
190
|
+
|
191
|
+
# Each of these might be schemas
|
192
|
+
["additionalProperties", "additionalItems", "dependencies", "extends"].each do |key|
|
193
|
+
if parent_schema.schema[key].is_a?(Hash)
|
194
|
+
handle_schema(parent_schema, parent_schema.schema[key])
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
end
|
199
|
+
|
200
|
+
# Either load a reference schema or create a new schema
|
201
|
+
def handle_schema(parent_schema, obj)
|
202
|
+
if obj['$ref']
|
203
|
+
load_ref_schema(parent_schema, obj['$ref'])
|
204
|
+
else
|
205
|
+
schema_uri = parent_schema.uri.clone
|
206
|
+
schema = JSON::Schema.new(obj,schema_uri,@options[:version])
|
207
|
+
if obj['id']
|
208
|
+
Validator.add_schema(schema)
|
209
|
+
end
|
210
|
+
build_schemas(schema)
|
211
|
+
end
|
212
|
+
end
|
213
|
+
|
214
|
+
|
215
|
+
class << self
|
216
|
+
def validate(schema, data,opts={})
|
217
|
+
begin
|
218
|
+
validator = JSON::Validator.new(schema, data, opts)
|
219
|
+
validator.validate
|
220
|
+
return true
|
221
|
+
rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
|
222
|
+
return false
|
223
|
+
end
|
224
|
+
end
|
225
|
+
|
226
|
+
def validate!(schema, data,opts={})
|
227
|
+
validator = JSON::Validator.new(schema, data, opts)
|
228
|
+
validator.validate
|
229
|
+
end
|
230
|
+
alias_method 'validate2', 'validate!'
|
231
|
+
|
232
|
+
def clear_cache
|
233
|
+
@@schemas = {} if @@cache_schemas == false
|
234
|
+
end
|
235
|
+
|
236
|
+
def schemas
|
237
|
+
@@schemas
|
238
|
+
end
|
239
|
+
|
240
|
+
def add_schema(schema)
|
241
|
+
@@schemas[schema.uri.to_s] = schema if @@schemas[schema.uri.to_s].nil?
|
242
|
+
end
|
243
|
+
|
244
|
+
def cache_schemas=(val)
|
245
|
+
@@cache_schemas = val == true ? true : false
|
246
|
+
end
|
247
|
+
|
248
|
+
def validators
|
249
|
+
@@validators
|
250
|
+
end
|
251
|
+
|
252
|
+
def default_validator
|
253
|
+
@@default_validator
|
254
|
+
end
|
255
|
+
|
256
|
+
def register_validator(v)
|
257
|
+
@@validators[v.to_s] = v
|
258
|
+
end
|
259
|
+
|
260
|
+
def register_default_validator(v)
|
261
|
+
@@default_validator = v
|
262
|
+
end
|
263
|
+
|
264
|
+
def json_backend
|
265
|
+
@@json_backend
|
266
|
+
end
|
267
|
+
|
268
|
+
def json_backend=(backend)
|
269
|
+
backend = backend.to_s
|
270
|
+
if @@available_json_backend.include?(backend)
|
271
|
+
@@json_backend = backend
|
272
|
+
else
|
273
|
+
raise JSON::Schema::JsonParseError.new("The JSON backend '#{backend}' could not be found.")
|
274
|
+
end
|
275
|
+
end
|
276
|
+
|
277
|
+
def parse(s)
|
278
|
+
case @@json_backend.to_s
|
279
|
+
when 'json'
|
280
|
+
JSON.parse(s)
|
281
|
+
when 'yajl'
|
282
|
+
json = StringIO.new(s)
|
283
|
+
parser = Yajl::Parser.new
|
284
|
+
parser.parse(json)
|
285
|
+
else
|
286
|
+
raise JSON::Schema::JsonParseError.new("No supported JSON parsers found. The following parsers are suported:\n * yajl-ruby\n * json")
|
287
|
+
end
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
if Gem.available?('json')
|
292
|
+
require 'json'
|
293
|
+
@@available_json_backends << 'json'
|
294
|
+
@@json_backend = 'json'
|
295
|
+
end
|
296
|
+
|
297
|
+
if Gem.available?('yajl-ruby')
|
298
|
+
require 'yajl'
|
299
|
+
@@available_json_backends << 'yajl'
|
300
|
+
@@json_backend = 'yajl'
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
private
|
305
|
+
<<<<<<< HEAD
|
306
|
+
|
307
|
+
=======
|
308
|
+
|
309
|
+
if Gem.available?('uuidtools')
|
310
|
+
require 'uuidtools'
|
311
|
+
@@fake_uri_generator = lambda{|s| UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, s).to_s }
|
312
|
+
else
|
313
|
+
require 'uri/uuid'
|
314
|
+
@@fake_uri_generator = lambda{|s| UUID.create_v5(s,UUID::Nil).to_s }
|
315
|
+
end
|
316
|
+
|
317
|
+
def fake_uri schema
|
318
|
+
@@fake_uri_generator.call(schema)
|
319
|
+
end
|
320
|
+
|
321
|
+
>>>>>>> bcd72ee... added optional dependency on uuidtools gem, to resolve UUID constant overload warning
|
322
|
+
def initialize_schema(schema)
|
323
|
+
if schema.is_a?(String)
|
324
|
+
begin
|
325
|
+
# Build a fake URI for this
|
326
|
+
schema_uri = URI.parse(fake_uri(schema))
|
327
|
+
schema = JSON::Validator.parse(schema)
|
328
|
+
if @options[:list]
|
329
|
+
schema = {"type" => "array", "items" => schema}
|
330
|
+
end
|
331
|
+
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
332
|
+
Validator.add_schema(schema)
|
333
|
+
rescue
|
334
|
+
# Build a uri for it
|
335
|
+
schema_uri = URI.parse(schema)
|
336
|
+
if schema_uri.relative?
|
337
|
+
# Check for absolute path
|
338
|
+
if schema[0,1] == '/'
|
339
|
+
schema_uri = URI.parse("file://#{schema}")
|
340
|
+
else
|
341
|
+
schema_uri = URI.parse("file://#{Dir.pwd}/#{schema}")
|
342
|
+
end
|
343
|
+
end
|
344
|
+
if Validator.schemas[schema_uri.to_s].nil?
|
345
|
+
schema = JSON::Validator.parse(open(schema_uri.to_s).read)
|
346
|
+
if @options[:list]
|
347
|
+
schema = {"type" => "array", "items" => schema}
|
348
|
+
end
|
349
|
+
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
350
|
+
Validator.add_schema(schema)
|
351
|
+
else
|
352
|
+
schema = Validator.schemas[schema_uri.to_s]
|
353
|
+
end
|
354
|
+
end
|
355
|
+
elsif schema.is_a?(Hash)
|
356
|
+
if @options[:list]
|
357
|
+
schema = {"type" => "array", "items" => schema}
|
358
|
+
end
|
359
|
+
schema_uri = URI.parse(fake_uri(schema.inspect))
|
360
|
+
schema = JSON::Schema.new(schema,schema_uri,@options[:version])
|
361
|
+
Validator.add_schema(schema)
|
362
|
+
else
|
363
|
+
raise "Invalid schema - must be either a string or a hash"
|
364
|
+
end
|
365
|
+
|
366
|
+
schema
|
367
|
+
end
|
368
|
+
|
369
|
+
|
370
|
+
def initialize_data(data)
|
371
|
+
# Parse the data, if any
|
372
|
+
if data.is_a?(String)
|
373
|
+
begin
|
374
|
+
data = JSON::Validator.parse(data)
|
375
|
+
rescue
|
376
|
+
json_uri = URI.parse(data)
|
377
|
+
if json_uri.relative?
|
378
|
+
if data[0,1] == '/'
|
379
|
+
schema_uri = URI.parse("file://#{data}")
|
380
|
+
else
|
381
|
+
schema_uri = URI.parse("file://#{Dir.pwd}/#{data}")
|
382
|
+
end
|
383
|
+
end
|
384
|
+
data = JSON::Validator.parse(open(json_uri.to_s).read)
|
385
|
+
end
|
386
|
+
end
|
387
|
+
data
|
388
|
+
end
|
389
|
+
|
390
|
+
end
|
391
|
+
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: json-schema
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 57
|
5
5
|
prerelease: false
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
9
|
+
- 1
|
10
|
+
version: 0.9.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Kenny Hoxworth
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-03-
|
18
|
+
date: 2011-03-21 00:00:00 -04:00
|
19
19
|
default_executable:
|
20
20
|
dependencies: []
|
21
21
|
|
@@ -57,6 +57,7 @@ files:
|
|
57
57
|
- lib/json-schema/uri/file.rb
|
58
58
|
- lib/json-schema/uri/uuid.rb
|
59
59
|
- lib/json-schema/validator.rb
|
60
|
+
- lib/json-schema/validator.rb.orig
|
60
61
|
- lib/json-schema/validators/draft1.rb
|
61
62
|
- lib/json-schema/validators/draft2.rb
|
62
63
|
- lib/json-schema/validators/draft3.rb
|