json-schema 0.1.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.
- data/README.textile +89 -0
- data/lib/json-schema.rb +5 -0
- data/lib/json-schema/schema.rb +39 -0
- data/lib/json-schema/uri/file.rb +32 -0
- data/lib/json-schema/validator.rb +480 -0
- data/test/test_jsonschema.rb +569 -0
- metadata +85 -0
data/README.textile
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
h1. Ruby JSON Schema Validator
|
2
|
+
|
3
|
+
This library is intended to provide Ruby with an interface for validating JSON objects against a JSON schema conforming to [[JSON Schema Draft 3|http://tools.ietf.org/html/draft-zyp-json-schema-03]]. The project originally started as a fork of [[Constellation's ruby-jsonschema|https://github.com/Constellation/ruby-jsonchema]] project, but differences in the JSON schema draft versions implemented as well as assumptions made by the ruby-jsonschema library forced this to become a new project.
|
4
|
+
|
5
|
+
This project is far from complete but is in a somewhat usable state...
|
6
|
+
|
7
|
+
h2. Usage
|
8
|
+
|
9
|
+
If downloading the git repo, build the gem and install it:
|
10
|
+
|
11
|
+
<pre>
|
12
|
+
$ rake package
|
13
|
+
$ gem install pkg/json-schema-0.1.0.gem
|
14
|
+
</pre>
|
15
|
+
|
16
|
+
<pre>
|
17
|
+
require 'rubygems'
|
18
|
+
require 'json-schema'
|
19
|
+
|
20
|
+
JSON::Validator.validate('schema.json', 'data.json')
|
21
|
+
|
22
|
+
schema = {
|
23
|
+
"properties" => {
|
24
|
+
"a" => {"type" => "integer"}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
|
28
|
+
data = {
|
29
|
+
"a" => 5
|
30
|
+
}
|
31
|
+
|
32
|
+
JSON::Validator.validate(schema, data)
|
33
|
+
</pre>
|
34
|
+
|
35
|
+
|
36
|
+
h2. Currently implemented
|
37
|
+
|
38
|
+
The following core schema definitions are currently implemented:
|
39
|
+
|
40
|
+
* type
|
41
|
+
* properties
|
42
|
+
* patternProperties
|
43
|
+
* additionalProperties
|
44
|
+
* items
|
45
|
+
* additionalItems
|
46
|
+
* required
|
47
|
+
* dependencies
|
48
|
+
* minimum
|
49
|
+
* maximum
|
50
|
+
* exclusiveMinimum
|
51
|
+
* exclusiveMaximum
|
52
|
+
* minItems
|
53
|
+
* maxItems
|
54
|
+
* uniqueItems
|
55
|
+
* pattern
|
56
|
+
* minLength
|
57
|
+
* maxLength
|
58
|
+
* enum
|
59
|
+
* title
|
60
|
+
* description
|
61
|
+
* divisibleBy
|
62
|
+
* disallow
|
63
|
+
* extends
|
64
|
+
* id
|
65
|
+
* $ref (this implementation only follows slash-delimited fragment resolution)
|
66
|
+
|
67
|
+
|
68
|
+
h2. Not implemented
|
69
|
+
|
70
|
+
The following core schema definitions are not implemented:
|
71
|
+
|
72
|
+
* default - This library aims to solely be a validator and does not modify an object it is validating.
|
73
|
+
* $schema - Support for this will come later, possibly with the ability to validate against other JSON Schema draft versions
|
74
|
+
|
75
|
+
In addition, the following hyper schema attributes are not implemented at this time:
|
76
|
+
|
77
|
+
* links (not much to do with validation...)
|
78
|
+
* fragmentResolution (only handles default slash-delimited)
|
79
|
+
* readonly
|
80
|
+
* contentEncoding
|
81
|
+
* pathStart
|
82
|
+
* mediaType
|
83
|
+
|
84
|
+
|
85
|
+
h2. To Do
|
86
|
+
|
87
|
+
* Massive re-factoring - the whole validation process needs to be broken down into something a bit more manageable
|
88
|
+
* (Much) More testing
|
89
|
+
* Better interface to validator to allow for error messages in validation to propogate
|
data/lib/json-schema.rb
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'json'
|
3
|
+
require 'pathname'
|
4
|
+
|
5
|
+
module JSON
|
6
|
+
class Schema
|
7
|
+
|
8
|
+
attr_accessor :schema, :uri
|
9
|
+
|
10
|
+
def initialize(schema,uri)
|
11
|
+
@schema = schema
|
12
|
+
@uri = uri
|
13
|
+
|
14
|
+
# If there is an ID on this schema, use it to generate the URI
|
15
|
+
if @schema['id']
|
16
|
+
temp_uri = URI.parse(@schema['id'])
|
17
|
+
if temp_uri.relative?
|
18
|
+
uri.path = (Pathname.new(uri.path).parent + @schema['id']).cleanpath
|
19
|
+
temp_uri = uri
|
20
|
+
end
|
21
|
+
@uri = temp_uri
|
22
|
+
end
|
23
|
+
@uri.fragment = nil
|
24
|
+
end
|
25
|
+
|
26
|
+
def base_uri
|
27
|
+
parts = @uri.to_s.split('/')
|
28
|
+
parts.pop
|
29
|
+
parts.join('/') + '/'
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
@schema.to_json
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module URI
|
4
|
+
|
5
|
+
# Ruby does not have built-in support for filesystem URIs, and definitely does not have built-in support for
|
6
|
+
# using open-uri with filesystem URIs
|
7
|
+
class File < Generic
|
8
|
+
|
9
|
+
COMPONENT = [
|
10
|
+
:scheme,
|
11
|
+
:path,
|
12
|
+
:fragment,
|
13
|
+
:host
|
14
|
+
].freeze
|
15
|
+
|
16
|
+
def initialize(*arg)
|
17
|
+
arg[2] = ""
|
18
|
+
super(*arg)
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.build(args)
|
22
|
+
tmp = Util::make_components_hash(self, args)
|
23
|
+
return super(tmp)
|
24
|
+
end
|
25
|
+
|
26
|
+
def open(*rest, &block)
|
27
|
+
::File.open(self.path, *rest, &block)
|
28
|
+
end
|
29
|
+
|
30
|
+
@@schemes['FILE'] = File
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,480 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'open-uri'
|
3
|
+
require 'pathname'
|
4
|
+
require 'bigdecimal'
|
5
|
+
|
6
|
+
module JSON
|
7
|
+
class Validator
|
8
|
+
|
9
|
+
def initialize(schema_data, data)
|
10
|
+
@schemas = {}
|
11
|
+
@base_schema = initialize_schema(schema_data)
|
12
|
+
@data = initialize_data(data)
|
13
|
+
@schemas[@base_schema.uri.to_s] = @base_schema
|
14
|
+
|
15
|
+
build_schemas(@base_schema)
|
16
|
+
end
|
17
|
+
|
18
|
+
|
19
|
+
def validate()
|
20
|
+
validate_schema(@base_schema, @data)
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
def validate_schema(current_schema, data)
|
25
|
+
valid = true # Actually doing true/false on validation. Return at any point if invalid
|
26
|
+
|
27
|
+
# Check the type
|
28
|
+
if current_schema.schema['type']
|
29
|
+
valid = validate_type(current_schema.schema['type'],data,current_schema)
|
30
|
+
end
|
31
|
+
return valid if !valid
|
32
|
+
if current_schema.schema['disallow']
|
33
|
+
valid = !validate_type(current_schema.schema['disallow'],data,current_schema)
|
34
|
+
end
|
35
|
+
return valid if !valid
|
36
|
+
|
37
|
+
# Check the values
|
38
|
+
if current_schema.schema['minimum'] && data.is_a?(Numeric)
|
39
|
+
valid = current_schema.schema['exclusiveMinimum'] ? data > current_schema.schema['minimum'] : data >= current_schema.schema['minimum']
|
40
|
+
end
|
41
|
+
return valid if !valid
|
42
|
+
|
43
|
+
if current_schema.schema['maximum'] && data.is_a?(Numeric)
|
44
|
+
valid = current_schema.schema['exclusiveMaximum'] ? data < current_schema.schema['maximum'] : data <= current_schema.schema['maximum']
|
45
|
+
end
|
46
|
+
return valid if !valid
|
47
|
+
|
48
|
+
if current_schema.schema['minItems'] && data.is_a?(Array)
|
49
|
+
valid = data.nitems >= current_schema.schema['minItems']
|
50
|
+
end
|
51
|
+
return valid if !valid
|
52
|
+
|
53
|
+
if current_schema.schema['maxItems'] && data.is_a?(Array)
|
54
|
+
valid = data.nitems <= current_schema.schema['maxItems']
|
55
|
+
end
|
56
|
+
return valid if !valid
|
57
|
+
|
58
|
+
if current_schema.schema['uniqueItems'] && data.is_a?(Array)
|
59
|
+
d = data.clone
|
60
|
+
dupes = d.uniq!
|
61
|
+
valid = dupes.nil?
|
62
|
+
end
|
63
|
+
return valid if !valid
|
64
|
+
|
65
|
+
if current_schema.schema['pattern'] && data.is_a?(String)
|
66
|
+
r = Regexp.new(current_schema.schema['pattern'])
|
67
|
+
valid = !(r.match(data)).nil?
|
68
|
+
end
|
69
|
+
return valid if !valid
|
70
|
+
|
71
|
+
if current_schema.schema['minLength'] && data.is_a?(String)
|
72
|
+
valid = data.length >= current_schema.schema['minLength']
|
73
|
+
end
|
74
|
+
return valid if !valid
|
75
|
+
|
76
|
+
if current_schema.schema['maxLength'] && data.is_a?(String)
|
77
|
+
valid = data.length <= current_schema.schema['maxLength']
|
78
|
+
end
|
79
|
+
return valid if !valid
|
80
|
+
|
81
|
+
if current_schema.schema['divisibleBy'] && data.is_a?(Numeric)
|
82
|
+
if current_schema.schema['divisibleBy'] == 0 || current_schema.schema['divisibleBy'] == 0.0
|
83
|
+
return false
|
84
|
+
else
|
85
|
+
valid = (BigDecimal.new(data.to_s) % BigDecimal.new(current_schema.schema['divisibleBy'].to_s)).to_f == 0
|
86
|
+
end
|
87
|
+
end
|
88
|
+
return valid if !valid
|
89
|
+
|
90
|
+
if current_schema.schema['enum']
|
91
|
+
valid = current_schema.schema['enum'].include?(data)
|
92
|
+
end
|
93
|
+
return valid if !valid
|
94
|
+
|
95
|
+
|
96
|
+
if current_schema.schema['properties'] && data.is_a?(Hash)
|
97
|
+
current_schema.schema['properties'].each do |property,property_schema|
|
98
|
+
valid = false if (property_schema['required'] && !data.has_key?(property))
|
99
|
+
|
100
|
+
if data.has_key?(property)
|
101
|
+
schema = JSON::Schema.new(property_schema,current_schema.uri)
|
102
|
+
valid = validate_schema(schema, data[property])
|
103
|
+
end
|
104
|
+
return valid if !valid
|
105
|
+
end
|
106
|
+
end
|
107
|
+
return valid if !valid
|
108
|
+
|
109
|
+
if current_schema.schema['patternProperties'] && data.is_a?(Hash)
|
110
|
+
current_schema.schema['properties'].each do |property,property_schema|
|
111
|
+
|
112
|
+
r = Regexp.new(property)
|
113
|
+
|
114
|
+
# Check each key in the data hash to see if it matches the regex
|
115
|
+
data.each do |key,value|
|
116
|
+
if r.match(key)
|
117
|
+
schema = JSON::Schema.new(property_schema,current_schema.uri)
|
118
|
+
valid = validate_schema(schema, data[key])
|
119
|
+
end
|
120
|
+
return valid if !valid
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
return valid if !valid
|
125
|
+
|
126
|
+
if current_schema.schema['additionalProperties'] && data.is_a?(Hash)
|
127
|
+
extra_properties = data.keys
|
128
|
+
|
129
|
+
if current_schema.schema['properties']
|
130
|
+
extra_properties = extra_properties - current_schema.schema['properties'].keys
|
131
|
+
end
|
132
|
+
|
133
|
+
if current_schema.schema['patternProperties']
|
134
|
+
current_schema.schema['patternProperties'].each_key do |key|
|
135
|
+
r = Regexp.new(key)
|
136
|
+
extras_clone = extra_properties.clone
|
137
|
+
extras_clone.each do |prop|
|
138
|
+
if r.match(prop)
|
139
|
+
extra_properties = extra_properties - [prop]
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
if current_schema.schema['additionalProperties'] == false
|
146
|
+
valid = extra_properties.empty?
|
147
|
+
elsif current_schema.schema['additionalProperties'].is_a?(Hash)
|
148
|
+
data.each do |key,value|
|
149
|
+
schema = JSON::Schema.new(current_schema.schema['additionalProperties'],current_schema.uri)
|
150
|
+
valid = validate_schema(schema,value)
|
151
|
+
return valid if !valid
|
152
|
+
end
|
153
|
+
end
|
154
|
+
end
|
155
|
+
return valid if !valid
|
156
|
+
|
157
|
+
if current_schema.schema['items'] && data.is_a?(Array)
|
158
|
+
if current_schema.schema['items'].is_a?(Hash)
|
159
|
+
data.each do |item|
|
160
|
+
schema = JSON::Schema.new(current_schema.schema['items'],current_schema.uri)
|
161
|
+
valid = validate_schema(schema,item)
|
162
|
+
return valid if !valid
|
163
|
+
end
|
164
|
+
elsif current_schema.schema['items'].is_a?(Array)
|
165
|
+
current_schema.schema['items'].each_with_index do |item_schema,i|
|
166
|
+
schema = JSON::Schema.new(item_schema,current_schema.uri)
|
167
|
+
valid = validate_schema(schema,data[i])
|
168
|
+
return valid if !valid
|
169
|
+
end
|
170
|
+
end
|
171
|
+
end
|
172
|
+
return valid if !valid
|
173
|
+
|
174
|
+
if current_schema.schema['additionalItems'] && data.is_a?(Array) && current_schema.schema['items'].is_a?(array)
|
175
|
+
if current_schema.schema['additionalItems'] == false
|
176
|
+
return current_schema.schema['additionalItems'].length == data.length
|
177
|
+
elsif current_schema.schema['additionaItems'].is_a?(Hash)
|
178
|
+
data.each do |item|
|
179
|
+
schema = JSON::Schema.new(current_schema.schema['additionalItems'],current_schema.uri)
|
180
|
+
valid = validate_schema(schema, item)
|
181
|
+
return valid if !valid
|
182
|
+
end
|
183
|
+
end
|
184
|
+
end
|
185
|
+
return valid if !valid
|
186
|
+
|
187
|
+
if current_schema.schema['dependences'] && data.is_a?(Hash)
|
188
|
+
current_schema.schema['dependencies'].each do |property,dependency_value|
|
189
|
+
if data.has_key?(property)
|
190
|
+
if dependency_value.is_a?(String)
|
191
|
+
valid = data.has_key?(dependency_value)
|
192
|
+
elsif dependency_value.is_a?(Array)
|
193
|
+
dependency_value.each do |value|
|
194
|
+
valid = data.has_key?(value)
|
195
|
+
break if !valid
|
196
|
+
end
|
197
|
+
else
|
198
|
+
schema = JSON::Schema.new(dependency_value,current_schema.uri)
|
199
|
+
valid = validate_schema(schema, data)
|
200
|
+
end
|
201
|
+
return valid if !valid
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|
205
|
+
return valid if !valid
|
206
|
+
|
207
|
+
# We're referencing another schema
|
208
|
+
if current_schema.schema['$ref']
|
209
|
+
temp_uri = URI.parse(current_schema.schema['$ref'])
|
210
|
+
if temp_uri.relative?
|
211
|
+
temp_uri = current_schema.uri.clone
|
212
|
+
temp_uri.path = (Pathname.new(current_schema.uri.path).parent + current_schema.schema['$ref'].split("#")[0]).cleanpath
|
213
|
+
temp_uri.fragment = current_schema.schema['$ref'].split("#")[1]
|
214
|
+
end
|
215
|
+
temp_uri.fragment = "" if temp_uri.fragment.nil?
|
216
|
+
|
217
|
+
# Grab the parent schema from the schema list
|
218
|
+
schema_key = temp_uri.to_s.split("#")[0]
|
219
|
+
ref_schema = @schemas[schema_key]
|
220
|
+
|
221
|
+
if ref_schema
|
222
|
+
# Perform fragment resolution to retrieve the appropriate level for the schema
|
223
|
+
target_schema = ref_schema.schema
|
224
|
+
fragments = temp_uri.fragment.split("/")
|
225
|
+
fragments.each do |fragment|
|
226
|
+
if fragment && fragment != ''
|
227
|
+
if target_schema.is_a?(Array)
|
228
|
+
target_schema = target_schema[fragment.to_i]
|
229
|
+
else
|
230
|
+
target_schema = target_schema[fragment]
|
231
|
+
end
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
# We have the schema finally, build it and validate!
|
236
|
+
schema = JSON::Schema.new(target_schema,temp_uri)
|
237
|
+
valid = validate_schema(schema, data)
|
238
|
+
end
|
239
|
+
end
|
240
|
+
|
241
|
+
if current_schema.schema['extends']
|
242
|
+
schemas = current_schema.schema['extends']
|
243
|
+
schemas = [schemas] if !schema.is_a?(Array)
|
244
|
+
schemas.each do |s|
|
245
|
+
schema = JSON::Schema.new(s,current_schema.uri)
|
246
|
+
valid = validate_schema(schema, item)
|
247
|
+
return valid if !valid
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
valid
|
252
|
+
end
|
253
|
+
|
254
|
+
|
255
|
+
def validate_type(types, data,current_schema)
|
256
|
+
union = true
|
257
|
+
if !types.is_a?(Array)
|
258
|
+
types = [types]
|
259
|
+
union = true
|
260
|
+
end
|
261
|
+
valid = false
|
262
|
+
|
263
|
+
types.each do |type|
|
264
|
+
if type.is_a?(String)
|
265
|
+
case type
|
266
|
+
when "string"
|
267
|
+
valid = data.is_a?(String)
|
268
|
+
when "number"
|
269
|
+
valid = data.is_a?(Numeric)
|
270
|
+
when "integer"
|
271
|
+
valid = data.is_a?(Integer)
|
272
|
+
when "boolean"
|
273
|
+
valid = (data.is_a?(TrueClass) || data.is_a?(FalseClass))
|
274
|
+
when "object"
|
275
|
+
valid = data.is_a?(Hash)
|
276
|
+
when "array"
|
277
|
+
valid = data.is_a?(Array)
|
278
|
+
when "null"
|
279
|
+
valid = data.is_a?(NilClass)
|
280
|
+
else
|
281
|
+
valid = true
|
282
|
+
end
|
283
|
+
elsif type.is_a?(Hash) && union
|
284
|
+
# Validate as a schema
|
285
|
+
schema = JSON::Schema.new(type,current_schema.uri)
|
286
|
+
valid = validate_schema(schema,data)
|
287
|
+
end
|
288
|
+
|
289
|
+
return valid if valid
|
290
|
+
end
|
291
|
+
|
292
|
+
valid
|
293
|
+
end
|
294
|
+
|
295
|
+
def load_ref_schema(parent_schema,ref)
|
296
|
+
uri = URI.parse(ref)
|
297
|
+
if uri.relative?
|
298
|
+
uri = parent_schema.uri.clone
|
299
|
+
uri.path = (Pathname.new(parent_schema.uri.path).parent + ref.split("#")[0]).cleanpath
|
300
|
+
uri.fragment = nil
|
301
|
+
end
|
302
|
+
|
303
|
+
if @schemas[uri.to_s].nil?
|
304
|
+
begin
|
305
|
+
schema = JSON::Schema.new(JSON.parse(open(uri.to_s).read), uri)
|
306
|
+
@schemas[uri.to_s] = schema
|
307
|
+
build_schemas(schema)
|
308
|
+
rescue
|
309
|
+
# Failures will occur when this URI cannot be referenced yet. Don't worry about it,
|
310
|
+
# the proper error will fall out if the ref isn't ever defined
|
311
|
+
end
|
312
|
+
end
|
313
|
+
end
|
314
|
+
|
315
|
+
|
316
|
+
# Build all schemas with IDs, mapping out the namespace
|
317
|
+
def build_schemas(parent_schema)
|
318
|
+
if parent_schema.schema["type"] && parent_schema.schema["type"].is_a?(Array) # If we're dealing with a Union type, there might be schemas a-brewin'
|
319
|
+
parent_schema.schema["type"].each_with_index do |type,i|
|
320
|
+
if type.is_a?(Hash)
|
321
|
+
if type['$ref']
|
322
|
+
load_ref_schema(parent_schema, type['$ref'])
|
323
|
+
else
|
324
|
+
schema_uri = parent_schema.uri.clone
|
325
|
+
schema = JSON::Schema.new(type,schema_uri)
|
326
|
+
if type['id']
|
327
|
+
@schemas[schema.uri.to_s] = schema
|
328
|
+
end
|
329
|
+
build_schemas(schema)
|
330
|
+
end
|
331
|
+
end
|
332
|
+
end
|
333
|
+
end
|
334
|
+
|
335
|
+
if parent_schema.schema["disallow"] && parent_schema.schema["disallow"].is_a?(Array) # If we're dealing with a Union type, there might be schemas a-brewin'
|
336
|
+
parent_schema.schema["disallow"].each_with_index do |type,i|
|
337
|
+
if type.is_a?(Hash)
|
338
|
+
if type['$ref']
|
339
|
+
load_ref_schema(parent_schema, type['$ref'])
|
340
|
+
else
|
341
|
+
type['id']
|
342
|
+
schema_uri = parent_schema.uri.clone
|
343
|
+
schema = JSON::Schema.new(type,schema_uri)
|
344
|
+
if type['id']
|
345
|
+
@schemas[schema.uri.to_s] = schema
|
346
|
+
end
|
347
|
+
build_schemas(schema)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
end
|
352
|
+
|
353
|
+
if parent_schema.schema["properties"]
|
354
|
+
parent_schema.schema["properties"].each do |k,v|
|
355
|
+
if v['$ref']
|
356
|
+
load_ref_schema(parent_schema, v['$ref'])
|
357
|
+
else
|
358
|
+
schema_uri = parent_schema.uri.clone
|
359
|
+
schema = JSON::Schema.new(v,schema_uri)
|
360
|
+
if v['id']
|
361
|
+
@schemas[schema.uri.to_s] = schema
|
362
|
+
end
|
363
|
+
build_schemas(schema)
|
364
|
+
end
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
if parent_schema.schema["additionalProperties"].is_a?(Hash)
|
369
|
+
if parent_schema.schema["additionalProperties"]["$ref"]
|
370
|
+
load_ref_schema(parent_schema, parent_schema.schema["additionalProperties"]["$ref"])
|
371
|
+
else
|
372
|
+
schema_uri = parent_schema.uri.clone
|
373
|
+
schema = JSON::Schema.new(parent_schema.schema["additionalProperties"],schema_uri)
|
374
|
+
if parent_schema.schema["additionalProperties"]['id']
|
375
|
+
@schemas[schema.uri.to_s] = schema
|
376
|
+
end
|
377
|
+
build_schemas(schema)
|
378
|
+
end
|
379
|
+
end
|
380
|
+
|
381
|
+
if parent_schema.schema["items"]
|
382
|
+
items = parent_schema.schema["items"].clone
|
383
|
+
single = false
|
384
|
+
if !items.is_a?(Array)
|
385
|
+
items = [items]
|
386
|
+
single = true
|
387
|
+
end
|
388
|
+
items.each_with_index do |item,i|
|
389
|
+
if item['$ref']
|
390
|
+
load_ref_schema(parent_schema, item['$ref'])
|
391
|
+
else
|
392
|
+
schema_uri = parent_schema.uri.clone
|
393
|
+
schema = JSON::Schema.new(item,schema_uri)
|
394
|
+
if item['id']
|
395
|
+
@schemas[schema.uri.to_s] = schema
|
396
|
+
end
|
397
|
+
build_schemas(schema)
|
398
|
+
end
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
if parent_schema.schema["additionalItems"].is_a?(Hash)
|
403
|
+
if parent_schema.schema["additionalItems"]['$ref']
|
404
|
+
load_ref_schema(parent_schema, parent_schema.schema["additionalItems"]['$ref'])
|
405
|
+
else
|
406
|
+
schema_uri = parent_schema.uri.clone
|
407
|
+
schema = JSON::Schema.new(parent_schema.schema["additionalItems"],schema_uri)
|
408
|
+
if parent_schema.schema["additionalItems"]['id']
|
409
|
+
@schemas[schema.uri.to_s] = schema
|
410
|
+
end
|
411
|
+
build_schemas(schema)
|
412
|
+
end
|
413
|
+
end
|
414
|
+
|
415
|
+
if parent_schema.schema["dependencies"].is_a?(Hash)
|
416
|
+
if parent_schema.schema["dependencies"]["$ref"]
|
417
|
+
load_ref_schema(parent_schema, parent_schema.schema["dependencies"]['$ref'])
|
418
|
+
else
|
419
|
+
schema_uri = parent_schema.uri.clone
|
420
|
+
schema = JSON::Schema.new(parent_schema.schema["dependencies"],schema_uri)
|
421
|
+
if parent_schema.schema["dependencies"]['id']
|
422
|
+
@schemas[schema.uri.to_s] = schema
|
423
|
+
end
|
424
|
+
build_schemas(schema)
|
425
|
+
end
|
426
|
+
end
|
427
|
+
end
|
428
|
+
|
429
|
+
|
430
|
+
class << self
|
431
|
+
def validate(schema, data)
|
432
|
+
validator = JSON::Validator.new(schema, data)
|
433
|
+
validator.validate
|
434
|
+
end
|
435
|
+
end
|
436
|
+
|
437
|
+
|
438
|
+
private
|
439
|
+
|
440
|
+
def initialize_schema(schema)
|
441
|
+
schema_uri = URI.parse("file://#{Dir.pwd}/__base_schema__.json")
|
442
|
+
if schema.is_a?(String)
|
443
|
+
begin
|
444
|
+
schema = JSON.parse(schema)
|
445
|
+
rescue
|
446
|
+
begin
|
447
|
+
# Build a uri for it
|
448
|
+
schema_uri = URI.parse(schema)
|
449
|
+
schema_uri = URI.parse("file://#{Dir.pwd}/#{schema}") if schema_uri.relative?
|
450
|
+
schema = JSON.parse(open(schema_uri.to_s).read)
|
451
|
+
rescue
|
452
|
+
raise "Invalid schema: #{schema_uri.to_s}"
|
453
|
+
end
|
454
|
+
end
|
455
|
+
end
|
456
|
+
|
457
|
+
JSON::Schema.new(schema,schema_uri)
|
458
|
+
end
|
459
|
+
|
460
|
+
|
461
|
+
def initialize_data(data)
|
462
|
+
# Parse the data, if any
|
463
|
+
if data.is_a?(String)
|
464
|
+
begin
|
465
|
+
data = JSON.parse(data)
|
466
|
+
rescue
|
467
|
+
begin
|
468
|
+
json_uri = URI.parse(data)
|
469
|
+
json_uri = URI.parse("file://#{Dir.pwd}/#{data}") if json_uri.relative?
|
470
|
+
data = JSON.parse(open(json_uri.to_s).read)
|
471
|
+
rescue
|
472
|
+
raise "Invalid JSON: #{json_uri.to_s}"
|
473
|
+
end
|
474
|
+
end
|
475
|
+
end
|
476
|
+
data
|
477
|
+
end
|
478
|
+
|
479
|
+
end
|
480
|
+
end
|
@@ -0,0 +1,569 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require File.dirname(__FILE__) + '/../lib/json-schema'
|
3
|
+
|
4
|
+
class JSONSchemaTest < Test::Unit::TestCase
|
5
|
+
def test_types
|
6
|
+
# Set up the default datatype
|
7
|
+
schema = {
|
8
|
+
"properties" => {
|
9
|
+
"a" => {}
|
10
|
+
}
|
11
|
+
}
|
12
|
+
data = {
|
13
|
+
"a" => nil
|
14
|
+
}
|
15
|
+
|
16
|
+
# Test integers
|
17
|
+
schema["properties"]["a"]["type"] = "integer"
|
18
|
+
data["a"] = 5
|
19
|
+
assert(JSON::Validator.validate(schema,data))
|
20
|
+
|
21
|
+
data["a"] = 5.2
|
22
|
+
assert(!JSON::Validator.validate(schema,data))
|
23
|
+
|
24
|
+
data['a'] = 'string'
|
25
|
+
assert(!JSON::Validator.validate(schema,data))
|
26
|
+
|
27
|
+
data['a'] = true
|
28
|
+
assert(!JSON::Validator.validate(schema,data))
|
29
|
+
|
30
|
+
|
31
|
+
# Test numbers
|
32
|
+
schema["properties"]["a"]["type"] = "number"
|
33
|
+
data["a"] = 5
|
34
|
+
assert(JSON::Validator.validate(schema,data))
|
35
|
+
|
36
|
+
data["a"] = 5.2
|
37
|
+
assert(JSON::Validator.validate(schema,data))
|
38
|
+
|
39
|
+
data['a'] = 'string'
|
40
|
+
assert(!JSON::Validator.validate(schema,data))
|
41
|
+
|
42
|
+
data['a'] = true
|
43
|
+
assert(!JSON::Validator.validate(schema,data))
|
44
|
+
|
45
|
+
|
46
|
+
# Test strings
|
47
|
+
schema["properties"]["a"]["type"] = "string"
|
48
|
+
data["a"] = 5
|
49
|
+
assert(!JSON::Validator.validate(schema,data))
|
50
|
+
|
51
|
+
data["a"] = 5.2
|
52
|
+
assert(!JSON::Validator.validate(schema,data))
|
53
|
+
|
54
|
+
data['a'] = 'string'
|
55
|
+
assert(JSON::Validator.validate(schema,data))
|
56
|
+
|
57
|
+
data['a'] = true
|
58
|
+
assert(!JSON::Validator.validate(schema,data))
|
59
|
+
|
60
|
+
|
61
|
+
# Test booleans
|
62
|
+
schema["properties"]["a"]["type"] = "boolean"
|
63
|
+
data["a"] = 5
|
64
|
+
assert(!JSON::Validator.validate(schema,data))
|
65
|
+
|
66
|
+
data["a"] = 5.2
|
67
|
+
assert(!JSON::Validator.validate(schema,data))
|
68
|
+
|
69
|
+
data['a'] = 'string'
|
70
|
+
assert(!JSON::Validator.validate(schema,data))
|
71
|
+
|
72
|
+
data['a'] = true
|
73
|
+
assert(JSON::Validator.validate(schema,data))
|
74
|
+
|
75
|
+
data['a'] = false
|
76
|
+
assert(JSON::Validator.validate(schema,data))
|
77
|
+
|
78
|
+
|
79
|
+
# Test object
|
80
|
+
schema["properties"]["a"]["type"] = "object"
|
81
|
+
data["a"] = {}
|
82
|
+
assert(JSON::Validator.validate(schema,data))
|
83
|
+
|
84
|
+
data["a"] = 5.2
|
85
|
+
assert(!JSON::Validator.validate(schema,data))
|
86
|
+
|
87
|
+
data['a'] = 'string'
|
88
|
+
assert(!JSON::Validator.validate(schema,data))
|
89
|
+
|
90
|
+
data['a'] = true
|
91
|
+
assert(!JSON::Validator.validate(schema,data))
|
92
|
+
|
93
|
+
|
94
|
+
# Test array
|
95
|
+
schema["properties"]["a"]["type"] = "array"
|
96
|
+
data["a"] = []
|
97
|
+
assert(JSON::Validator.validate(schema,data))
|
98
|
+
|
99
|
+
data["a"] = 5.2
|
100
|
+
assert(!JSON::Validator.validate(schema,data))
|
101
|
+
|
102
|
+
data['a'] = 'string'
|
103
|
+
assert(!JSON::Validator.validate(schema,data))
|
104
|
+
|
105
|
+
data['a'] = true
|
106
|
+
assert(!JSON::Validator.validate(schema,data))
|
107
|
+
|
108
|
+
|
109
|
+
# Test null
|
110
|
+
schema["properties"]["a"]["type"] = "null"
|
111
|
+
data["a"] = nil
|
112
|
+
assert(JSON::Validator.validate(schema,data))
|
113
|
+
|
114
|
+
data["a"] = 5.2
|
115
|
+
assert(!JSON::Validator.validate(schema,data))
|
116
|
+
|
117
|
+
data['a'] = 'string'
|
118
|
+
assert(!JSON::Validator.validate(schema,data))
|
119
|
+
|
120
|
+
data['a'] = true
|
121
|
+
assert(!JSON::Validator.validate(schema,data))
|
122
|
+
|
123
|
+
|
124
|
+
# Test any
|
125
|
+
schema["properties"]["a"]["type"] = "any"
|
126
|
+
data["a"] = 5
|
127
|
+
assert(JSON::Validator.validate(schema,data))
|
128
|
+
|
129
|
+
data["a"] = 5.2
|
130
|
+
assert(JSON::Validator.validate(schema,data))
|
131
|
+
|
132
|
+
data['a'] = 'string'
|
133
|
+
assert(JSON::Validator.validate(schema,data))
|
134
|
+
|
135
|
+
data['a'] = true
|
136
|
+
assert(JSON::Validator.validate(schema,data))
|
137
|
+
|
138
|
+
|
139
|
+
# Test a union type
|
140
|
+
schema["properties"]["a"]["type"] = ["integer","string"]
|
141
|
+
data["a"] = 5
|
142
|
+
assert(JSON::Validator.validate(schema,data))
|
143
|
+
|
144
|
+
data["a"] = 'boo'
|
145
|
+
assert(JSON::Validator.validate(schema,data))
|
146
|
+
|
147
|
+
data["a"] = false
|
148
|
+
assert(!JSON::Validator.validate(schema,data))
|
149
|
+
end
|
150
|
+
|
151
|
+
|
152
|
+
|
153
|
+
def test_required
|
154
|
+
# Set up the default datatype
|
155
|
+
schema = {
|
156
|
+
"properties" => {
|
157
|
+
"a" => {"required" => true}
|
158
|
+
}
|
159
|
+
}
|
160
|
+
data = {
|
161
|
+
}
|
162
|
+
|
163
|
+
assert(!JSON::Validator.validate(schema,data))
|
164
|
+
data['a'] = "Hello"
|
165
|
+
assert(JSON::Validator.validate(schema,data))
|
166
|
+
end
|
167
|
+
|
168
|
+
|
169
|
+
|
170
|
+
def test_minimum
|
171
|
+
# Set up the default datatype
|
172
|
+
schema = {
|
173
|
+
"properties" => {
|
174
|
+
"a" => {"minimum" => 5}
|
175
|
+
}
|
176
|
+
}
|
177
|
+
|
178
|
+
data = {
|
179
|
+
"a" => nil
|
180
|
+
}
|
181
|
+
|
182
|
+
|
183
|
+
# Test an integer
|
184
|
+
data["a"] = 5
|
185
|
+
assert(JSON::Validator.validate(schema,data))
|
186
|
+
|
187
|
+
data["a"] = 4
|
188
|
+
assert(!JSON::Validator.validate(schema,data))
|
189
|
+
|
190
|
+
# Test a float
|
191
|
+
data["a"] = 5.0
|
192
|
+
assert(JSON::Validator.validate(schema,data))
|
193
|
+
|
194
|
+
data["a"] = 4.9
|
195
|
+
assert(!JSON::Validator.validate(schema,data))
|
196
|
+
|
197
|
+
# Test a non-number
|
198
|
+
data["a"] = "a string"
|
199
|
+
assert(JSON::Validator.validate(schema,data))
|
200
|
+
|
201
|
+
# Test exclusiveMinimum
|
202
|
+
schema["properties"]["a"]["exclusiveMinimum"] = true
|
203
|
+
|
204
|
+
data["a"] = 6
|
205
|
+
assert(JSON::Validator.validate(schema,data))
|
206
|
+
|
207
|
+
data["a"] = 5
|
208
|
+
assert(!JSON::Validator.validate(schema,data))
|
209
|
+
|
210
|
+
# Test with float
|
211
|
+
data["a"] = 5.00000001
|
212
|
+
assert(JSON::Validator.validate(schema,data))
|
213
|
+
|
214
|
+
data["a"] = 5.0
|
215
|
+
assert(!JSON::Validator.validate(schema,data))
|
216
|
+
end
|
217
|
+
|
218
|
+
|
219
|
+
|
220
|
+
def test_maximum
|
221
|
+
# Set up the default datatype
|
222
|
+
schema = {
|
223
|
+
"properties" => {
|
224
|
+
"a" => {"maximum" => 5}
|
225
|
+
}
|
226
|
+
}
|
227
|
+
|
228
|
+
data = {
|
229
|
+
"a" => nil
|
230
|
+
}
|
231
|
+
|
232
|
+
|
233
|
+
# Test an integer
|
234
|
+
data["a"] = 5
|
235
|
+
assert(JSON::Validator.validate(schema,data))
|
236
|
+
|
237
|
+
data["a"] = 6
|
238
|
+
assert(!JSON::Validator.validate(schema,data))
|
239
|
+
|
240
|
+
# Test a float
|
241
|
+
data["a"] = 5.0
|
242
|
+
assert(JSON::Validator.validate(schema,data))
|
243
|
+
|
244
|
+
data["a"] = 5.1
|
245
|
+
assert(!JSON::Validator.validate(schema,data))
|
246
|
+
|
247
|
+
# Test a non-number
|
248
|
+
data["a"] = "a string"
|
249
|
+
assert(JSON::Validator.validate(schema,data))
|
250
|
+
|
251
|
+
# Test exclusiveMinimum
|
252
|
+
schema["properties"]["a"]["exclusiveMaximum"] = true
|
253
|
+
|
254
|
+
data["a"] = 4
|
255
|
+
assert(JSON::Validator.validate(schema,data))
|
256
|
+
|
257
|
+
data["a"] = 5
|
258
|
+
assert(!JSON::Validator.validate(schema,data))
|
259
|
+
|
260
|
+
# Test with float
|
261
|
+
data["a"] = 4.9999999
|
262
|
+
assert(JSON::Validator.validate(schema,data))
|
263
|
+
|
264
|
+
data["a"] = 5.0
|
265
|
+
assert(!JSON::Validator.validate(schema,data))
|
266
|
+
end
|
267
|
+
|
268
|
+
|
269
|
+
def test_min_items
|
270
|
+
# Set up the default datatype
|
271
|
+
schema = {
|
272
|
+
"properties" => {
|
273
|
+
"a" => {"minItems" => 1}
|
274
|
+
}
|
275
|
+
}
|
276
|
+
|
277
|
+
data = {
|
278
|
+
"a" => nil
|
279
|
+
}
|
280
|
+
|
281
|
+
# Test with an array
|
282
|
+
data["a"] = ["boo"]
|
283
|
+
assert(JSON::Validator.validate(schema,data))
|
284
|
+
|
285
|
+
data["a"] = []
|
286
|
+
assert(!JSON::Validator.validate(schema,data))
|
287
|
+
|
288
|
+
# Test with a non-array
|
289
|
+
data["a"] = "boo"
|
290
|
+
assert(JSON::Validator.validate(schema,data))
|
291
|
+
end
|
292
|
+
|
293
|
+
|
294
|
+
|
295
|
+
def test_max_items
|
296
|
+
# Set up the default datatype
|
297
|
+
schema = {
|
298
|
+
"properties" => {
|
299
|
+
"a" => {"maxItems" => 1}
|
300
|
+
}
|
301
|
+
}
|
302
|
+
|
303
|
+
data = {
|
304
|
+
"a" => nil
|
305
|
+
}
|
306
|
+
|
307
|
+
# Test with an array
|
308
|
+
data["a"] = ["boo"]
|
309
|
+
assert(JSON::Validator.validate(schema,data))
|
310
|
+
|
311
|
+
data["a"] = ["boo","taco"]
|
312
|
+
assert(!JSON::Validator.validate(schema,data))
|
313
|
+
|
314
|
+
# Test with a non-array
|
315
|
+
data["a"] = "boo"
|
316
|
+
assert(JSON::Validator.validate(schema,data))
|
317
|
+
end
|
318
|
+
|
319
|
+
|
320
|
+
|
321
|
+
def test_unique_items
|
322
|
+
# Set up the default datatype
|
323
|
+
schema = {
|
324
|
+
"properties" => {
|
325
|
+
"a" => {"uniqueItems" => true}
|
326
|
+
}
|
327
|
+
}
|
328
|
+
|
329
|
+
data = {
|
330
|
+
"a" => nil
|
331
|
+
}
|
332
|
+
|
333
|
+
# Test with nulls
|
334
|
+
data["a"] = [nil,5]
|
335
|
+
assert(JSON::Validator.validate(schema,data))
|
336
|
+
|
337
|
+
data["a"] = [nil,nil]
|
338
|
+
assert(!JSON::Validator.validate(schema,data))
|
339
|
+
|
340
|
+
# Test with booleans
|
341
|
+
data["a"] = [true,4]
|
342
|
+
assert(JSON::Validator.validate(schema,data))
|
343
|
+
|
344
|
+
data["a"] = [true,false]
|
345
|
+
assert(JSON::Validator.validate(schema,data))
|
346
|
+
|
347
|
+
data["a"] = [true,true]
|
348
|
+
assert(!JSON::Validator.validate(schema,data))
|
349
|
+
|
350
|
+
# Test with numbers
|
351
|
+
data["a"] = [4,true]
|
352
|
+
assert(JSON::Validator.validate(schema,data))
|
353
|
+
|
354
|
+
data["a"] = [4,4.1]
|
355
|
+
assert(JSON::Validator.validate(schema,data))
|
356
|
+
|
357
|
+
data["a"] = [4,4]
|
358
|
+
assert(!JSON::Validator.validate(schema,data))
|
359
|
+
|
360
|
+
# Test with strings
|
361
|
+
data["a"] = ['a',true]
|
362
|
+
assert(JSON::Validator.validate(schema,data))
|
363
|
+
|
364
|
+
data["a"] = ['a','ab']
|
365
|
+
assert(JSON::Validator.validate(schema,data))
|
366
|
+
|
367
|
+
data["a"] = ['a','a']
|
368
|
+
assert(!JSON::Validator.validate(schema,data))
|
369
|
+
|
370
|
+
# Test with arrays
|
371
|
+
data["a"] = [[1],true]
|
372
|
+
assert(JSON::Validator.validate(schema,data))
|
373
|
+
|
374
|
+
data["a"] = [[1,2],[1,3]]
|
375
|
+
assert(JSON::Validator.validate(schema,data))
|
376
|
+
|
377
|
+
data["a"] = [[1,2,3],[1,2,3]]
|
378
|
+
assert(!JSON::Validator.validate(schema,data))
|
379
|
+
|
380
|
+
# Test with objects
|
381
|
+
data["a"] = [{"a" => 1},true]
|
382
|
+
assert(JSON::Validator.validate(schema,data))
|
383
|
+
|
384
|
+
data["a"] = [{"a" => 1},{"a" => 2}]
|
385
|
+
assert(JSON::Validator.validate(schema,data))
|
386
|
+
|
387
|
+
data["a"] = [{"a" => 1, "b" => 2}, {"a" => 1, "b" => 2}]
|
388
|
+
assert(!JSON::Validator.validate(schema,data))
|
389
|
+
end
|
390
|
+
|
391
|
+
|
392
|
+
def test_pattern
|
393
|
+
# Set up the default datatype
|
394
|
+
schema = {
|
395
|
+
"properties" => {
|
396
|
+
"a" => {"pattern" => "\\d+ taco"}
|
397
|
+
}
|
398
|
+
}
|
399
|
+
|
400
|
+
data = {
|
401
|
+
"a" => nil
|
402
|
+
}
|
403
|
+
|
404
|
+
# Test strings
|
405
|
+
data["a"] = "156 taco bell"
|
406
|
+
assert(JSON::Validator.validate(schema,data))
|
407
|
+
|
408
|
+
data["a"] = "taco"
|
409
|
+
assert(!JSON::Validator.validate(schema,data))
|
410
|
+
|
411
|
+
# Test a non-string
|
412
|
+
data["a"] = 5
|
413
|
+
assert(JSON::Validator.validate(schema,data))
|
414
|
+
end
|
415
|
+
|
416
|
+
|
417
|
+
def test_min_length
|
418
|
+
# Set up the default datatype
|
419
|
+
schema = {
|
420
|
+
"properties" => {
|
421
|
+
"a" => {"minLength" => 1}
|
422
|
+
}
|
423
|
+
}
|
424
|
+
|
425
|
+
data = {
|
426
|
+
"a" => nil
|
427
|
+
}
|
428
|
+
|
429
|
+
# Try out strings
|
430
|
+
data["a"] = "t"
|
431
|
+
assert(JSON::Validator.validate(schema,data))
|
432
|
+
|
433
|
+
data["a"] = ""
|
434
|
+
assert(!JSON::Validator.validate(schema,data))
|
435
|
+
|
436
|
+
# Try out non-string
|
437
|
+
data["a"] = 5
|
438
|
+
assert(JSON::Validator.validate(schema,data))
|
439
|
+
end
|
440
|
+
|
441
|
+
|
442
|
+
def test_max_length
|
443
|
+
# Set up the default datatype
|
444
|
+
schema = {
|
445
|
+
"properties" => {
|
446
|
+
"a" => {"maxLength" => 1}
|
447
|
+
}
|
448
|
+
}
|
449
|
+
|
450
|
+
data = {
|
451
|
+
"a" => nil
|
452
|
+
}
|
453
|
+
|
454
|
+
# Try out strings
|
455
|
+
data["a"] = "t"
|
456
|
+
assert(JSON::Validator.validate(schema,data))
|
457
|
+
|
458
|
+
data["a"] = "tt"
|
459
|
+
assert(!JSON::Validator.validate(schema,data))
|
460
|
+
|
461
|
+
# Try out non-string
|
462
|
+
data["a"] = 5
|
463
|
+
assert(JSON::Validator.validate(schema,data))
|
464
|
+
end
|
465
|
+
|
466
|
+
|
467
|
+
def test_enum
|
468
|
+
# Set up the default datatype
|
469
|
+
schema = {
|
470
|
+
"properties" => {
|
471
|
+
"a" => {"enum" => [1,'boo',[1,2,3],{"a" => "b"}]}
|
472
|
+
}
|
473
|
+
}
|
474
|
+
|
475
|
+
data = {
|
476
|
+
"a" => nil
|
477
|
+
}
|
478
|
+
|
479
|
+
# Make sure all of the above are valid...
|
480
|
+
data["a"] = 1
|
481
|
+
assert(JSON::Validator.validate(schema,data))
|
482
|
+
|
483
|
+
data["a"] = 'boo'
|
484
|
+
assert(JSON::Validator.validate(schema,data))
|
485
|
+
|
486
|
+
data["a"] = [1,2,3]
|
487
|
+
assert(JSON::Validator.validate(schema,data))
|
488
|
+
|
489
|
+
data["a"] = {"a" => "b"}
|
490
|
+
assert(JSON::Validator.validate(schema,data))
|
491
|
+
|
492
|
+
# Test something that doesn't exist
|
493
|
+
data["a"] = 'taco'
|
494
|
+
assert(!JSON::Validator.validate(schema,data))
|
495
|
+
|
496
|
+
# Try it without the key
|
497
|
+
data = {}
|
498
|
+
assert(JSON::Validator.validate(schema,data))
|
499
|
+
end
|
500
|
+
|
501
|
+
|
502
|
+
def test_divisible_by
|
503
|
+
# Set up the default datatype
|
504
|
+
schema = {
|
505
|
+
"properties" => {
|
506
|
+
"a" => {"divisibleBy" => 1.1}
|
507
|
+
}
|
508
|
+
}
|
509
|
+
|
510
|
+
data = {
|
511
|
+
"a" => nil
|
512
|
+
}
|
513
|
+
|
514
|
+
data["a"] = 3.3
|
515
|
+
assert(JSON::Validator.validate(schema,data))
|
516
|
+
|
517
|
+
data["a"] = 3.4
|
518
|
+
assert(!JSON::Validator.validate(schema,data))
|
519
|
+
|
520
|
+
schema["properties"]["a"]["divisibleBy"] = 2.0
|
521
|
+
|
522
|
+
data["a"] = 4.0
|
523
|
+
assert(JSON::Validator.validate(schema,data))
|
524
|
+
|
525
|
+
data["a"] = 'boo'
|
526
|
+
assert(JSON::Validator.validate(schema,data))
|
527
|
+
|
528
|
+
data["a"] = 5
|
529
|
+
schema["properties"]["a"]["divisibleBy"] = 0
|
530
|
+
assert(!JSON::Validator.validate(schema,data))
|
531
|
+
end
|
532
|
+
|
533
|
+
|
534
|
+
|
535
|
+
def test_disallow
|
536
|
+
# Set up the default datatype
|
537
|
+
schema = {
|
538
|
+
"properties" => {
|
539
|
+
"a" => {"disallow" => "integer"}
|
540
|
+
}
|
541
|
+
}
|
542
|
+
|
543
|
+
data = {
|
544
|
+
"a" => nil
|
545
|
+
}
|
546
|
+
|
547
|
+
|
548
|
+
data["a"] = 'string'
|
549
|
+
assert(JSON::Validator.validate(schema,data))
|
550
|
+
|
551
|
+
data["a"] = 5
|
552
|
+
assert(!JSON::Validator.validate(schema,data))
|
553
|
+
|
554
|
+
|
555
|
+
schema["properties"]["a"]["disallow"] = ["integer","string"]
|
556
|
+
data["a"] = 'string'
|
557
|
+
assert(!JSON::Validator.validate(schema,data))
|
558
|
+
|
559
|
+
data["a"] = 5
|
560
|
+
assert(!JSON::Validator.validate(schema,data))
|
561
|
+
|
562
|
+
data["a"] = false
|
563
|
+
assert(JSON::Validator.validate(schema,data))
|
564
|
+
|
565
|
+
end
|
566
|
+
|
567
|
+
|
568
|
+
end
|
569
|
+
|
metadata
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: json-schema
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 27
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 1
|
9
|
+
- 0
|
10
|
+
version: 0.1.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Kenny Hoxworth
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-11-24 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies:
|
21
|
+
- !ruby/object:Gem::Dependency
|
22
|
+
name: json
|
23
|
+
prerelease: false
|
24
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
hash: 3
|
30
|
+
segments:
|
31
|
+
- 0
|
32
|
+
version: "0"
|
33
|
+
type: :runtime
|
34
|
+
version_requirements: *id001
|
35
|
+
description: A Ruby JSON Schema Validator based on JSON Schema draft 03
|
36
|
+
email: hoxworth@gmail.com
|
37
|
+
executables: []
|
38
|
+
|
39
|
+
extensions: []
|
40
|
+
|
41
|
+
extra_rdoc_files:
|
42
|
+
- README.textile
|
43
|
+
files:
|
44
|
+
- lib/json-schema.rb
|
45
|
+
- lib/json-schema/schema.rb
|
46
|
+
- lib/json-schema/validator.rb
|
47
|
+
- lib/json-schema/uri/file.rb
|
48
|
+
- README.textile
|
49
|
+
- test/test_jsonschema.rb
|
50
|
+
has_rdoc: true
|
51
|
+
homepage: http://github.com/hoxworth/json-schema/tree/master
|
52
|
+
licenses: []
|
53
|
+
|
54
|
+
post_install_message:
|
55
|
+
rdoc_options: []
|
56
|
+
|
57
|
+
require_paths:
|
58
|
+
- lib
|
59
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
60
|
+
none: false
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
hash: 3
|
65
|
+
segments:
|
66
|
+
- 0
|
67
|
+
version: "0"
|
68
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
69
|
+
none: false
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
74
|
+
segments:
|
75
|
+
- 0
|
76
|
+
version: "0"
|
77
|
+
requirements: []
|
78
|
+
|
79
|
+
rubyforge_project:
|
80
|
+
rubygems_version: 1.3.7
|
81
|
+
signing_key:
|
82
|
+
specification_version: 3
|
83
|
+
summary: Ruby JSON Schema Validator
|
84
|
+
test_files:
|
85
|
+
- test/test_jsonschema.rb
|