json-schema-openc-fork 0.0.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.
Files changed (114) hide show
  1. checksums.yaml +15 -0
  2. data/LICENSE.md +19 -0
  3. data/README.textile +452 -0
  4. data/lib/json-schema.rb +19 -0
  5. data/lib/json-schema/attribute.rb +43 -0
  6. data/lib/json-schema/attributes/additionalitems.rb +28 -0
  7. data/lib/json-schema/attributes/additionalproperties.rb +58 -0
  8. data/lib/json-schema/attributes/allof.rb +39 -0
  9. data/lib/json-schema/attributes/anyof.rb +47 -0
  10. data/lib/json-schema/attributes/dependencies.rb +44 -0
  11. data/lib/json-schema/attributes/disallow.rb +12 -0
  12. data/lib/json-schema/attributes/divisibleby.rb +22 -0
  13. data/lib/json-schema/attributes/enum.rb +24 -0
  14. data/lib/json-schema/attributes/extends.rb +50 -0
  15. data/lib/json-schema/attributes/format.rb +14 -0
  16. data/lib/json-schema/attributes/formats/custom.rb +21 -0
  17. data/lib/json-schema/attributes/formats/date.rb +24 -0
  18. data/lib/json-schema/attributes/formats/date_time.rb +36 -0
  19. data/lib/json-schema/attributes/formats/date_time_v4.rb +15 -0
  20. data/lib/json-schema/attributes/formats/ip.rb +41 -0
  21. data/lib/json-schema/attributes/formats/time.rb +22 -0
  22. data/lib/json-schema/attributes/formats/uri.rb +20 -0
  23. data/lib/json-schema/attributes/items.rb +26 -0
  24. data/lib/json-schema/attributes/limit.rb +179 -0
  25. data/lib/json-schema/attributes/maxdecimal.rb +18 -0
  26. data/lib/json-schema/attributes/multipleof.rb +11 -0
  27. data/lib/json-schema/attributes/not.rb +30 -0
  28. data/lib/json-schema/attributes/oneof.rb +56 -0
  29. data/lib/json-schema/attributes/pattern.rb +18 -0
  30. data/lib/json-schema/attributes/patternproperties.rb +22 -0
  31. data/lib/json-schema/attributes/properties.rb +74 -0
  32. data/lib/json-schema/attributes/properties_optional.rb +26 -0
  33. data/lib/json-schema/attributes/ref.rb +74 -0
  34. data/lib/json-schema/attributes/required.rb +28 -0
  35. data/lib/json-schema/attributes/type.rb +83 -0
  36. data/lib/json-schema/attributes/type_v4.rb +29 -0
  37. data/lib/json-schema/attributes/uniqueitems.rb +16 -0
  38. data/lib/json-schema/errors/custom_format_error.rb +6 -0
  39. data/lib/json-schema/errors/json_parse_error.rb +6 -0
  40. data/lib/json-schema/errors/schema_error.rb +6 -0
  41. data/lib/json-schema/errors/validation_error.rb +46 -0
  42. data/lib/json-schema/schema.rb +63 -0
  43. data/lib/json-schema/schema/reader.rb +113 -0
  44. data/lib/json-schema/schema/validator.rb +36 -0
  45. data/lib/json-schema/util/array_set.rb +14 -0
  46. data/lib/json-schema/util/uri.rb +16 -0
  47. data/lib/json-schema/util/uuid.rb +285 -0
  48. data/lib/json-schema/validator.rb +592 -0
  49. data/lib/json-schema/validators/draft1.rb +45 -0
  50. data/lib/json-schema/validators/draft2.rb +46 -0
  51. data/lib/json-schema/validators/draft3.rb +50 -0
  52. data/lib/json-schema/validators/draft4.rb +56 -0
  53. data/lib/json-schema/validators/hyper-draft4.rb +14 -0
  54. data/resources/draft-01.json +155 -0
  55. data/resources/draft-02.json +166 -0
  56. data/resources/draft-03.json +174 -0
  57. data/resources/draft-04.json +150 -0
  58. data/test/data/all_of_ref_data.json +3 -0
  59. data/test/data/any_of_ref_data.json +7 -0
  60. data/test/data/bad_data_1.json +3 -0
  61. data/test/data/good_data_1.json +3 -0
  62. data/test/data/one_of_ref_links_data.json +5 -0
  63. data/test/schemas/address_microformat.json +18 -0
  64. data/test/schemas/all_of_ref_base_schema.json +6 -0
  65. data/test/schemas/all_of_ref_schema.json +7 -0
  66. data/test/schemas/any_of_ref_jane_schema.json +4 -0
  67. data/test/schemas/any_of_ref_jimmy_schema.json +4 -0
  68. data/test/schemas/any_of_ref_john_schema.json +4 -0
  69. data/test/schemas/any_of_ref_schema.json +15 -0
  70. data/test/schemas/definition_schema.json +15 -0
  71. data/test/schemas/extends_and_additionalProperties-1-filename.schema.json +34 -0
  72. data/test/schemas/extends_and_additionalProperties-1-ref.schema.json +34 -0
  73. data/test/schemas/extends_and_additionalProperties-2-filename.schema.json +33 -0
  74. data/test/schemas/extends_and_additionalProperties-2-ref.schema.json +33 -0
  75. data/test/schemas/good_schema_1.json +10 -0
  76. data/test/schemas/good_schema_2.json +10 -0
  77. data/test/schemas/good_schema_extends1.json +10 -0
  78. data/test/schemas/good_schema_extends2.json +13 -0
  79. data/test/schemas/inner.schema.json +21 -0
  80. data/test/schemas/one_of_ref_links_schema.json +16 -0
  81. data/test/schemas/ref john with spaces schema.json +11 -0
  82. data/test/schemas/relative_definition_schema.json +8 -0
  83. data/test/schemas/self_link_schema.json +17 -0
  84. data/test/schemas/up_link_schema.json +17 -0
  85. data/test/test_all_of_ref_schema.rb +35 -0
  86. data/test/test_any_of_ref_schema.rb +35 -0
  87. data/test/test_bad_schema_ref.rb +39 -0
  88. data/test/test_common_test_suite.rb +66 -0
  89. data/test/test_custom_format.rb +116 -0
  90. data/test/test_definition.rb +15 -0
  91. data/test/test_extended_schema.rb +62 -0
  92. data/test/test_extends_and_additionalProperties.rb +52 -0
  93. data/test/test_files_v3.rb +43 -0
  94. data/test/test_fragment_resolution.rb +30 -0
  95. data/test/test_fragment_validation_with_ref.rb +34 -0
  96. data/test/test_full_validation.rb +208 -0
  97. data/test/test_helper.rb +47 -0
  98. data/test/test_initialize_data.rb +118 -0
  99. data/test/test_jsonschema_draft1.rb +171 -0
  100. data/test/test_jsonschema_draft2.rb +142 -0
  101. data/test/test_jsonschema_draft3.rb +502 -0
  102. data/test/test_jsonschema_draft4.rb +704 -0
  103. data/test/test_list_option.rb +21 -0
  104. data/test/test_merge_missing_values.rb +45 -0
  105. data/test/test_minitems.rb +16 -0
  106. data/test/test_one_of.rb +85 -0
  107. data/test/test_ruby_schema.rb +59 -0
  108. data/test/test_schema_loader.rb +74 -0
  109. data/test/test_schema_type_attribute.rb +20 -0
  110. data/test/test_schema_validation.rb +185 -0
  111. data/test/test_stringify.rb +48 -0
  112. data/test/test_uri_related.rb +67 -0
  113. data/test/test_validator.rb +53 -0
  114. metadata +284 -0
@@ -0,0 +1,592 @@
1
+ require 'addressable/uri'
2
+ require 'open-uri'
3
+ require 'pathname'
4
+ require 'bigdecimal'
5
+ require 'digest/sha1'
6
+ require 'date'
7
+ require 'thread'
8
+ require 'yaml'
9
+
10
+ require 'json-schema/schema/reader'
11
+ require 'json-schema/errors/schema_error'
12
+ require 'json-schema/errors/json_parse_error'
13
+
14
+ module JSON
15
+
16
+ class Validator
17
+
18
+ @@schemas = {}
19
+ @@cache_schemas = false
20
+ @@default_opts = {
21
+ :list => false,
22
+ :version => nil,
23
+ :validate_schema => false,
24
+ :record_errors => false,
25
+ :errors_as_objects => false,
26
+ :insert_defaults => false,
27
+ :clear_cache => true,
28
+ :strict => false,
29
+ :parse_data => true
30
+ }
31
+ @@validators = {}
32
+ @@default_validator = nil
33
+ @@available_json_backends = []
34
+ @@json_backend = nil
35
+ @@serializer = nil
36
+ @@mutex = Mutex.new
37
+
38
+ def initialize(schema_data, data, opts={})
39
+ @options = @@default_opts.clone.merge(opts)
40
+ @errors = []
41
+
42
+ validator = JSON::Validator.validator_for_name(@options[:version])
43
+ @options[:version] = validator
44
+ @options[:schema_reader] ||= JSON::Validator.schema_reader
45
+
46
+ @validation_options = @options[:record_errors] ? {:record_errors => true} : {}
47
+ @validation_options[:insert_defaults] = true if @options[:insert_defaults]
48
+ @validation_options[:strict] = true if @options[:strict] == true
49
+
50
+ @@mutex.synchronize { @base_schema = initialize_schema(schema_data) }
51
+ @original_data = data
52
+ @data = initialize_data(data)
53
+ @@mutex.synchronize { build_schemas(@base_schema) }
54
+
55
+ # validate the schema, if requested
56
+ if @options[:validate_schema]
57
+ begin
58
+ if @base_schema.schema["$schema"]
59
+ base_validator = JSON::Validator.validator_for_name(@base_schema.schema["$schema"])
60
+ end
61
+ metaschema = base_validator ? base_validator.metaschema : validator.metaschema
62
+ # Don't clear the cache during metaschema validation!
63
+ meta_validator = JSON::Validator.new(metaschema, @base_schema.schema, {:clear_cache => false})
64
+ meta_validator.validate
65
+ rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
66
+ raise $!
67
+ end
68
+ end
69
+
70
+ # If the :fragment option is set, try and validate against the fragment
71
+ if opts[:fragment]
72
+ @base_schema = schema_from_fragment(@base_schema, opts[:fragment])
73
+ end
74
+ end
75
+
76
+ def schema_from_fragment(base_schema, fragment)
77
+ schema_uri = base_schema.uri
78
+ fragments = fragment.split("/")
79
+
80
+ # ensure the first element was a hash, per the fragment spec
81
+ if fragments.shift != "#"
82
+ raise JSON::Schema::SchemaError.new("Invalid fragment syntax in :fragment option")
83
+ end
84
+
85
+ fragments.each do |f|
86
+ if base_schema.is_a?(JSON::Schema) #test if fragment is a JSON:Schema instance
87
+ if !base_schema.schema.has_key?(f)
88
+ raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
89
+ end
90
+ base_schema = base_schema.schema[f]
91
+ elsif base_schema.is_a?(Hash)
92
+ if !base_schema.has_key?(f)
93
+ raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
94
+ end
95
+ base_schema = JSON::Schema.new(base_schema[f],schema_uri,@options[:version])
96
+ elsif base_schema.is_a?(Array)
97
+ if base_schema[f.to_i].nil?
98
+ raise JSON::Schema::SchemaError.new("Invalid fragment resolution for :fragment option")
99
+ end
100
+ base_schema = JSON::Schema.new(base_schema[f.to_i],schema_uri,@options[:version])
101
+ else
102
+ raise JSON::Schema::SchemaError.new("Invalid schema encountered when resolving :fragment option")
103
+ end
104
+ end
105
+
106
+ if @options[:list]
107
+ base_schema.to_array_schema
108
+ else
109
+ base_schema
110
+ end
111
+ end
112
+
113
+ # Run a simple true/false validation of data against a schema
114
+ def validate()
115
+ @base_schema.validate(@data,[],self,@validation_options)
116
+ if @options[:errors_as_objects]
117
+ return @errors.map{|e| e.to_hash}
118
+ else
119
+ return @errors.map{|e| e.to_string}
120
+ end
121
+ ensure
122
+ if @validation_options[:clear_cache] == true
123
+ Validator.clear_cache
124
+ end
125
+ if @validation_options[:insert_defaults]
126
+ JSON::Validator.merge_missing_values(@data, @original_data)
127
+ end
128
+ end
129
+
130
+ def load_ref_schema(parent_schema, ref)
131
+ schema_uri = absolutize_ref_uri(ref, parent_schema.uri)
132
+
133
+ return true if self.class.schema_loaded?(schema_uri)
134
+
135
+ schema = @options[:schema_reader].read(schema_uri)
136
+ self.class.add_schema(schema)
137
+ build_schemas(schema)
138
+ end
139
+
140
+ def absolutize_ref_uri(ref, parent_schema_uri)
141
+ ref_uri = Addressable::URI.parse(ref)
142
+
143
+ return ref_uri if ref_uri.absolute?
144
+ # This is a self reference and thus the schema does not need to be re-loaded
145
+ return parent_schema_uri if ref_uri.path.empty?
146
+
147
+ uri = parent_schema_uri.clone
148
+ uri.fragment = ''
149
+ Util::URI.normalized_uri(uri.join(ref_uri.path))
150
+ end
151
+
152
+ # Build all schemas with IDs, mapping out the namespace
153
+ def build_schemas(parent_schema)
154
+ schema = parent_schema.schema
155
+
156
+ # Build ref schemas if they exist
157
+ if schema["$ref"]
158
+ load_ref_schema(parent_schema, schema["$ref"])
159
+ end
160
+
161
+ case schema["extends"]
162
+ when String
163
+ load_ref_schema(parent_schema, schema["extends"])
164
+ when Array
165
+ schema['extends'].each do |type|
166
+ handle_schema(parent_schema, type)
167
+ end
168
+ end
169
+
170
+ # Check for schemas in union types
171
+ ["type", "disallow"].each do |key|
172
+ if schema[key].is_a?(Array)
173
+ schema[key].each do |type|
174
+ if type.is_a?(Hash)
175
+ handle_schema(parent_schema, type)
176
+ end
177
+ end
178
+ end
179
+ end
180
+
181
+ # Schema properties whose values are objects, the values of which
182
+ # are themselves schemas.
183
+ %w[definitions properties patternProperties].each do |key|
184
+ next unless value = schema[key]
185
+ value.each do |k, inner_schema|
186
+ handle_schema(parent_schema, inner_schema)
187
+ end
188
+ end
189
+
190
+ # Schema properties whose values are themselves schemas.
191
+ %w[additionalProperties additionalItems dependencies extends].each do |key|
192
+ next unless schema[key].is_a?(Hash)
193
+ handle_schema(parent_schema, schema[key])
194
+ end
195
+
196
+ # Schema properties whose values may be an array of schemas.
197
+ %w[allOf anyOf oneOf not].each do |key|
198
+ next unless value = schema[key]
199
+ Array(value).each do |inner_schema|
200
+ handle_schema(parent_schema, inner_schema)
201
+ end
202
+ end
203
+
204
+ # Items are always schemas
205
+ if schema["items"]
206
+ items = schema["items"].clone
207
+ items = [items] unless items.is_a?(Array)
208
+
209
+ items.each do |item|
210
+ handle_schema(parent_schema, item)
211
+ end
212
+ end
213
+
214
+ # Convert enum to a ArraySet
215
+ if schema["enum"].is_a?(Array)
216
+ schema["enum"] = ArraySet.new(schema["enum"])
217
+ end
218
+
219
+ end
220
+
221
+ # Either load a reference schema or create a new schema
222
+ def handle_schema(parent_schema, obj)
223
+ if obj.is_a?(Hash)
224
+ schema_uri = parent_schema.uri.clone
225
+ schema = JSON::Schema.new(obj, schema_uri, parent_schema.validator)
226
+ if obj['id']
227
+ Validator.add_schema(schema)
228
+ end
229
+ build_schemas(schema)
230
+ end
231
+ end
232
+
233
+ def validation_error(error)
234
+ @errors.push(error)
235
+ end
236
+
237
+ def validation_errors
238
+ @errors
239
+ end
240
+
241
+
242
+ class << self
243
+ def validate(schema, data,opts={})
244
+ begin
245
+ validator = JSON::Validator.new(schema, data, opts)
246
+ validator.validate
247
+ return true
248
+ rescue JSON::Schema::ValidationError, JSON::Schema::SchemaError
249
+ return false
250
+ end
251
+ end
252
+
253
+ def validate_json(schema, data, opts={})
254
+ validate(schema, data, opts.merge(:json => true))
255
+ end
256
+
257
+ def validate_uri(schema, data, opts={})
258
+ validate(schema, data, opts.merge(:uri => true))
259
+ end
260
+
261
+ def validate!(schema, data,opts={})
262
+ validator = JSON::Validator.new(schema, data, opts)
263
+ validator.validate
264
+ return true
265
+ end
266
+ alias_method 'validate2', 'validate!'
267
+
268
+ def validate_json!(schema, data, opts={})
269
+ validate!(schema, data, opts.merge(:json => true))
270
+ end
271
+
272
+ def validate_uri!(schema, data, opts={})
273
+ validate!(schema, data, opts.merge(:uri => true))
274
+ end
275
+
276
+ def fully_validate(schema, data, opts={})
277
+ opts[:record_errors] = true
278
+ validator = JSON::Validator.new(schema, data, opts)
279
+ validator.validate
280
+ end
281
+
282
+ def fully_validate_schema(schema, opts={})
283
+ data = schema
284
+ schema = JSON::Validator.validator_for_name(opts[:version]).metaschema
285
+ fully_validate(schema, data, opts)
286
+ end
287
+
288
+ def fully_validate_json(schema, data, opts={})
289
+ fully_validate(schema, data, opts.merge(:json => true))
290
+ end
291
+
292
+ def fully_validate_uri(schema, data, opts={})
293
+ fully_validate(schema, data, opts.merge(:uri => true))
294
+ end
295
+
296
+ def schema_reader
297
+ @@schema_reader ||= JSON::Schema::Reader.new
298
+ end
299
+
300
+ def schema_reader=(reader)
301
+ @@schema_reader = reader
302
+ end
303
+
304
+ def clear_cache
305
+ @@schemas = {} if @@cache_schemas == false
306
+ end
307
+
308
+ def schemas
309
+ @@schemas
310
+ end
311
+
312
+ def add_schema(schema)
313
+ @@schemas[schema_key_for(schema.uri)] ||= schema
314
+ end
315
+
316
+ def schema_for_uri(uri)
317
+ # We only store normalized uris terminated with fragment #, so we can try whether
318
+ # normalization can be skipped
319
+ @@schemas[uri] || @@schemas[schema_key_for(uri)]
320
+ end
321
+
322
+ def schema_loaded?(schema_uri)
323
+ !schema_for_uri(schema_uri).nil?
324
+ end
325
+
326
+ def schema_key_for(uri)
327
+ key = Util::URI.normalized_uri(uri).to_s
328
+ key.end_with?('#') ? key : "#{key}#"
329
+ end
330
+
331
+ def cache_schemas=(val)
332
+ warn "[DEPRECATION NOTICE] Schema caching is now a validation option. Schemas will still be cached if this is set to true, but this method will be removed in version >= 3. Please use the :clear_cache validation option instead."
333
+ @@cache_schemas = val == true ? true : false
334
+ end
335
+
336
+ def validators
337
+ @@validators
338
+ end
339
+
340
+ def default_validator
341
+ @@default_validator
342
+ end
343
+
344
+ def validator_for_uri(schema_uri)
345
+ return default_validator unless schema_uri
346
+ u = Addressable::URI.parse(schema_uri)
347
+ validator = validators["#{u.scheme}://#{u.host}#{u.path}"]
348
+ if validator.nil?
349
+ raise JSON::Schema::SchemaError.new("Schema not found: #{schema_uri}")
350
+ else
351
+ validator
352
+ end
353
+ end
354
+
355
+ def validator_for_name(schema_name)
356
+ return default_validator unless schema_name
357
+ validator = validators_for_names([schema_name]).first
358
+ if validator.nil?
359
+ raise JSON::Schema::SchemaError.new("The requested JSON schema version is not supported")
360
+ else
361
+ validator
362
+ end
363
+ end
364
+
365
+ alias_method :validator_for, :validator_for_uri
366
+
367
+ def register_validator(v)
368
+ @@validators["#{v.uri.scheme}://#{v.uri.host}#{v.uri.path}"] = v
369
+ end
370
+
371
+ def register_default_validator(v)
372
+ @@default_validator = v
373
+ end
374
+
375
+ def register_format_validator(format, validation_proc, versions = ["draft1", "draft2", "draft3", "draft4"])
376
+ custom_format_validator = JSON::Schema::CustomFormat.new(validation_proc)
377
+ validators_for_names(versions).each do |validator|
378
+ validator.formats[format.to_s] = custom_format_validator
379
+ end
380
+ end
381
+
382
+ def deregister_format_validator(format, versions = ["draft1", "draft2", "draft3", "draft4"])
383
+ validators_for_names(versions).each do |validator|
384
+ validator.formats[format.to_s] = validator.default_formats[format.to_s]
385
+ end
386
+ end
387
+
388
+ def restore_default_formats(versions = ["draft1", "draft2", "draft3", "draft4"])
389
+ validators_for_names(versions).each do |validator|
390
+ validator.formats = validator.default_formats.clone
391
+ end
392
+ end
393
+
394
+ def json_backend
395
+ if defined?(MultiJson)
396
+ MultiJson.respond_to?(:adapter) ? MultiJson.adapter : MultiJson.engine
397
+ else
398
+ @@json_backend
399
+ end
400
+ end
401
+
402
+ def json_backend=(backend)
403
+ if defined?(MultiJson)
404
+ backend = backend == 'json' ? 'json_gem' : backend
405
+ MultiJson.respond_to?(:use) ? MultiJson.use(backend) : MultiJson.engine = backend
406
+ else
407
+ backend = backend.to_s
408
+ if @@available_json_backends.include?(backend)
409
+ @@json_backend = backend
410
+ else
411
+ raise JSON::Schema::JsonParseError.new("The JSON backend '#{backend}' could not be found.")
412
+ end
413
+ end
414
+ end
415
+
416
+ def parse(s)
417
+ if defined?(MultiJson)
418
+ MultiJson.respond_to?(:adapter) ? MultiJson.load(s) : MultiJson.decode(s)
419
+ else
420
+ case @@json_backend.to_s
421
+ when 'json'
422
+ JSON.parse(s, :quirks_mode => true)
423
+ when 'yajl'
424
+ json = StringIO.new(s)
425
+ parser = Yajl::Parser.new
426
+ parser.parse(json) or raise JSON::Schema::JsonParseError.new("The JSON could not be parsed by yajl")
427
+ else
428
+ raise JSON::Schema::JsonParseError.new("No supported JSON parsers found. The following parsers are suported:\n * yajl-ruby\n * json")
429
+ end
430
+ end
431
+ end
432
+
433
+ def merge_missing_values(source, destination)
434
+ case destination
435
+ when Hash
436
+ source.each do |key, source_value|
437
+ destination_value = destination[key] || destination[key.to_sym]
438
+ if destination_value.nil?
439
+ destination[key] = source_value
440
+ else
441
+ merge_missing_values(source_value, destination_value)
442
+ end
443
+ end
444
+ when Array
445
+ source.each_with_index do |source_value, i|
446
+ destination_value = destination[i]
447
+ merge_missing_values(source_value, destination_value)
448
+ end
449
+ end
450
+ end
451
+
452
+ if !defined?(MultiJson)
453
+ if Gem::Specification::find_all_by_name('json').any?
454
+ require 'json'
455
+ @@available_json_backends << 'json'
456
+ @@json_backend = 'json'
457
+ else
458
+ # Try force-loading json for rubies > 1.9.2
459
+ begin
460
+ require 'json'
461
+ @@available_json_backends << 'json'
462
+ @@json_backend = 'json'
463
+ rescue LoadError
464
+ end
465
+ end
466
+
467
+
468
+ if Gem::Specification::find_all_by_name('yajl-ruby').any?
469
+ require 'yajl'
470
+ @@available_json_backends << 'yajl'
471
+ @@json_backend = 'yajl'
472
+ end
473
+
474
+ if @@json_backend == 'yajl'
475
+ @@serializer = lambda{|o| Yajl::Encoder.encode(o) }
476
+ else
477
+ @@serializer = lambda{|o| YAML.dump(o) }
478
+ end
479
+ end
480
+
481
+ private
482
+
483
+ def validators_for_names(names)
484
+ names.map! { |name| name.to_s }
485
+ validators.reduce([]) do |memo, (_, validator)|
486
+ memo.tap { |m| m << validator if (validator.names & names).any? }
487
+ end
488
+ end
489
+ end
490
+
491
+ private
492
+
493
+ if Gem::Specification::find_all_by_name('uuidtools').any?
494
+ require 'uuidtools'
495
+ @@fake_uuid_generator = lambda{|s| UUIDTools::UUID.sha1_create(UUIDTools::UUID_URL_NAMESPACE, s).to_s }
496
+ else
497
+ require 'json-schema/util/uuid'
498
+ @@fake_uuid_generator = lambda{|s| JSON::Util::UUID.create_v5(s,JSON::Util::UUID::Nil).to_s }
499
+ end
500
+
501
+ def serialize schema
502
+ if defined?(MultiJson)
503
+ MultiJson.respond_to?(:dump) ? MultiJson.dump(schema) : MultiJson.encode(schema)
504
+ else
505
+ @@serializer.call(schema)
506
+ end
507
+ end
508
+
509
+ def fake_uuid schema
510
+ @@fake_uuid_generator.call(schema)
511
+ end
512
+
513
+ def initialize_schema(schema)
514
+ if schema.is_a?(String)
515
+ begin
516
+ # Build a fake URI for this
517
+ schema_uri = Addressable::URI.parse(fake_uuid(schema))
518
+ schema = JSON::Schema.new(JSON::Validator.parse(schema), schema_uri, @options[:version])
519
+ if @options[:list] && @options[:fragment].nil?
520
+ schema = schema.to_array_schema
521
+ end
522
+ Validator.add_schema(schema)
523
+ rescue
524
+ # Build a uri for it
525
+ schema_uri = Util::URI.normalized_uri(schema)
526
+ if !self.class.schema_loaded?(schema_uri)
527
+ schema = @options[:schema_reader].read(schema_uri)
528
+ schema = JSON::Schema.stringify(schema)
529
+
530
+ if @options[:list] && @options[:fragment].nil?
531
+ schema = schema.to_array_schema
532
+ end
533
+
534
+ Validator.add_schema(schema)
535
+ else
536
+ schema = self.class.schema_for_uri(schema_uri)
537
+ if @options[:list] && @options[:fragment].nil?
538
+ schema = schema.to_array_schema
539
+ schema.uri = Addressable::URI.parse(fake_uuid(serialize(schema.schema)))
540
+ Validator.add_schema(schema)
541
+ end
542
+ schema
543
+ end
544
+ end
545
+ elsif schema.is_a?(Hash)
546
+ schema_uri = Addressable::URI.parse(fake_uuid(serialize(schema)))
547
+ schema = JSON::Schema.stringify(schema)
548
+ schema = JSON::Schema.new(schema, schema_uri, @options[:version])
549
+ if @options[:list] && @options[:fragment].nil?
550
+ schema = schema.to_array_schema
551
+ end
552
+ Validator.add_schema(schema)
553
+ else
554
+ raise "Invalid schema - must be either a string or a hash"
555
+ end
556
+
557
+ schema
558
+ end
559
+
560
+ def initialize_data(data)
561
+ if @options[:parse_data]
562
+ if @options[:json]
563
+ data = JSON::Validator.parse(data)
564
+ elsif @options[:uri]
565
+ json_uri = Util::URI.normalized_uri(data)
566
+ data = JSON::Validator.parse(custom_open(json_uri))
567
+ elsif data.is_a?(String)
568
+ begin
569
+ data = JSON::Validator.parse(data)
570
+ rescue
571
+ begin
572
+ json_uri = Util::URI.normalized_uri(data)
573
+ data = JSON::Validator.parse(custom_open(json_uri))
574
+ rescue
575
+ # Silently discard the error - the data will not change
576
+ end
577
+ end
578
+ end
579
+ end
580
+ JSON::Schema.stringify(data)
581
+ end
582
+
583
+ def custom_open(uri)
584
+ uri = Util::URI.normalized_uri(uri) if uri.is_a?(String)
585
+ if uri.absolute? && uri.scheme != 'file'
586
+ open(uri.to_s).read
587
+ else
588
+ File.read(Addressable::URI.unescape(uri.path))
589
+ end
590
+ end
591
+ end
592
+ end