schema-validator 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 (6) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE +22 -0
  3. data/README.md +42 -0
  4. data/bin/schema-validator +82 -0
  5. data/lib/rx/ruby/Rx.rb +658 -0
  6. metadata +49 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 35da5c079158aa63d96d214b3ae9178236ffeba8
4
+ data.tar.gz: 5deffeb8218a0c223536dce3214362b41c668ed5
5
+ SHA512:
6
+ metadata.gz: 6605965706c35485ffb5da9774151e68a4d7616eba9cd100da244f8f17349bdb9cf041dea688d648e4576704b0f700a59f1011b7351815c8390744cd104bf92e
7
+ data.tar.gz: 61967ced8167906dd409ca9131df95e5317b260956f80a4beded6b40231c64ac9626a44300fd78226e8f9e13b8b91ad0297148c7c4c040e11a4215610144cd5b
data/LICENSE ADDED
@@ -0,0 +1,22 @@
1
+ Copyright (c) 2017 Lars Lockefeer
2
+
3
+ MIT License
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining
6
+ a copy of this software and associated documentation files (the
7
+ "Software"), to deal in the Software without restriction, including
8
+ without limitation the rights to use, copy, modify, merge, publish,
9
+ distribute, sublicense, and/or sell copies of the Software, and to
10
+ permit persons to whom the Software is furnished to do so, subject to
11
+ the following conditions:
12
+
13
+ The above copyright notice and this permission notice shall be
14
+ included in all copies or substantial portions of the Software.
15
+
16
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,42 @@
1
+ # SchemaValidator
2
+
3
+ A simple CLI wrapper around [Rx](http://rx.codesimply.com) for all your schema validation needs.
4
+
5
+ ## Usage
6
+
7
+ ```
8
+ Usage: runner [options]
9
+ -s, --schema SCHEMA The schema to validate against
10
+ -f, --file FILE The file to validate
11
+ -m META_SCHEMATA, A file containing meta schema definitions
12
+ --meta-schemata
13
+ ```
14
+
15
+ Example: validate `validatable.json` against the schema defined in `schema.json`, using the meta schemas from `meta_schemata.json`:
16
+
17
+ ```
18
+ ./schema-validator -s schema.json -f validatable.json -m meta_schemata.json
19
+ ```
20
+
21
+ ## Installation
22
+
23
+ Clone this repository and run:
24
+
25
+ ```
26
+ gem build schema-validator.gemspec
27
+ gem install schema-validator-{version}.gem
28
+ ```
29
+
30
+ Or add the following to your Gemfile:
31
+
32
+ ```
33
+ gem 'schema-validator', :git => 'https://github.com/larslockefeer/schema-validator.git', :submodules => true
34
+ ```
35
+
36
+ ## Acknowledgements
37
+
38
+ Under the hood, this gem uses [Rx](http://rx.codesimply.com) as the actual schema validation implementation.
39
+
40
+ ## Author
41
+
42
+ * Lars Lockefeer ([@larslockefeer](https://twitter.com/larslockefeer))
@@ -0,0 +1,82 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'json'
4
+ require 'optparse'
5
+ require 'ostruct'
6
+ require_relative '../lib/rx/ruby/Rx.rb'
7
+ require 'yaml'
8
+
9
+ # A utility to parse JSON or YAML
10
+ def parse_json_or_yaml(file)
11
+ begin
12
+ JSON.parse(file)
13
+ rescue Exception => e
14
+ YAML.load(file)
15
+ end
16
+ end
17
+
18
+ options = OpenStruct.new
19
+ OptionParser.new do |opt|
20
+ opt.on('-s', '--schema SCHEMA', 'The schema to validate against.') { |o| options.schema = o }
21
+ opt.on('-f', '--file FILE', 'The file to validate.') { |o| options.validatable = o }
22
+ opt.on('-m', '--meta-schemata META_SCHEMATA', 'A file containing meta schema definitions.') { |o| options.meta_schemata = o }
23
+ end.parse!
24
+
25
+ unless options.schema && options.validatable
26
+ puts "Please provide a schema and a file to validate."
27
+ puts "Run me with the -h flag to see usage instructions."
28
+ exit
29
+ end
30
+
31
+ if options.meta_schemata
32
+ meta_schemata_file = File.open(options.meta_schemata).read
33
+ meta_schemata = parse_json_or_yaml(meta_schemata_file)
34
+ else
35
+ meta_schemata = []
36
+ end
37
+
38
+ schema_file = File.open(options.schema).read
39
+ schema = parse_json_or_yaml(schema_file)
40
+
41
+ file = File.open(options.validatable).read
42
+ validatable = parse_json_or_yaml(file)
43
+
44
+ rx = Rx.new({ :load_core => true })
45
+
46
+ # Step 1: Learn the meta schemata
47
+ unless meta_schemata.empty?
48
+ puts "Learning meta schemata"
49
+ end
50
+ meta_schemata.each do |meta_schema|
51
+ begin
52
+ rx.learn_type(meta_schema['uri'], meta_schema['schema'])
53
+ puts " ✅ Learned meta scheme #{meta_schema['uri']}"
54
+ rescue Exception => e
55
+ puts " ❌ An error occured learning meta scheme #{meta_schema['uri']}"
56
+ puts " #{e.message}"
57
+ exit
58
+ end
59
+ end
60
+
61
+ # Step 2: Load the schema that we are going to validate against
62
+ puts "Loading schema to validate against"
63
+ begin
64
+ schema = rx.make_schema(schema)
65
+ puts " ✅ Schema loaded successfully"
66
+ rescue Exception => e
67
+ puts " ❌ An error occured loading the schema"
68
+ puts " #{e.message}"
69
+ exit
70
+ end
71
+
72
+ # Step 3: Validate our file against the schema
73
+ puts "Validating"
74
+ if schema then
75
+ begin
76
+ schema.check!(validatable)
77
+ puts " ✅ File is according to schema."
78
+ rescue Exception => e
79
+ puts " ❌ An error occured validating the file against the schema"
80
+ puts " #{e.message}"
81
+ end
82
+ end
data/lib/rx/ruby/Rx.rb ADDED
@@ -0,0 +1,658 @@
1
+
2
+ class Rx
3
+ def self.schema(schema)
4
+ Rx.new(:load_core => true).make_schema(schema)
5
+ end
6
+
7
+ def initialize(opt={})
8
+ @type_registry = {}
9
+ @prefix = {
10
+ '' => 'tag:codesimply.com,2008:rx/core/',
11
+ '.meta' => 'tag:codesimply.com,2008:rx/meta/',
12
+ }
13
+
14
+ if opt[:load_core] then
15
+ Type::Core.core_types.each { |t| register_type(t) }
16
+ end
17
+ end
18
+
19
+ def register_type(type)
20
+ uri = type.uri
21
+
22
+ if @type_registry.has_key?(uri) then
23
+ raise Rx::Exception.new(
24
+ "attempted to register already-known type #{uri}"
25
+ )
26
+ end
27
+
28
+ @type_registry[ uri ] = type
29
+ end
30
+
31
+ def learn_type(uri, schema)
32
+ if @type_registry.has_key?(uri) then
33
+ raise Rx::Exception.new(
34
+ "attempted to learn type for already-registered uri #{uri}"
35
+ )
36
+ end
37
+
38
+ # make sure schema is valid
39
+ # should this be in a begin/rescue?
40
+ make_schema(schema)
41
+
42
+ @type_registry[ uri ] = { 'schema' => schema }
43
+ end
44
+
45
+ def expand_uri(name)
46
+ if name.match(/\A\w+:/) then; return name; end;
47
+
48
+ match = name.match(/\A\/(.*?)\/(.+)\z/)
49
+ if ! match then
50
+ raise Rx::Exception.new("couldn't understand Rx type name: #{name}")
51
+ end
52
+
53
+ if ! @prefix.has_key?(match[1]) then
54
+ raise Rx::Exception.new("unknown prefix '#{match[1]}' in name 'name'")
55
+ end
56
+
57
+ return @prefix[ match[1] ] + match[2]
58
+ end
59
+
60
+ def add_prefix(name, base)
61
+ if @prefix.has_key?(name) then
62
+ throw Rx::Exception.new("the prefix '#{name}' is already registered")
63
+ end
64
+
65
+ @prefix[name] = base
66
+ end
67
+
68
+ def make_schema(schema)
69
+ schema = { 'type' => schema } if schema.instance_of?(String)
70
+
71
+ if not (schema.instance_of?(Hash) and schema['type']) then
72
+ raise Rx::Exception.new('invalid type')
73
+ end
74
+
75
+ uri = expand_uri(schema['type'])
76
+
77
+ if ! @type_registry.has_key?(uri) then
78
+ raise Rx::Exception.new('unknown type')
79
+ end
80
+
81
+ type_class = @type_registry[uri]
82
+
83
+ if type_class.instance_of?(Hash) then
84
+ if schema.keys != [ 'type' ] then
85
+ raise Rx::Exception.new('composed type does not take check arguments')
86
+ end
87
+ return make_schema(type_class['schema'])
88
+ else
89
+ return type_class.new(schema, self)
90
+ end
91
+ end
92
+
93
+ class Helper; end;
94
+ class Helper::Range
95
+
96
+ def initialize(arg)
97
+ @range = { }
98
+
99
+ arg.each_pair { |key,value|
100
+ if not ['min', 'max', 'min-ex', 'max-ex'].index(key) then
101
+ raise Rx::Exception.new("illegal argument for Rx::Helper::Range")
102
+ end
103
+
104
+ @range[ key ] = value
105
+ }
106
+ end
107
+
108
+ def check(value)
109
+ return false if ! @range['min' ].nil? and value < @range['min' ]
110
+ return false if ! @range['min-ex'].nil? and value <= @range['min-ex']
111
+ return false if ! @range['max-ex'].nil? and value >= @range['max-ex']
112
+ return false if ! @range['max' ].nil? and value > @range['max' ]
113
+ return true
114
+ end
115
+ end
116
+
117
+ class Exception < StandardError
118
+ end
119
+
120
+ class ValidationError < StandardError
121
+ attr_accessor :path
122
+
123
+ def initialize(message, path)
124
+ @message = message
125
+ @path = path
126
+ end
127
+
128
+ def path
129
+ @path ||= ""
130
+ end
131
+
132
+ def message
133
+ "#{@message} (#{@path})"
134
+ end
135
+
136
+ def inspect
137
+ "#{@message} (#{@path})"
138
+ end
139
+
140
+ def to_s
141
+ inspect
142
+ end
143
+ end
144
+
145
+ class Type
146
+ def initialize(param, rx)
147
+ assert_valid_params(param)
148
+ end
149
+
150
+ def uri; self.class.uri; end
151
+
152
+ def assert_valid_params(param)
153
+ param.each_key { |k|
154
+ unless self.allowed_param?(k) then
155
+ raise Rx::Exception.new("unknown parameter #{k} for #{uri}")
156
+ end
157
+ }
158
+ end
159
+
160
+ module NoParams
161
+ def initialize(param, rx)
162
+ return if param.keys.length == 0
163
+ return if param.keys == [ 'type' ]
164
+
165
+ raise Rx::Exception.new('this type is not parameterized')
166
+ end
167
+ end
168
+
169
+ class Type::Core < Type
170
+ class << self
171
+ def uri
172
+ return 'tag:codesimply.com,2008:rx/core/' + subname
173
+ end
174
+ end
175
+
176
+ def check(value)
177
+ begin
178
+ check!(value)
179
+ true
180
+ rescue ValidationError
181
+ false
182
+ end
183
+ end
184
+
185
+ class All < Type::Core
186
+ @@allowed_param = { 'of' => true, 'type' => true }
187
+ def allowed_param?(p); return @@allowed_param[p]; end
188
+
189
+ def initialize(param, rx)
190
+ super
191
+
192
+ if ! param.has_key?('of') then
193
+ raise Rx::Exception.new("no 'of' parameter provided for #{uri}")
194
+ end
195
+
196
+ if param['of'].length == 0 then
197
+ raise Rx::Exception.new("no schemata provided for 'of' in #{uri}")
198
+ end
199
+
200
+ @alts = [ ]
201
+ param['of'].each { |alt| @alts.push(rx.make_schema(alt)) }
202
+ end
203
+
204
+ class << self; def subname; return 'all'; end; end
205
+
206
+ def check!(value)
207
+ @alts.each do |alt|
208
+ begin
209
+ alt.check!(value)
210
+ rescue ValidationError => e
211
+ e.path = "/all" + e.path
212
+ raise e
213
+ end
214
+ end
215
+ return true
216
+ end
217
+ end
218
+
219
+ class Any < Type::Core
220
+ @@allowed_param = { 'of' => true, 'type' => true }
221
+ def allowed_param?(p); return @@allowed_param[p]; end
222
+
223
+ def initialize(param, rx)
224
+ super
225
+
226
+ if param['of'] then
227
+ if param['of'].length == 0 then
228
+ raise Rx::Exception.new(
229
+ "no alternatives provided for 'of' in #{uri}"
230
+ )
231
+ end
232
+
233
+ @alts = [ ]
234
+ param['of'].each { |alt| @alts.push(rx.make_schema(alt)) }
235
+ end
236
+ end
237
+
238
+ class << self; def subname; return 'any'; end; end
239
+
240
+ def check!(value)
241
+ return true unless @alts
242
+
243
+ @alts.each do |alt|
244
+ begin
245
+ return true if alt.check!(value)
246
+ rescue ValidationError
247
+ end
248
+ end
249
+
250
+ raise ValidationError.new("expected one to match", "/any")
251
+ end
252
+ end
253
+
254
+ class Arr < Type::Core
255
+ class << self; def subname; return 'arr'; end; end
256
+
257
+ @@allowed_param = { 'contents' => true, 'length' => true, 'type' => true }
258
+ def allowed_param?(p); return @@allowed_param[p]; end
259
+
260
+ def initialize(param, rx)
261
+ super
262
+
263
+ unless param['contents'] then
264
+ raise Rx::Exception.new("no contents schema given for #{uri}")
265
+ end
266
+
267
+ @contents_schema = rx.make_schema( param['contents'] )
268
+
269
+ if param['length'] then
270
+ @length_range = Rx::Helper::Range.new( param['length'] )
271
+ end
272
+ end
273
+
274
+ def check!(value)
275
+ unless value.instance_of?(Array)
276
+ raise ValidationError.new("expected array got #{value.class}", "/arr")
277
+ end
278
+
279
+ if @length_range
280
+ unless @length_range.check(value.length)
281
+ raise ValidationError.new("expected array with #{@length_range} elements, got #{value.length}", "/arr")
282
+ end
283
+ end
284
+
285
+ if @contents_schema then
286
+ value.each do |v|
287
+ begin
288
+ @contents_schema.check!(v)
289
+ rescue ValidationError => e
290
+ e.path = "/arr" + e.path
291
+ raise e
292
+ end
293
+ end
294
+ end
295
+
296
+ return true
297
+ end
298
+ end
299
+
300
+ class Bool < Type::Core
301
+ class << self; def subname; return 'bool'; end; end
302
+
303
+ include Type::NoParams
304
+
305
+ def check!(value)
306
+ unless value.instance_of?(TrueClass) or value.instance_of?(FalseClass)
307
+ raise ValidationError.new("expected bool got #{value.inspect}", "/bool")
308
+ end
309
+ true
310
+ end
311
+ end
312
+
313
+ class Fail < Type::Core
314
+ class << self; def subname; return 'fail'; end; end
315
+ include Type::NoParams
316
+ def check(value); return false; end
317
+ def check!(value); raise ValidationError.new("explicit fail", "/fail"); end
318
+ end
319
+
320
+ #
321
+ # Added by dan - 81030
322
+ class Date < Type::Core
323
+ class << self; def subname; return 'date'; end; end
324
+
325
+ include Type::NoParams
326
+
327
+ def check!(value)
328
+ unless value.instance_of?(::Date)
329
+ raise ValidationError("expected Date got #{value.inspect}", "/date")
330
+ end
331
+ true
332
+ end
333
+ end
334
+
335
+ class Def < Type::Core
336
+ class << self; def subname; return 'def'; end; end
337
+ include Type::NoParams
338
+ def check!(value); raise ValidationError.new("def failed", "/def") unless ! value.nil?; end
339
+ end
340
+
341
+ class Map < Type::Core
342
+ class << self; def subname; return 'map'; end; end
343
+ @@allowed_param = { 'values' => true, 'type' => true }
344
+ def allowed_param?(p); return @@allowed_param[p]; end
345
+
346
+ def initialize(param, rx)
347
+ super
348
+
349
+ unless param['values'] then
350
+ raise Rx::Exception.new("no values schema given for #{uri}")
351
+ end
352
+
353
+ @value_schema = rx.make_schema(param['values'])
354
+ end
355
+
356
+ def check!(value)
357
+ unless value.instance_of?(Hash) or value.class.to_s == "HashWithIndifferentAccess"
358
+ raise ValidationError.new("expected map got #{value.inspect}", "/map")
359
+ end
360
+
361
+ if @value_schema
362
+ value.each_value do |v|
363
+ begin
364
+ @value_schema.check!(v)
365
+ rescue ValidationError => e
366
+ e.path = "/map" + e.path
367
+ raise e
368
+ end
369
+ end
370
+ end
371
+
372
+ return true
373
+ end
374
+ end
375
+
376
+ class Nil < Type::Core
377
+ class << self; def subname; return 'nil'; end; end
378
+ include Type::NoParams
379
+ def check!(value); raise ValidationError.new("expected nil got #{value.inspect}", "/nil") unless value.nil?; true; end
380
+ end
381
+
382
+ class Num < Type::Core
383
+ class << self; def subname; return 'num'; end; end
384
+ @@allowed_param = { 'range' => true, 'type' => true, 'value' => true }
385
+ def allowed_param?(p); return @@allowed_param[p]; end
386
+
387
+ def initialize(param, rx)
388
+ super
389
+
390
+ if param.has_key?('value') then
391
+ if ! param['value'].kind_of?(Numeric) then
392
+ raise Rx::Exception.new("invalid value parameter for #{uri}")
393
+ end
394
+
395
+ @value = param['value']
396
+ end
397
+
398
+ if param['range'] then
399
+ @value_range = Rx::Helper::Range.new( param['range'] )
400
+ end
401
+ end
402
+
403
+ def check!(value)
404
+ if not value.kind_of?(Numeric)
405
+ raise ValidationError.new("expected Numeric got #{value.inspect}", "/#{self.class.subname}")
406
+ end
407
+ if @value_range and not @value_range.check(value)
408
+ raise ValidationError.new("expected Numeric in range #{@value_range} got #{value.inspect}", "/#{self.class.subname}")
409
+ end
410
+ if @value and value != @value
411
+ raise ValidationError.new("expected Numeric to equal #{@value} got #{value.inspect}", "/#{self.class.subname}")
412
+ end
413
+ true
414
+ end
415
+ end
416
+
417
+ class Int < Type::Core::Num
418
+ class << self; def subname; return 'int'; end; end
419
+
420
+ def initialize(param, rx)
421
+ super
422
+
423
+ if @value and @value % 1 != 0 then
424
+ raise Rx::Exception.new("invalid value parameter for #{uri}")
425
+ end
426
+ end
427
+
428
+ def check!(value)
429
+ super
430
+ unless value % 1 == 0
431
+ raise ValidationError.new("expected Integer got #{value.inspect}", "/int")
432
+ end
433
+ return true
434
+ end
435
+ end
436
+
437
+ class One < Type::Core
438
+ class << self; def subname; return 'one'; end; end
439
+ include Type::NoParams
440
+
441
+ def check!(value)
442
+ unless [ Numeric, String, TrueClass, FalseClass ].any? { |cls| value.kind_of?(cls) }
443
+ raise ValidationError.new("expected One got #{value.inspect}", "/one")
444
+ end
445
+ end
446
+ end
447
+
448
+ class Rec < Type::Core
449
+ class << self; def subname; return 'rec'; end; end
450
+ @@allowed_param = {
451
+ 'type' => true,
452
+ 'rest' => true,
453
+ 'required' => true,
454
+ 'optional' => true,
455
+ }
456
+
457
+ def allowed_param?(p); return @@allowed_param[p]; end
458
+
459
+ def initialize(param, rx)
460
+ super
461
+
462
+ @field = { }
463
+
464
+ @rest_schema = rx.make_schema(param['rest']) if param['rest']
465
+
466
+ [ 'optional', 'required' ].each { |type|
467
+ next unless param[type]
468
+ param[type].keys.each { |field|
469
+ if @field[field] then
470
+ raise Rx::Exception.new("#{field} in both required and optional")
471
+ end
472
+
473
+ @field[field] = {
474
+ :required => (type == 'required'),
475
+ :schema => rx.make_schema(param[type][field]),
476
+ }
477
+ }
478
+ }
479
+ end
480
+
481
+ def check!(value)
482
+ unless value.instance_of?(Hash) or value.class.to_s == "HashWithIndifferentAccess"
483
+ raise ValidationError.new("expected Hash got #{value.class}", "/rec")
484
+ end
485
+
486
+ rest = [ ]
487
+
488
+ value.each do |field, field_value|
489
+ unless @field[field] then
490
+ rest.push(field)
491
+ next
492
+ end
493
+
494
+ begin
495
+ @field[field][:schema].check!(field_value)
496
+ rescue ValidationError => e
497
+ e.path = "/rec:'#{field}'"
498
+ raise e
499
+ end
500
+ end
501
+
502
+ @field.select { |k,v| @field[k][:required] }.each do |pair|
503
+ unless value.has_key?(pair[0])
504
+ raise ValidationError.new("expected Hash to have key: '#{pair[0]}', only had #{value.keys.inspect}", "/rec")
505
+ end
506
+ end
507
+
508
+ if rest.length > 0 then
509
+ unless @rest_schema
510
+ raise ValidationError.new("Hash had extra keys: #{rest.inspect}", "/rec")
511
+ end
512
+ rest_hash = { }
513
+ rest.each { |field| rest_hash[field] = value[field] }
514
+ begin
515
+ @rest_schema.check!(rest_hash)
516
+ rescue ValidationError => e
517
+ e.path = "/rec"
518
+ raise e
519
+ end
520
+ end
521
+
522
+ return true
523
+ end
524
+ end
525
+
526
+ class Seq < Type::Core
527
+ class << self; def subname; return 'seq'; end; end
528
+ @@allowed_param = { 'tail' => true, 'contents' => true, 'type' => true }
529
+ def allowed_param?(p); return @@allowed_param[p]; end
530
+
531
+ def initialize(param, rx)
532
+ super
533
+
534
+ unless param['contents'] and param['contents'].kind_of?(Array) then
535
+ raise Rx::Exception.new("missing or invalid contents for #{uri}")
536
+ end
537
+
538
+ @content_schemata = param['contents'].map { |s| rx.make_schema(s) }
539
+
540
+ if param['tail'] then
541
+ @tail_schema = rx.make_schema(param['tail'])
542
+ end
543
+ end
544
+
545
+ def check!(value)
546
+ unless value.instance_of?(Array)
547
+ raise ValidationError.new("expected Array got #{value.inspect}", "/seq")
548
+ end
549
+ if value.length < @content_schemata.length
550
+ raise ValidationError.new("expected Array to have at least #{@content_schemata.length} elements, had #{value.length}", "/seq")
551
+ end
552
+ @content_schemata.each_index { |i|
553
+ begin
554
+ @content_schemata[i].check!(value[i])
555
+ rescue ValidationError => e
556
+ e.path = "/seq" + e.path
557
+ raise e
558
+ end
559
+ }
560
+
561
+ if value.length > @content_schemata.length then
562
+ unless @tail_schema
563
+ raise ValidationError.new("expected tail_schema", "/seq")
564
+ end
565
+ begin
566
+ @tail_schema.check!(value[
567
+ @content_schemata.length,
568
+ value.length - @content_schemata.length
569
+ ])
570
+ rescue ValidationError => e
571
+ e.path = "/seq" + e.path
572
+ raise e
573
+ end
574
+ end
575
+
576
+ return true
577
+ end
578
+ end
579
+
580
+ class Str < Type::Core
581
+ class << self; def subname; return 'str'; end; end
582
+ @@allowed_param = { 'type' => true, 'value' => true, 'length' => true }
583
+ def allowed_param?(p); return @@allowed_param[p]; end
584
+
585
+ def initialize(param, rx)
586
+ super
587
+
588
+ if param['length'] then
589
+ @length_range = Rx::Helper::Range.new( param['length'] )
590
+ end
591
+
592
+ if param.has_key?('value') then
593
+ if ! param['value'].instance_of?(String) then
594
+ raise Rx::Exception.new("invalid value parameter for #{uri}")
595
+ end
596
+
597
+ @value = param['value']
598
+ end
599
+ end
600
+
601
+ def check!(value)
602
+ unless value.instance_of?(String)
603
+ raise ValidationError.new("expected String got #{value.inspect}", "/str")
604
+ end
605
+
606
+ if @length_range
607
+ unless @length_range.check(value.length)
608
+ raise ValidationError.new("expected string with #{@length_range} characters, got #{value.length}", "/str")
609
+ end
610
+ end
611
+
612
+ if @value and value != @value
613
+ raise ValidationError.new("expected #{@value.inspect} got #{value.inspect}", "/str")
614
+ end
615
+ return true
616
+ end
617
+ end
618
+
619
+ #
620
+ # Added by dan - 81106
621
+ class Time < Type::Core
622
+ class << self; def subname; return 'time'; end; end
623
+
624
+ include Type::NoParams
625
+
626
+ def check!(value)
627
+ unless value.instance_of?(::Time)
628
+ raise ValidationError.new("expected Time got #{value.inspect}", "/time")
629
+ end
630
+ true
631
+ end
632
+ end
633
+
634
+ class << self
635
+ def core_types
636
+ return [
637
+ Type::Core::All,
638
+ Type::Core::Any,
639
+ Type::Core::Arr,
640
+ Type::Core::Bool,
641
+ Type::Core::Date,
642
+ Type::Core::Def,
643
+ Type::Core::Fail,
644
+ Type::Core::Int,
645
+ Type::Core::Map,
646
+ Type::Core::Nil,
647
+ Type::Core::Num,
648
+ Type::Core::One,
649
+ Type::Core::Rec,
650
+ Type::Core::Seq,
651
+ Type::Core::Str,
652
+ Type::Core::Time
653
+ ]
654
+ end
655
+ end
656
+ end
657
+ end
658
+ end
metadata ADDED
@@ -0,0 +1,49 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: schema-validator
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Lars Lockefeer
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2017-10-27 00:00:00.000000000 Z
12
+ dependencies: []
13
+ description: "\n A JSON schema validation tool.\n "
14
+ email:
15
+ - lars.lockefeer@teampicnic.com
16
+ executables:
17
+ - schema-validator
18
+ extensions: []
19
+ extra_rdoc_files: []
20
+ files:
21
+ - LICENSE
22
+ - README.md
23
+ - bin/schema-validator
24
+ - lib/rx/ruby/Rx.rb
25
+ homepage: https://github.com/larslockefeer/schema-validator
26
+ licenses:
27
+ - MIT
28
+ metadata: {}
29
+ post_install_message:
30
+ rdoc_options: []
31
+ require_paths:
32
+ - lib/rx/ruby
33
+ required_ruby_version: !ruby/object:Gem::Requirement
34
+ requirements:
35
+ - - "~>"
36
+ - !ruby/object:Gem::Version
37
+ version: '2.0'
38
+ required_rubygems_version: !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ version: '0'
43
+ requirements: []
44
+ rubyforge_project:
45
+ rubygems_version: 2.4.8
46
+ signing_key:
47
+ specification_version: 4
48
+ summary: A JSON schema validation tool.
49
+ test_files: []