json_schemer 0.1.3 → 0.1.4

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0c60e714e579a94981d17cf588f7b036ff39b95f95c6a4080b291c335e7ad4a4
4
- data.tar.gz: b902418e60c5e98d19456aed4ae6aad09e787b4074a9b08177b9cb1fa967cb4f
3
+ metadata.gz: 6f1555ed0ddacfa334c2a2635b4cce09c532aae3121539c28086e27ddf3c22fe
4
+ data.tar.gz: 5e49a8c68c44f40ac3ac9b3766b49f8f1c5d21ff5560dd1e2dd8f3d994183655
5
5
  SHA512:
6
- metadata.gz: 56f2f16354a2d1aff6565de44517b67722b8abc764dab185da0f4a46813a73599d32c7fdc1792790ad2cd1eaa08c92bda13b77ac76847da1c53b59bde0850c9b
7
- data.tar.gz: efd9edf9ab76f389107ec9d02964ed4904655c3e5d2f2e6aec66cad668b6d034a5d61a7fea77f56b7f10d7c8a8f8ceb2635316d7987f41ac96f34c4bf1d25fc5
6
+ metadata.gz: e5e79032c18e1e4f9ba1a21be3d7b6afc48a7decdd37f7b2f9d4a9984b85684b1b115e2b16a4497955ec0d0d696d082dcd346f0443b3494f415718323f3beb86
7
+ data.tar.gz: 229375ee9837355c3225080db7b88eed7dce26a3fb608ded003453b9765de4a3d1546d3ea0eb6e7649698fcbe8ba58b49157cab7817f6a71ae66963abb5f45a4
@@ -1,3 +1,3 @@
1
1
  [submodule "JSON-Schema-Test-Suite"]
2
2
  path = JSON-Schema-Test-Suite
3
- url = git@github.com:json-schema-org/JSON-Schema-Test-Suite
3
+ url = https://github.com/json-schema-org/JSON-Schema-Test-Suite
@@ -1,5 +1,10 @@
1
1
  sudo: false
2
2
  language: ruby
3
3
  rvm:
4
- - 2.5.0
4
+ - 2.5
5
+ - 2.3
6
+ - 2.2
5
7
  before_install: gem install bundler -v 1.16.1
8
+ before_script:
9
+ - pip install --user Flask
10
+ - ./JSON-Schema-Test-Suite/bin/jsonschema_suite serve &
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- json_schemer (0.1.3)
4
+ json_schemer (0.1.4)
5
5
  ecma-re-validator (~> 0.1.2)
6
6
  hana (~> 1.3.3)
7
7
  uri_template (~> 0.7.0)
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # JSONSchemer
2
2
 
3
- JSON Schema draft-07 validator
3
+ JSON Schema validator. Supports drafts 4, 6, and 7.
4
4
 
5
5
  ## Installation
6
6
 
@@ -32,7 +32,7 @@ schema = {
32
32
  }
33
33
  }
34
34
  }
35
- schemer = JSONSchemer::Schema.new(schema)
35
+ schemer = JSONSchemer.schema(schema)
36
36
 
37
37
  # true/false validation
38
38
 
@@ -51,7 +51,7 @@ schemer.validate({ 'abc' => 10 }).to_a
51
51
  ## Options
52
52
 
53
53
  ```ruby
54
- JSONSchemer::Schema.new(
54
+ JSONSchemer.schema(
55
55
  schema,
56
56
 
57
57
  # validate `format` (https://tools.ietf.org/html/draft-handrews-json-schema-validation-00#section-7)
@@ -71,7 +71,9 @@ JSONSchemer::Schema.new(
71
71
 
72
72
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake test` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
73
73
 
74
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
74
+ ## Build Status
75
+
76
+ [![Build Status](https://travis-ci.org/davishmcclurg/json_schemer.svg?branch=master)](https://travis-ci.org/davishmcclurg/json_schemer)
75
77
 
76
78
  ## Contributing
77
79
 
@@ -9,7 +9,7 @@ Gem::Specification.new do |spec|
9
9
  spec.authors = ["David Harsha"]
10
10
  spec.email = ["davishmcclurg@gmail.com"]
11
11
 
12
- spec.summary = "JSON Schema draft-07 validator"
12
+ spec.summary = "JSON Schema validator. Supports drafts 4, 6, and 7."
13
13
  spec.homepage = "https://github.com/davishmcclurg/json_schemer"
14
14
  spec.license = "MIT"
15
15
 
@@ -1,521 +1,27 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "json_schemer/version"
4
- require "json_schemer/format"
5
-
6
- require "base64"
7
- require "ecma-re-validator"
8
- require "hana"
9
- require "ipaddr"
10
- require "json"
11
- require 'net/http'
12
- require "time"
13
- require "uri"
14
- require "uri_template"
3
+ require 'json_schemer/version'
4
+ require 'json_schemer/format'
5
+ require 'json_schemer/schema/base'
6
+ require 'json_schemer/schema/draft4'
7
+ require 'json_schemer/schema/draft6'
8
+ require 'json_schemer/schema/draft7'
15
9
 
16
10
  module JSONSchemer
17
- class Schema
18
- class InvalidMetaSchema < StandardError; end
19
- class UnknownRef < StandardError; end
20
-
21
- META_SCHEMA = 'http://json-schema.org/draft-07/schema#'
22
- DEFAULT_REF_RESOLVER = proc { |uri| raise UnknownRef, uri.to_s }.freeze
23
- NET_HTTP_REF_RESOLVER = proc { |uri| JSON.parse(Net::HTTP.get(uri)) }.freeze
24
- BOOLEANS = Set[true, false].freeze
25
-
26
- def initialize(
27
- schema,
28
- format: true,
29
- formats: nil,
30
- keywords: nil,
31
- ref_resolver: DEFAULT_REF_RESOLVER
32
- )
33
- if schema.is_a?(Hash) && schema.key?('$schema') && schema['$schema'] != META_SCHEMA
34
- raise InvalidMetaSchema, "draft-07 is the only supported meta-schema (#{META_SCHEMA})"
35
- end
36
-
37
- @root = schema
38
- @format = format
39
- @formats = formats
40
- @keywords = keywords
41
- @ref_resolver = ref_resolver == 'net/http' ? NET_HTTP_REF_RESOLVER : ref_resolver
42
- end
43
-
44
- def valid?(data, schema = root, pointer = '', parent_uri = nil)
45
- validate(data, schema, pointer, parent_uri).none?
46
- end
47
-
48
- def validate(data, schema = root, pointer = '', parent_uri = nil)
49
- return enum_for(:validate, data, schema, pointer, parent_uri) unless block_given?
50
-
51
- return if schema == true
52
- if schema == false
53
- yield error(data, schema, pointer, 'schema')
54
- return
55
- end
56
-
57
- return if schema.empty?
58
-
59
- type = schema['type']
60
- enum = schema['enum']
61
- all_of = schema['allOf']
62
- any_of = schema['anyOf']
63
- one_of = schema['oneOf']
64
- not_schema = schema['not']
65
- if_schema = schema['if']
66
- then_schema = schema['then']
67
- else_schema = schema['else']
68
- format = schema['format']
69
- ref = schema['$ref']
70
- id = schema['$id']
71
-
72
- parent_uri = join_uri(parent_uri, id)
73
-
74
- if ref
75
- validate_ref(data, schema, pointer, parent_uri, ref, &Proc.new)
76
- return
77
- end
78
-
79
- validate_format(data, schema, pointer, format, &Proc.new) if format && format?
80
-
81
- if keywords
82
- keywords.each do |keyword, callable|
83
- if schema.key?(keyword)
84
- result = callable.call(data, schema, pointer)
85
- if result.is_a?(Array)
86
- result.each { |error| yield error }
87
- elsif !result
88
- yield error(data, schema, pointer, keyword)
89
- end
90
- end
91
- end
92
- end
93
-
94
- yield error(data, schema, pointer, 'enum') if enum && !enum.include?(data)
95
- yield error(data, schema, pointer, 'const') if schema.key?('const') && schema['const'] != data
96
-
97
- yield error(data, schema, pointer, 'allOf') if all_of && !all_of.all? { |subschema| valid?(data, subschema, pointer, parent_uri) }
98
- yield error(data, schema, pointer, 'anyOf') if any_of && !any_of.any? { |subschema| valid?(data, subschema, pointer, parent_uri) }
99
- yield error(data, schema, pointer, 'oneOf') if one_of && !one_of.one? { |subschema| valid?(data, subschema, pointer, parent_uri) }
100
- yield error(data, schema, pointer, 'not') if !not_schema.nil? && valid?(data, not_schema, pointer, parent_uri)
101
-
102
- if if_schema && valid?(data, if_schema, pointer, parent_uri)
103
- yield error(data, schema, pointer, 'then') if !then_schema.nil? && !valid?(data, then_schema, pointer, parent_uri)
104
- elsif if_schema
105
- yield error(data, schema, pointer, 'else') if !else_schema.nil? && !valid?(data, else_schema, pointer, parent_uri)
106
- end
107
-
108
- case type
109
- when nil
110
- validate_class(data, schema, pointer, parent_uri, &Proc.new)
111
- when String
112
- validate_type(data, schema, pointer, parent_uri, type, &Proc.new)
113
- when Array
114
- if valid_type = type.find { |subtype| valid?(data, { 'type' => subtype }, pointer, parent_uri) }
115
- validate_type(data, schema, pointer, parent_uri, valid_type, &Proc.new)
116
- else
117
- yield error(data, schema, pointer, 'type')
118
- end
119
- end
120
- end
121
-
122
- protected
123
-
124
- def ids
125
- @ids ||= resolve_ids(root)
126
- end
127
-
128
- private
129
-
130
- attr_reader :root, :formats, :keywords, :ref_resolver
131
-
132
- def format?
133
- !!@format
134
- end
135
-
136
- def child(schema)
137
- self.class.new(
138
- schema,
139
- format: format?,
140
- formats: formats,
141
- keywords: keywords,
142
- ref_resolver: ref_resolver
143
- )
144
- end
145
-
146
- def error(data, schema, pointer, type)
147
- {
148
- 'data' => data,
149
- 'schema' => schema,
150
- 'pointer' => pointer,
151
- 'type' => type,
152
- }
153
- end
154
-
155
- def validate_class(data, schema, pointer, parent_uri)
156
- case data
157
- when Integer
158
- validate_integer(data, schema, pointer, &Proc.new)
159
- when Numeric
160
- validate_number(data, schema, pointer, &Proc.new)
161
- when String
162
- validate_string(data, schema, pointer, &Proc.new)
163
- when Array
164
- validate_array(data, schema, pointer, parent_uri, &Proc.new)
165
- when Hash
166
- validate_object(data, schema, pointer, parent_uri, &Proc.new)
167
- end
168
- end
169
-
170
- def validate_type(data, schema, pointer, parent_uri, type)
171
- case type
172
- when 'null'
173
- yield error(data, schema, pointer, 'null') unless data.nil?
174
- when 'boolean'
175
- yield error(data, schema, pointer, 'boolean') unless BOOLEANS.include?(data)
176
- when 'number'
177
- validate_number(data, schema, pointer, &Proc.new)
178
- when 'integer'
179
- validate_integer(data, schema, pointer, &Proc.new)
180
- when 'string'
181
- validate_string(data, schema, pointer, &Proc.new)
182
- when 'array'
183
- validate_array(data, schema, pointer, parent_uri, &Proc.new)
184
- when 'object'
185
- validate_object(data, schema, pointer, parent_uri, &Proc.new)
186
- end
187
- end
188
-
189
- def validate_ref(data, schema, pointer, parent_uri, ref)
190
- ref_uri = join_uri(parent_uri, ref)
191
-
192
- if valid_json_pointer?(ref_uri.fragment)
193
- ref_pointer = Hana::Pointer.new(URI.unescape(ref_uri.fragment || ''))
194
- if ref.start_with?('#')
195
- validate(data, ref_pointer.eval(root), pointer, pointer_uri(root, ref_pointer), &Proc.new)
196
- else
197
- ref_root = ref_resolver.call(ref_uri)
198
- ref_object = child(ref_root)
199
- ref_object.validate(data, ref_pointer.eval(ref_root), pointer, pointer_uri(ref_root, ref_pointer), &Proc.new)
200
- end
201
- elsif ids.key?(ref_uri.to_s)
202
- validate(data, ids.fetch(ref_uri.to_s), pointer, ref_uri, &Proc.new)
203
- else
204
- ref_root = ref_resolver.call(ref_uri)
205
- ref_object = child(ref_root)
206
- ref_object.validate(data, ref_object.ids.fetch(ref_uri.to_s, ref_root), pointer, ref_uri, &Proc.new)
207
- end
208
- end
209
-
210
- def validate_format(data, schema, pointer, format)
211
- valid = if formats && formats.key?(format)
212
- format_option = formats[format]
213
- format_option == false || format_option.call(data, schema)
214
- else
215
- case format
216
- when 'date-time'
217
- valid_date_time?(data)
218
- when 'date'
219
- valid_date_time?("#{data}T04:05:06.123456789+07:00")
220
- when 'time'
221
- valid_date_time?("2001-02-03T#{data}")
222
- when 'email'
223
- data.ascii_only? && valid_email?(data)
224
- when 'idn-email'
225
- valid_email?(data)
226
- when 'hostname'
227
- data.ascii_only? && valid_hostname?(data)
228
- when 'idn-hostname'
229
- valid_hostname?(data)
230
- when 'ipv4'
231
- valid_ip?(data, :v4)
232
- when 'ipv6'
233
- valid_ip?(data, :v6)
234
- when 'uri'
235
- data.ascii_only? && valid_iri?(data)
236
- when 'uri-reference'
237
- data.ascii_only? && (valid_iri?(data) || valid_iri_reference?(data))
238
- when 'iri'
239
- valid_iri?(data)
240
- when 'iri-reference'
241
- valid_iri?(data) || valid_iri_reference?(data)
242
- when 'uri-template'
243
- valid_uri_template?(data)
244
- when 'json-pointer'
245
- valid_json_pointer?(data)
246
- when 'relative-json-pointer'
247
- valid_relative_json_pointer?(data)
248
- when 'regex'
249
- EcmaReValidator.valid?(data)
250
- end
251
- end
252
- yield error(data, schema, pointer, 'format') unless valid
253
- end
254
-
255
- def validate_numeric(data, schema, pointer)
256
- multiple_of = schema['multipleOf']
257
- maximum = schema['maximum']
258
- exclusive_maximum = schema['exclusiveMaximum']
259
- minimum = schema['minimum']
260
- exclusive_minimum = schema['exclusiveMinimum']
261
-
262
- yield error(data, schema, pointer, 'maximum') if maximum && data > maximum
263
- yield error(data, schema, pointer, 'exclusiveMaximum') if exclusive_maximum && data >= exclusive_maximum
264
- yield error(data, schema, pointer, 'minimum') if minimum && data < minimum
265
- yield error(data, schema, pointer, 'exclusiveMinimum') if exclusive_minimum && data <= exclusive_minimum
266
-
267
- if multiple_of
268
- quotient = data / multiple_of.to_f
269
- yield error(data, schema, pointer, 'multipleOf') unless quotient.floor == quotient
270
- end
271
- end
272
-
273
- def validate_number(data, schema, pointer)
274
- unless data.is_a?(Numeric)
275
- yield error(data, schema, pointer, 'number')
276
- return
277
- end
278
-
279
- validate_numeric(data, schema, pointer, &Proc.new)
280
- end
281
-
282
- def validate_integer(data, schema, pointer)
283
- if !data.is_a?(Numeric) || (!data.is_a?(Integer) && data.floor != data)
284
- yield error(data, schema, pointer, 'integer')
285
- return
286
- end
287
-
288
- validate_numeric(data, schema, pointer, &Proc.new)
289
- end
290
-
291
- def validate_string(data, schema, pointer)
292
- unless data.is_a?(String)
293
- yield error(data, schema, pointer, 'string')
294
- return
295
- end
296
-
297
- max_length = schema['maxLength']
298
- min_length = schema['minLength']
299
- pattern = schema['pattern']
300
- content_encoding = schema['contentEncoding']
301
- content_media_type = schema['contentMediaType']
302
-
303
- yield error(data, schema, pointer, 'maxLength') if max_length && data.size > max_length
304
- yield error(data, schema, pointer, 'minLength') if min_length && data.size < min_length
305
- yield error(data, schema, pointer, 'pattern') if pattern && Regexp.new(pattern) !~ data
306
-
307
- if content_encoding || content_media_type
308
- decoded_data = data
309
-
310
- if content_encoding
311
- decoded_data = case content_encoding.downcase
312
- when 'base64'
313
- safe_strict_decode64(data)
314
- else # '7bit', '8bit', 'binary', 'quoted-printable'
315
- raise NotImplementedError
316
- end
317
- yield error(data, schema, pointer, 'contentEncoding') unless decoded_data
318
- end
319
-
320
- if content_media_type && decoded_data
321
- case content_media_type.downcase
322
- when 'application/json'
323
- yield error(data, schema, pointer, 'contentMediaType') unless valid_json?(decoded_data)
324
- else
325
- raise NotImplementedError
326
- end
327
- end
328
- end
329
- end
330
-
331
- def validate_array(data, schema, pointer, parent_uri, &block)
332
- unless data.is_a?(Array)
333
- yield error(data, schema, pointer, 'array')
334
- return
335
- end
336
-
337
- items = schema['items']
338
- additional_items = schema['additionalItems']
339
- max_items = schema['maxItems']
340
- min_items = schema['minItems']
341
- unique_items = schema['uniqueItems']
342
- contains = schema['contains']
343
-
344
- yield error(data, schema, pointer, 'maxItems') if max_items && data.size > max_items
345
- yield error(data, schema, pointer, 'minItems') if min_items && data.size < min_items
346
- yield error(data, schema, pointer, 'uniqueItems') if unique_items && data.size != data.uniq.size
347
- yield error(data, schema, pointer, 'contains') if !contains.nil? && data.all? { |item| !valid?(item, contains, pointer, parent_uri) }
348
-
349
- if items.is_a?(Array)
350
- data.each_with_index do |item, index|
351
- if index < items.size
352
- validate(item, items[index], "#{pointer}/#{index}", parent_uri, &block)
353
- elsif !additional_items.nil?
354
- validate(item, additional_items, "#{pointer}/#{index}", parent_uri, &block)
355
- else
356
- break
357
- end
358
- end
359
- elsif !items.nil?
360
- data.each_with_index do |item, index|
361
- validate(item, items, "#{pointer}/#{index}", parent_uri, &block)
362
- end
363
- end
364
- end
365
-
366
- def validate_object(data, schema, pointer, parent_uri, &block)
367
- unless data.is_a?(Hash)
368
- yield error(data, schema, pointer, 'object')
369
- return
370
- end
371
-
372
- max_properties = schema['maxProperties']
373
- min_properties = schema['minProperties']
374
- required = schema['required']
375
- properties = schema['properties']
376
- pattern_properties = schema['patternProperties']
377
- additional_properties = schema['additionalProperties']
378
- dependencies = schema['dependencies']
379
- property_names = schema['propertyNames']
380
-
381
- if dependencies
382
- dependencies.each do |key, value|
383
- next unless data.key?(key)
384
- subschema = value.is_a?(Array) ? { 'required' => value } : value
385
- validate(data, subschema, pointer, parent_uri, &block)
386
- end
387
- end
388
-
389
- yield error(data, schema, pointer, 'maxProperties') if max_properties && data.size > max_properties
390
- yield error(data, schema, pointer, 'minProperties') if min_properties && data.size < min_properties
391
- yield error(data, schema, pointer, 'required') if required && required.any? { |key| !data.key?(key) }
392
-
393
- regex_pattern_properties = nil
394
- data.each do |key, value|
395
- validate(key, property_names, pointer, parent_uri, &block) unless property_names.nil?
396
-
397
- matched_key = false
398
-
399
- if properties && properties.key?(key)
400
- validate(value, properties[key], "#{pointer}/#{key}", parent_uri, &block)
401
- matched_key = true
402
- end
403
-
404
- if pattern_properties
405
- regex_pattern_properties ||= pattern_properties.map do |pattern, property_schema|
406
- [Regexp.new(pattern), property_schema]
407
- end
408
- regex_pattern_properties.each do |regex, property_schema|
409
- if regex =~ key
410
- validate(value, property_schema, "#{pointer}/#{key}", parent_uri, &block)
411
- matched_key = true
412
- end
413
- end
414
- end
415
-
416
- next if matched_key
417
-
418
- validate(value, additional_properties, "#{pointer}/#{key}", parent_uri, &block) unless additional_properties.nil?
419
- end
420
- end
421
-
422
- def safe_strict_decode64(data)
423
- begin
424
- Base64.strict_decode64(data)
425
- rescue ArgumentError => e
426
- raise e unless e.message == 'invalid base64'
427
- nil
428
- end
429
- end
430
-
431
- def valid_json?(data)
432
- JSON.parse(data)
433
- true
434
- rescue JSON::ParserError
435
- false
436
- end
437
-
438
- def valid_date_time?(data)
439
- DateTime.rfc3339(data)
440
- true
441
- rescue ArgumentError => e
442
- raise e unless e.message == 'invalid date'
443
- false
444
- end
445
-
446
- def valid_email?(data)
447
- !!(Format::EMAIL_REGEX =~ data)
448
- end
449
-
450
- def valid_hostname?(data)
451
- !!(Format::HOSTNAME_REGEX =~ data && data.split('.').all? { |label| label.size <= 63 })
452
- end
453
-
454
- def valid_ip?(data, type)
455
- ip_address = IPAddr.new(data)
456
- type == :v4 ? ip_address.ipv4? : ip_address.ipv6?
457
- rescue IPAddr::InvalidAddressError
458
- false
459
- end
460
-
461
- def valid_iri?(data)
462
- !!(Format::IRI =~ data)
463
- end
464
-
465
- def valid_iri_reference?(data)
466
- !!(Format::IRELATIVE_REF =~ data)
467
- end
468
-
469
- def valid_uri_template?(data)
470
- URITemplate.new(data)
471
- true
472
- rescue URITemplate::Invalid
473
- false
474
- end
475
-
476
- def valid_json_pointer?(data)
477
- !!(Format::JSON_POINTER_REGEX =~ data)
478
- end
479
-
480
- def valid_relative_json_pointer?(data)
481
- !!(Format::RELATIVE_JSON_POINTER_REGEX =~ data)
482
- end
11
+ class UnsupportedMetaSchema < StandardError; end
12
+ class UnknownRef < StandardError; end
483
13
 
484
- def join_uri(a, b)
485
- if a && b
486
- URI.join(a, b)
487
- elsif b
488
- URI.parse(b)
489
- else
490
- a
491
- end
492
- end
14
+ DRAFT_CLASS_BY_META_SCHEMA = {
15
+ 'http://json-schema.org/draft-04/schema#' => Schema::Draft4,
16
+ 'http://json-schema.org/draft-06/schema#' => Schema::Draft6,
17
+ 'http://json-schema.org/draft-07/schema#' => Schema::Draft7
18
+ }.freeze
493
19
 
494
- def pointer_uri(schema, pointer)
495
- uri_parts = nil
496
- pointer.reduce(schema) do |obj, token|
497
- next obj.fetch(token.to_i) if obj.is_a?(Array)
498
- if obj_id = obj['$id']
499
- uri_parts ||= []
500
- uri_parts << obj_id
501
- end
502
- obj.fetch(token)
503
- end
504
- uri_parts ? URI.join(*uri_parts) : nil
505
- end
20
+ DEFAULT_META_SCHEMA = 'http://json-schema.org/draft-07/schema#'
506
21
 
507
- def resolve_ids(schema, ids = {}, parent_uri = nil)
508
- if schema.is_a?(Array)
509
- schema.each { |subschema| resolve_ids(subschema, ids, parent_uri) }
510
- elsif schema.is_a?(Hash)
511
- id = schema['$id']
512
- uri = join_uri(parent_uri, id)
513
- ids[uri.to_s] = schema unless uri == parent_uri
514
- if definitions = schema['definitions']
515
- definitions.each_value { |subschema| resolve_ids(subschema, ids, uri) }
516
- end
517
- end
518
- ids
519
- end
22
+ def self.schema(schema, **options)
23
+ meta_schema = schema.is_a?(Hash) && schema.key?('$schema') ? schema['$schema'] : DEFAULT_META_SCHEMA
24
+ draft_class = DRAFT_CLASS_BY_META_SCHEMA[meta_schema] || raise(UnsupportedMetaSchema, meta_schema)
25
+ draft_class.new(schema, **options)
520
26
  end
521
27
  end