jcrvalidator 0.6.5 → 0.7.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.
- checksums.yaml +4 -4
- data/lib/jcr/evaluate_array_rules.rb +1 -1
- data/lib/jcr/evaluate_group_rules.rb +1 -1
- data/lib/jcr/evaluate_object_rules.rb +1 -1
- data/lib/jcr/evaluate_rules.rb +128 -30
- data/lib/jcr/evaluate_value_rules.rb +8 -8
- data/lib/jcr/find_roots.rb +34 -8
- data/lib/jcr/jcr.rb +73 -22
- data/lib/jcr/parser.rb +34 -31
- data/lib/jcr/version.rb +1 -1
- metadata +9 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1092c1613500ed477ee3eb26367ed73fee3a940f
|
4
|
+
data.tar.gz: 824cdfcc22c6dc6a03d55bc10ad75857c881c627
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f6f55143125ef7cf87457a53bb66edb4c3b353fb710e8513cf85e893f969d7cb3b95a78d98429fef5c55b8b25fb4306455ecb1cf9c77c449c71d1ad2dedba84
|
7
|
+
data.tar.gz: 9539a3d5ad7577a119f30bb69596c8cb279d1d45818574b26f22c1f71613cac0ba785268a56797f57266b5533de8cc159fa42f9055643d8272a141642b024813
|
@@ -289,6 +289,6 @@ module JCR
|
|
289
289
|
|
290
290
|
def self.array_to_s( jcr, shallow=true )
|
291
291
|
rules, annotations = get_rules_and_annotations( jcr )
|
292
|
-
return "#{annotations_to_s( annotations)}
|
292
|
+
return "#{annotations_to_s( annotations)}[ #{rules_to_s( rules, shallow )} ]"
|
293
293
|
end
|
294
294
|
end
|
@@ -58,7 +58,7 @@ module JCR
|
|
58
58
|
|
59
59
|
def self.group_to_s( jcr, shallow=true)
|
60
60
|
rules, annotations = get_rules_and_annotations( jcr )
|
61
|
-
return "#{annotations_to_s( annotations)}
|
61
|
+
return "#{annotations_to_s( annotations)}( #{rules_to_s(rules,shallow)} )"
|
62
62
|
end
|
63
63
|
|
64
64
|
end
|
@@ -174,6 +174,6 @@ module JCR
|
|
174
174
|
|
175
175
|
def self.object_to_s( jcr, shallow=true )
|
176
176
|
rules, annotations = get_rules_and_annotations( jcr )
|
177
|
-
return "#{annotations_to_s( annotations)}
|
177
|
+
return "#{annotations_to_s( annotations)}{ #{rules_to_s(rules,shallow)} }"
|
178
178
|
end
|
179
179
|
end
|
data/lib/jcr/evaluate_rules.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2015-
|
1
|
+
# Copyright (c) 2015-2017 American Registry for Internet Numbers
|
2
2
|
#
|
3
3
|
# Permission to use, copy, modify, and/or distribute this software for any
|
4
4
|
# purpose with or without fee is hereby granted, provided that the above
|
@@ -54,9 +54,9 @@ module JCR
|
|
54
54
|
end
|
55
55
|
|
56
56
|
class EvalConditions
|
57
|
-
attr_accessor :mapping, :callbacks, :trace, :trace_stack, :
|
57
|
+
attr_accessor :mapping, :callbacks, :trace, :trace_stack, :failures
|
58
58
|
def initialize mapping, callbacks, trace = false
|
59
|
-
@
|
59
|
+
@failures = {}
|
60
60
|
@mapping = mapping
|
61
61
|
@trace = trace
|
62
62
|
@trace_stack = []
|
@@ -66,6 +66,29 @@ module JCR
|
|
66
66
|
@callbacks = {}
|
67
67
|
end
|
68
68
|
end
|
69
|
+
|
70
|
+
def report_failure failure
|
71
|
+
@failures[ failure.stack_level ] = Array.new unless @failures[ failure.stack_level ]
|
72
|
+
@failures[ failure.stack_level ] << failure
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
class Failure
|
77
|
+
attr_accessor :data, :json, :json_elided, :evaluation, :rule, :pos, :offset, :type, :definition, :stack_level, :reason_elided
|
78
|
+
def initialize data, jcr, type, evaluation, stack_level
|
79
|
+
@json = data.to_json
|
80
|
+
@json_elided = JCR::elide(@json)
|
81
|
+
@data = JCR::rule_data( data )
|
82
|
+
@rule = JCR::find_first_slice( jcr )
|
83
|
+
@pos = @rule.line_and_column
|
84
|
+
@offset = @rule.offset
|
85
|
+
@type = type
|
86
|
+
@evaluation = evaluation
|
87
|
+
@reason_elided = "unknown reason"
|
88
|
+
@reason_elided = JCR::elide( @evaluation.reason ) if @evaluation.reason
|
89
|
+
@definition = JCR::rule_def( type, jcr )
|
90
|
+
@stack_level = stack_level
|
91
|
+
end
|
69
92
|
end
|
70
93
|
|
71
94
|
def self.evaluate_rule jcr, rule_atom, data, econs, behavior = nil
|
@@ -271,22 +294,30 @@ module JCR
|
|
271
294
|
end
|
272
295
|
|
273
296
|
def self.elide s
|
274
|
-
if s.length >
|
275
|
-
s = s[0..
|
297
|
+
if s.length > 45
|
298
|
+
s = s[0..41]
|
276
299
|
s = s + " ..."
|
277
300
|
end
|
278
301
|
return s
|
279
302
|
end
|
280
303
|
|
304
|
+
def self.rule_data data=nil
|
305
|
+
if data
|
306
|
+
if data.is_a? String
|
307
|
+
s = '"' + data + '"'
|
308
|
+
else
|
309
|
+
s = data.pretty_print_inspect
|
310
|
+
end
|
311
|
+
return elide(s)
|
312
|
+
end
|
313
|
+
#else
|
314
|
+
return nil
|
315
|
+
end
|
316
|
+
|
281
317
|
def self.trace econs, message, data = nil
|
282
318
|
if econs.trace
|
283
319
|
if data
|
284
|
-
|
285
|
-
s = '"' + data + '"'
|
286
|
-
else
|
287
|
-
s = data.pretty_print_inspect
|
288
|
-
end
|
289
|
-
message = "#{message} data: #{elide(s)}"
|
320
|
+
message = "#{message} data: #{rule_data( data )}"
|
290
321
|
end
|
291
322
|
last = econs.trace_stack.last
|
292
323
|
pos = "#{last.line_and_column}@#{last.offset}" if last
|
@@ -294,6 +325,25 @@ module JCR
|
|
294
325
|
end
|
295
326
|
end
|
296
327
|
|
328
|
+
def self.rule_def type, jcr
|
329
|
+
s = ""
|
330
|
+
case type
|
331
|
+
when "value"
|
332
|
+
s = elide(value_to_s(jcr))
|
333
|
+
when "member"
|
334
|
+
s = elide(member_to_s(jcr))
|
335
|
+
when "object"
|
336
|
+
s = elide(object_to_s(jcr))
|
337
|
+
when "array"
|
338
|
+
s = elide(array_to_s(jcr))
|
339
|
+
when "group"
|
340
|
+
s = elide(group_to_s(jcr))
|
341
|
+
else
|
342
|
+
s = "** unknown rule **"
|
343
|
+
end
|
344
|
+
return "#{type} definition: #{s}"
|
345
|
+
end
|
346
|
+
|
297
347
|
def self.trace_def econs, type, jcr, data
|
298
348
|
if econs.trace
|
299
349
|
s = ""
|
@@ -311,7 +361,7 @@ module JCR
|
|
311
361
|
else
|
312
362
|
s = "** unknown rule **"
|
313
363
|
end
|
314
|
-
trace( econs,
|
364
|
+
trace( econs, rule_def( type, jcr ) )
|
315
365
|
end
|
316
366
|
end
|
317
367
|
|
@@ -319,19 +369,9 @@ module JCR
|
|
319
369
|
if evaluation.success
|
320
370
|
trace( econs, "#{message} evaluation is true" )
|
321
371
|
else
|
372
|
+
failure = Failure.new( data, jcr, type, evaluation, econs.trace_stack.length )
|
373
|
+
econs.report_failure( failure )
|
322
374
|
trace( econs, "#{message} evaluation failed: #{evaluation.reason}")
|
323
|
-
unless econs.first_failure
|
324
|
-
econs.first_failure = evaluation
|
325
|
-
trace( econs, "** LIKELY ROOT CAUSE FOR FAILURE **" )
|
326
|
-
trace( econs, "***********************************" )
|
327
|
-
rule = find_first_slice( jcr )
|
328
|
-
pos = "Failed rule at line,column: #{rule.line_and_column} file position offset: #{rule.offset}"
|
329
|
-
trace( econs, pos )
|
330
|
-
trace_def( econs, type, jcr, data )
|
331
|
-
data_s = "JSON that failed to validate: #{data.to_json}"
|
332
|
-
trace( econs, data_s )
|
333
|
-
trace( econs, "***********************************" )
|
334
|
-
end
|
335
375
|
end
|
336
376
|
end
|
337
377
|
|
@@ -373,6 +413,20 @@ module JCR
|
|
373
413
|
end
|
374
414
|
|
375
415
|
def self.rule_to_s( rule, shallow=true)
|
416
|
+
if rule[:rule_name]
|
417
|
+
if rule[:primitive_rule]
|
418
|
+
retval = "$#{rule[:rule_name].to_s} =: #{ruletype_to_s( rule, shallow )}"
|
419
|
+
else
|
420
|
+
retval = "$#{rule[:rule_name].to_s} = #{ruletype_to_s( rule, shallow )}"
|
421
|
+
end
|
422
|
+
else
|
423
|
+
retval = ruletype_to_s( rule, shallow )
|
424
|
+
end
|
425
|
+
return retval
|
426
|
+
end
|
427
|
+
|
428
|
+
def self.ruletype_to_s( rule, shallow=true )
|
429
|
+
|
376
430
|
if rule[:primitive_rule]
|
377
431
|
retval = value_to_s( rule[:primitive_rule] )
|
378
432
|
elsif rule[:member_rule]
|
@@ -393,6 +447,7 @@ module JCR
|
|
393
447
|
retval = "** unknown rule definition ** #{rule}"
|
394
448
|
end
|
395
449
|
return retval
|
450
|
+
|
396
451
|
end
|
397
452
|
|
398
453
|
def self.rules_to_s( rules, shallow=true)
|
@@ -405,7 +460,7 @@ module JCR
|
|
405
460
|
elsif rule[:sequence_combiner]
|
406
461
|
retval = retval + " , "
|
407
462
|
end
|
408
|
-
retval = retval + rule_to_s( rule, shallow )
|
463
|
+
retval = retval + rule_to_s( rule, shallow ) + repetitions_to_s( rule )
|
409
464
|
end
|
410
465
|
return retval
|
411
466
|
end
|
@@ -415,13 +470,13 @@ module JCR
|
|
415
470
|
annotations.each do |a|
|
416
471
|
case
|
417
472
|
when a[:unordered_annotation]
|
418
|
-
retval = retval + "
|
473
|
+
retval = retval + "@{unordered}"
|
419
474
|
when a[:not_annotation]
|
420
|
-
retval = retval + "
|
475
|
+
retval = retval + "@{not}"
|
421
476
|
when a[:root_annotation]
|
422
|
-
retval = retval + "
|
477
|
+
retval = retval + "@{root}"
|
423
478
|
else
|
424
|
-
retval = retval + "
|
479
|
+
retval = retval + "@{ ** unknown annotation ** }"
|
425
480
|
end
|
426
481
|
end if annotations
|
427
482
|
retval = retval + " " if retval.length != 0
|
@@ -429,7 +484,50 @@ module JCR
|
|
429
484
|
end
|
430
485
|
|
431
486
|
def self.target_to_s( jcr )
|
432
|
-
return annotations_to_s( jcr[:annotations] ) + "
|
487
|
+
return annotations_to_s( jcr[:annotations] ) + "$" + jcr[:rule_name].to_s
|
488
|
+
end
|
489
|
+
|
490
|
+
def self.repetitions_to_s rule
|
491
|
+
retval = ""
|
492
|
+
if rule[:optional]
|
493
|
+
retval = "?"
|
494
|
+
elsif rule[:one_or_more]
|
495
|
+
retval = "+"
|
496
|
+
if rule[:repetition_step]
|
497
|
+
retval = "%" + rule[:repetition_step].to_s
|
498
|
+
end
|
499
|
+
elsif rule[:zero_or_more]
|
500
|
+
retval = "*"
|
501
|
+
retval = retval + "%" + rule[:repetition_step].to_s if rule[:repetition_step]
|
502
|
+
elsif rule[:specific_repetition] && rule[:specific_repetition].is_a?( Parslet::Slice )
|
503
|
+
retval = "*" + rule[:specific_repetition].to_s
|
504
|
+
else
|
505
|
+
if rule[:repetition_interval]
|
506
|
+
min = "0"
|
507
|
+
max = "INF"
|
508
|
+
o = rule[:repetition_min]
|
509
|
+
if o
|
510
|
+
if o.is_a?(Parslet::Slice)
|
511
|
+
min = o.to_s
|
512
|
+
end
|
513
|
+
end
|
514
|
+
o = rule[:repetition_max]
|
515
|
+
if o
|
516
|
+
if o.is_a?(Parslet::Slice)
|
517
|
+
max = o.to_s
|
518
|
+
end
|
519
|
+
end
|
520
|
+
retval = "*"+min+".."+max
|
521
|
+
end
|
522
|
+
o = rule[:repetition_step]
|
523
|
+
if o
|
524
|
+
if o.is_a?( Parslet::Slice )
|
525
|
+
retval = retval + "%" + o.to_s
|
526
|
+
end
|
527
|
+
end
|
528
|
+
end
|
529
|
+
retval = " " + retval if retval.length != 0
|
530
|
+
return retval
|
433
531
|
end
|
434
532
|
|
435
533
|
end
|
@@ -55,35 +55,35 @@ module JCR
|
|
55
55
|
when jcr[:integer_v]
|
56
56
|
si = jcr[:integer_v].to_s
|
57
57
|
if si == "integer"
|
58
|
-
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?(
|
58
|
+
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
|
59
59
|
end
|
60
60
|
when jcr[:integer]
|
61
61
|
i = jcr[:integer].to_s.to_i
|
62
62
|
return bad_value( jcr, rule_atom, i, data ) unless data == i
|
63
63
|
when jcr[:integer_min] != nil && jcr[:integer_max] == nil
|
64
|
-
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?(
|
64
|
+
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
|
65
65
|
min = jcr[:integer_min].to_s.to_i
|
66
66
|
return bad_value( jcr, rule_atom, min, data ) unless data >= min
|
67
67
|
when jcr[:integer_min] == nil && jcr[:integer_max] != nil
|
68
|
-
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?(
|
68
|
+
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
|
69
69
|
max = jcr[:integer_max].to_s.to_i
|
70
70
|
return bad_value( jcr, rule_atom, max, data ) unless data <= max
|
71
71
|
when jcr[:integer_min],jcr[:integer_max]
|
72
|
-
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?(
|
72
|
+
return bad_value( jcr, rule_atom, "integer", data ) unless data.is_a?( Integer )
|
73
73
|
min = jcr[:integer_min].to_s.to_i
|
74
74
|
return bad_value( jcr, rule_atom, min, data ) unless data >= min
|
75
75
|
max = jcr[:integer_max].to_s.to_i
|
76
76
|
return bad_value( jcr, rule_atom, max, data ) unless data <= max
|
77
77
|
when jcr[:sized_int_v]
|
78
78
|
bits = jcr[:sized_int_v][:bits].to_i
|
79
|
-
return bad_value( jcr, rule_atom, "int" + bits.to_s, data ) unless data.is_a?(
|
79
|
+
return bad_value( jcr, rule_atom, "int" + bits.to_s, data ) unless data.is_a?( Integer )
|
80
80
|
min = -(2**(bits-1))
|
81
81
|
return bad_value( jcr, rule_atom, min, data ) unless data >= min
|
82
82
|
max = 2**(bits-1)-1
|
83
83
|
return bad_value( jcr, rule_atom, max, data ) unless data <= max
|
84
84
|
when jcr[:sized_uint_v]
|
85
85
|
bits = jcr[:sized_uint_v][:bits].to_i
|
86
|
-
return bad_value( jcr, rule_atom, "int" + bits.to_s, data ) unless data.is_a?(
|
86
|
+
return bad_value( jcr, rule_atom, "int" + bits.to_s, data ) unless data.is_a?( Integer )
|
87
87
|
min = 0
|
88
88
|
return bad_value( jcr, rule_atom, min, data ) unless data >= min
|
89
89
|
max = 2**bits-1
|
@@ -470,9 +470,9 @@ module JCR
|
|
470
470
|
|
471
471
|
when rule[:uri]
|
472
472
|
if rule[:uri].is_a? Hash
|
473
|
-
retval = "
|
473
|
+
retval = "uri..#{rule[:uri][:uri_scheme].to_s}"
|
474
474
|
else
|
475
|
-
retval = "
|
475
|
+
retval = "uri"
|
476
476
|
end
|
477
477
|
|
478
478
|
when rule[:email]
|
data/lib/jcr/find_roots.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2015-
|
1
|
+
# Copyright (c) 2015-2017 American Registry for Internet Numbers
|
2
2
|
#
|
3
3
|
# Permission to use, copy, modify, and/or distribute this software for any
|
4
4
|
# purpose with or without fee is hereby granted, provided that the above
|
@@ -18,7 +18,7 @@ require 'jcr/evaluate_rules'
|
|
18
18
|
module JCR
|
19
19
|
|
20
20
|
class Root
|
21
|
-
attr_accessor :nameless, :name, :rule, :default
|
21
|
+
attr_accessor :nameless, :name, :rule, :default, :slice, :pos, :offset, :failures
|
22
22
|
|
23
23
|
def initialize rule, name = nil, nameless = true, default = false
|
24
24
|
@rule = rule
|
@@ -28,6 +28,9 @@ module JCR
|
|
28
28
|
@nameless = false
|
29
29
|
end
|
30
30
|
@default = default
|
31
|
+
@slice = JCR::find_first_slice( rule )
|
32
|
+
@pos = @slice.line_and_column
|
33
|
+
@offset = @slice.offset
|
31
34
|
end
|
32
35
|
end
|
33
36
|
|
@@ -52,18 +55,41 @@ module JCR
|
|
52
55
|
rn = node[:rule][:rule_name].to_str
|
53
56
|
rule = node[:rule]
|
54
57
|
ruledef = get_rule_by_type( rule )
|
55
|
-
|
58
|
+
new_root = nil
|
59
|
+
# look to see if the root_annotation is in the name before assignment ( @{root} $r = ... )
|
60
|
+
if rule[:annotations]
|
61
|
+
if rule[:annotations].is_a? Array
|
62
|
+
rule[:annotations].each do |annotation|
|
63
|
+
if annotation[:root_annotation]
|
64
|
+
new_root = Root.new(node, rn)
|
65
|
+
roots << new_root
|
66
|
+
# root is found, now look into subrule for unnamed roots
|
67
|
+
subrule = get_rule_by_type( ruledef )
|
68
|
+
roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
|
69
|
+
end
|
70
|
+
end
|
71
|
+
elsif rule[:annotations][:root_annotation]
|
72
|
+
new_root = Root.new(node, rn)
|
73
|
+
roots << new_root
|
74
|
+
# root is found, now look into subrule for unnamed roots
|
75
|
+
subrule = get_rule_by_type( ruledef )
|
76
|
+
roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
|
77
|
+
end
|
78
|
+
end
|
79
|
+
if ruledef && !new_root
|
56
80
|
if ruledef.is_a? Array
|
57
81
|
ruledef.each do |rdi|
|
82
|
+
# if it has a @{root} annotation in the rule definition
|
58
83
|
if rdi[:root_annotation]
|
59
|
-
roots << Root.new(
|
60
|
-
|
61
|
-
|
84
|
+
roots << Root.new(node, rn)
|
85
|
+
# else look into the definition further and examine subrules
|
86
|
+
elsif (subrule = get_rule_by_type(rdi))
|
87
|
+
roots.concat(find_roots_in_unnamed(subrule))
|
62
88
|
end
|
63
89
|
end
|
64
90
|
elsif ruledef.is_a? Hash
|
65
|
-
subrule = get_rule_by_type(
|
66
|
-
roots.concat(
|
91
|
+
subrule = get_rule_by_type(ruledef)
|
92
|
+
roots.concat(find_roots_in_unnamed(subrule)) if subrule
|
67
93
|
end
|
68
94
|
end
|
69
95
|
return roots
|
data/lib/jcr/jcr.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# Copyright (c) 2015-
|
1
|
+
# Copyright (c) 2015-2017 American Registry for Internet Numbers
|
2
2
|
#
|
3
3
|
# Permission to use, copy, modify, and/or distribute this software for any
|
4
4
|
# purpose with or without fee is hereby granted, provided that the above
|
@@ -28,7 +28,7 @@ require 'jcr/version'
|
|
28
28
|
module JCR
|
29
29
|
|
30
30
|
class Context
|
31
|
-
attr_accessor :mapping, :callbacks, :id, :tree, :roots, :catalog, :trace
|
31
|
+
attr_accessor :mapping, :callbacks, :id, :tree, :roots, :catalog, :trace, :failed_roots, :failure_report
|
32
32
|
|
33
33
|
def add_ruleset_alias( ruleset_alias, alias_uri )
|
34
34
|
unless @catalog
|
@@ -60,6 +60,7 @@ module JCR
|
|
60
60
|
|
61
61
|
def initialize( ruleset = nil, trace = false )
|
62
62
|
@trace = trace
|
63
|
+
@failed_roots = []
|
63
64
|
if ruleset
|
64
65
|
ingested = JCR.ingest_ruleset( ruleset, false, nil )
|
65
66
|
@mapping = ingested.mapping
|
@@ -109,30 +110,56 @@ module JCR
|
|
109
110
|
end
|
110
111
|
|
111
112
|
def self.evaluate_ruleset( data, ctx, root_name = nil )
|
112
|
-
|
113
|
+
roots = []
|
113
114
|
if root_name
|
114
115
|
root_rule = ctx.mapping[root_name]
|
115
116
|
raise "No rule by the name of #{root_name} for a root rule has been found" unless root_rule
|
116
|
-
|
117
|
+
root = JCR::Root.new( root_rule, root_name )
|
118
|
+
roots << root
|
117
119
|
else
|
118
|
-
ctx.roots
|
119
|
-
root_rules << r.rule
|
120
|
-
end
|
120
|
+
roots = ctx.roots
|
121
121
|
end
|
122
122
|
|
123
|
-
raise "No root rule defined. Specify a root rule name" if
|
123
|
+
raise "No root rule defined. Specify a root rule name" if roots.empty?
|
124
124
|
|
125
125
|
retval = nil
|
126
|
-
|
127
|
-
pp "Evaluating Root:", rule_to_s( r, false ) if ctx.trace
|
128
|
-
raise "Root rules cannot be member rules" if r[:member_rule]
|
129
|
-
|
126
|
+
roots.each do |r|
|
127
|
+
pp "Evaluating Root:", rule_to_s( r.rule, false ) if ctx.trace
|
128
|
+
raise "Root rules cannot be member rules" if r.rule[:member_rule]
|
129
|
+
econs = EvalConditions.new( ctx.mapping, ctx.callbacks, ctx.trace )
|
130
|
+
retval = JCR.evaluate_rule( r.rule, r.rule, data, econs )
|
130
131
|
break if retval.success
|
132
|
+
# else
|
133
|
+
r.failures = econs.failures
|
134
|
+
ctx.failed_roots << r
|
131
135
|
end
|
132
136
|
|
137
|
+
ctx.failure_report = failure_report( ctx )
|
133
138
|
return retval
|
134
139
|
end
|
135
140
|
|
141
|
+
def self.failure_report ctx
|
142
|
+
report = []
|
143
|
+
ctx.failed_roots.each do |failed_root|
|
144
|
+
if failed_root.name
|
145
|
+
report << "- ** Failures for root rule named '#{failed_root.name}'"
|
146
|
+
else
|
147
|
+
report << "- ** Failures for root rule at line #{failed_root.pos[0]}"
|
148
|
+
end
|
149
|
+
failed_root.failures.sort.map do |stack_level, failures|
|
150
|
+
if failures.length > 1
|
151
|
+
report << " - failure at rule depth #{stack_level} caused by one of the following #{failures.length} reasons"
|
152
|
+
else
|
153
|
+
report << " - failure at rule depth #{stack_level} caused by"
|
154
|
+
end
|
155
|
+
failures.each_with_index do |failure, index|
|
156
|
+
report << " - #{failure.json_elided} failed rule #{failure.definition} at #{failure.pos} because #{failure.reason_elided}"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
end
|
160
|
+
return report
|
161
|
+
end
|
162
|
+
|
136
163
|
def self.main my_argv=nil
|
137
164
|
|
138
165
|
my_argv = ARGV unless my_argv
|
@@ -205,6 +232,10 @@ module JCR
|
|
205
232
|
options[:verbose] = true
|
206
233
|
end
|
207
234
|
|
235
|
+
opt.on("-q","quiet") do |quiet|
|
236
|
+
options[:quiet] = true
|
237
|
+
end
|
238
|
+
|
208
239
|
opt.on("-h","display help") do |help|
|
209
240
|
options[:help] = true
|
210
241
|
end
|
@@ -243,7 +274,7 @@ module JCR
|
|
243
274
|
|
244
275
|
if options[:verbose]
|
245
276
|
pp "Ruleset Parse Tree", ctx.tree
|
246
|
-
|
277
|
+
puts "Ruleset Map"
|
247
278
|
ctx.mapping.each do |name,rule|
|
248
279
|
puts "Parsed Rule: #{name}"
|
249
280
|
puts rule_to_s( rule, false )
|
@@ -258,7 +289,7 @@ module JCR
|
|
258
289
|
return 0
|
259
290
|
elsif options[:json]
|
260
291
|
data = JSON.parse( options[:json] )
|
261
|
-
ec = cli_eval( ctx, data, options[:root_name], options[:
|
292
|
+
ec = cli_eval( ctx, data, options[:root_name], options[:quiet] )
|
262
293
|
return ec
|
263
294
|
elsif $stdin.tty?
|
264
295
|
ec = 0
|
@@ -267,35 +298,55 @@ module JCR
|
|
267
298
|
else
|
268
299
|
my_argv.each do |fn|
|
269
300
|
data = JSON.parse( File.open( fn ).read )
|
270
|
-
tec = cli_eval( ctx, data, options[:root_name], options[:
|
301
|
+
tec = cli_eval( ctx, data, options[:root_name], options[:quiet] )
|
271
302
|
ec = tec if tec != 0 #record error but don't let non-error overwrite error
|
272
303
|
end
|
273
304
|
end
|
274
305
|
return ec
|
275
306
|
else
|
276
|
-
|
277
|
-
ec =
|
307
|
+
lines = ""
|
308
|
+
ec = 0
|
309
|
+
ARGF.each do |line|
|
310
|
+
lines = lines + line
|
311
|
+
if ARGF.eof?
|
312
|
+
data = JSON.parse( lines )
|
313
|
+
tec = cli_eval( ctx, data, options[:root_name], options[:quiet] )
|
314
|
+
ec = tec if tec != 0 #record error but don't let non-error overwrite error
|
315
|
+
lines = ""
|
316
|
+
end
|
317
|
+
end
|
278
318
|
return ec
|
279
319
|
end
|
280
320
|
|
281
321
|
rescue Parslet::ParseFailed => failure
|
282
|
-
puts failure.
|
322
|
+
puts failure.parse_failure_cause.ascii_tree unless options[:quiet]
|
323
|
+
return 1
|
324
|
+
rescue JSON::ParserError => parser_error
|
325
|
+
unless options[:quiet]
|
326
|
+
puts "Unable to parse JSON"
|
327
|
+
puts parser_error.message.inspect
|
328
|
+
end
|
329
|
+
return 3
|
283
330
|
end
|
331
|
+
|
284
332
|
end
|
285
333
|
|
286
334
|
end
|
287
335
|
|
288
|
-
def self.cli_eval ctx, data, root_name,
|
336
|
+
def self.cli_eval ctx, data, root_name, quiet
|
289
337
|
ec = 2
|
290
338
|
e = ctx.evaluate( data, root_name )
|
291
339
|
if e.success
|
292
|
-
|
340
|
+
unless quiet
|
293
341
|
puts "Success!"
|
294
342
|
end
|
295
343
|
ec = 0
|
296
344
|
else
|
297
|
-
|
298
|
-
puts "Failure
|
345
|
+
unless quiet
|
346
|
+
puts "Failure! Use -v for more information."
|
347
|
+
ctx.failure_report.each do |line|
|
348
|
+
puts line
|
349
|
+
end
|
299
350
|
end
|
300
351
|
ec = 3
|
301
352
|
end
|
data/lib/jcr/parser.rb
CHANGED
@@ -72,8 +72,12 @@ module JCR
|
|
72
72
|
#> jcr-version-kw = "jcr-version"
|
73
73
|
#! major_version = non_neg_integer
|
74
74
|
#! minor_version = non_neg_integer
|
75
|
-
rule(:extension_id) {
|
76
|
-
#! extension_id =
|
75
|
+
rule(:extension_id) { id }
|
76
|
+
#! extension_id = id
|
77
|
+
rule(:id) { match('[a-zA-Z]') >> id_tail.repeat }
|
78
|
+
#! id = ALPHA *id-tail
|
79
|
+
rule(:id_tail) { match('[^\s}]') }
|
80
|
+
#! id-tail = %x21-7C / %x7E-10FFFF ; not spaces, not }
|
77
81
|
rule(:ruleset_id_d) { (str('ruleset-id') >> dsps >> ruleset_id.as(:ruleset_id)).as(:ruleset_id_d) }
|
78
82
|
#! ruleset_id_d = ruleset-id-kw DSPs ruleset_id
|
79
83
|
#> ruleset-id-kw = "ruleset-id"
|
@@ -82,9 +86,8 @@ module JCR
|
|
82
86
|
#! [ DSPs as_kw DSPs ruleset_id_alias ]
|
83
87
|
#> import-kw = "import"
|
84
88
|
#> as-kw = "as"
|
85
|
-
rule(:ruleset_id) {
|
86
|
-
#! ruleset_id =
|
87
|
-
#! not-space = %x21-10FFFF
|
89
|
+
rule(:ruleset_id) { id }
|
90
|
+
#! ruleset_id = id
|
88
91
|
rule(:ruleset_id_alias) { name.as(:ruleset_id_alias) }
|
89
92
|
#! ruleset_id_alias = name
|
90
93
|
rule(:one_line_tbd_directive_d) { name.as(:directive_name) >> ( wsp >> match('[^\r\n]').repeat.as(:directive_parameters) ).maybe }
|
@@ -309,41 +312,41 @@ module JCR
|
|
309
312
|
str('{') >> spcCmnt? >> object_items.maybe >> spcCmnt? >> str('}') ).as(:object_rule) }
|
310
313
|
#! object_rule = annotations "{" spcCmnt?
|
311
314
|
#! [ object_items spcCmnt? ] "}"
|
312
|
-
rule(:object_items) { object_item >> ((
|
313
|
-
(
|
314
|
-
#! object_items = object_item
|
315
|
-
#! *( choice_combiner object_item )
|
316
|
-
rule(:object_item ) { object_item_types >> spcCmnt? >> repetition.maybe }
|
317
|
-
#! object_item = object_item_types spcCmnt? [ repetition ]
|
315
|
+
rule(:object_items) { object_item >> (( sequence_combiner >> object_item ).repeat(1) |
|
316
|
+
( choice_combiner >> object_item ).repeat(1) ).maybe }
|
317
|
+
#! object_items = object_item [ 1*( sequence_combiner object_item ) /
|
318
|
+
#! 1*( choice_combiner object_item ) ]
|
319
|
+
rule(:object_item ) { object_item_types >> spcCmnt? >> ( repetition >> spcCmnt? ).maybe }
|
320
|
+
#! object_item = object_item_types spcCmnt? [ repetition spcCmnt? ]
|
318
321
|
rule(:object_item_types) { object_group | member_rule | target_rule_name }
|
319
322
|
#! object_item_types = object_group / member_rule / target_rule_name
|
320
|
-
rule(:object_group) { ( str('(') >> spcCmnt? >> object_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) }
|
321
|
-
#! object_group = "(" spcCmnt? [ object_items spcCmnt? ] ")"
|
323
|
+
rule(:object_group) { ( annotations >> str('(') >> spcCmnt? >> object_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) }
|
324
|
+
#! object_group = annotations "(" spcCmnt? [ object_items spcCmnt? ] ")"
|
322
325
|
#!
|
323
326
|
|
324
327
|
rule(:array_rule) { ( annotations >>
|
325
328
|
str('[') >> spcCmnt? >> array_items.maybe >> spcCmnt? >> str(']') ).as(:array_rule) }
|
326
329
|
#! array_rule = annotations "[" spcCmnt? [ array_items spcCmnt? ] "]"
|
327
|
-
rule(:array_items) { array_item >> ((
|
328
|
-
(
|
329
|
-
#! array_items = array_item
|
330
|
-
#! *( choice_combiner array_item )
|
331
|
-
rule(:array_item) { array_item_types >> spcCmnt? >> repetition.maybe }
|
332
|
-
#! array_item = array_item_types spcCmnt? [ repetition ]
|
330
|
+
rule(:array_items) { array_item >> (( sequence_combiner >> array_item ).repeat(1) |
|
331
|
+
( choice_combiner >> array_item ).repeat(1) ).maybe }
|
332
|
+
#! array_items = array_item [ 1*( sequence_combiner array_item ) /
|
333
|
+
#! 1*( choice_combiner array_item ) ]
|
334
|
+
rule(:array_item) { array_item_types >> spcCmnt? >> ( repetition >> spcCmnt? ).maybe }
|
335
|
+
#! array_item = array_item_types spcCmnt? [ repetition spcCmnt? ]
|
333
336
|
rule(:array_item_types) { array_group | type_rule | explicit_type_choice }
|
334
337
|
#! array_item_types = array_group / type_rule / explicit_type_choice
|
335
|
-
rule(:array_group) { ( str('(') >> spcCmnt? >> array_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) }
|
336
|
-
#! array_group = "(" spcCmnt? [ array_items spcCmnt? ] ")"
|
338
|
+
rule(:array_group) { ( annotations >> str('(') >> spcCmnt? >> array_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) }
|
339
|
+
#! array_group = annotations "(" spcCmnt? [ array_items spcCmnt? ] ")"
|
337
340
|
#!
|
338
341
|
|
339
342
|
rule(:group_rule) { ( annotations >> str('(') >> spcCmnt? >> group_items.maybe >> spcCmnt? >> str(')') ).as(:group_rule) }
|
340
343
|
#! group_rule = annotations "(" spcCmnt? [ group_items spcCmnt? ] ")"
|
341
|
-
rule(:group_items) { group_item >> ((
|
342
|
-
(
|
343
|
-
#! group_items = group_item
|
344
|
-
#! *( choice_combiner group_item )
|
345
|
-
rule(:group_item) { group_item_types >> spcCmnt? >> repetition.maybe }
|
346
|
-
#! group_item = group_item_types spcCmnt? [ repetition ]
|
344
|
+
rule(:group_items) { group_item >> (( sequence_combiner >> group_item ).repeat(1) |
|
345
|
+
( choice_combiner >> group_item ).repeat(1) ).maybe }
|
346
|
+
#! group_items = group_item [ 1*( sequence_combiner group_item ) /
|
347
|
+
#! 1*( choice_combiner group_item ) ]
|
348
|
+
rule(:group_item) { group_item_types >> spcCmnt? >> ( repetition >> spcCmnt? ).maybe }
|
349
|
+
#! group_item = group_item_types spcCmnt? [ repetition spcCmnt? ]
|
347
350
|
rule(:group_item_types) { group_group | member_rule | type_rule | explicit_type_choice }
|
348
351
|
#! group_item_types = group_group / member_rule /
|
349
352
|
#! type_rule / explicit_type_choice
|
@@ -351,10 +354,10 @@ module JCR
|
|
351
354
|
#! group_group = group_rule
|
352
355
|
#!
|
353
356
|
|
354
|
-
rule(:sequence_combiner) { str(',').as(:sequence_combiner) }
|
355
|
-
#! sequence_combiner =
|
356
|
-
rule(:choice_combiner) { str('|').as(:choice_combiner) }
|
357
|
-
#! choice_combiner =
|
357
|
+
rule(:sequence_combiner) { str(',').as(:sequence_combiner) >> spcCmnt? }
|
358
|
+
#! sequence_combiner = "," spcCmnt?
|
359
|
+
rule(:choice_combiner) { str('|').as(:choice_combiner) >> spcCmnt? }
|
360
|
+
#! choice_combiner = "|" spcCmnt?
|
358
361
|
#!
|
359
362
|
|
360
363
|
rule(:repetition) { optional | one_or_more |
|
data/lib/jcr/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: jcrvalidator
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Andrew Newton
|
@@ -9,20 +9,20 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2017-12-03 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: parslet
|
16
16
|
requirement: !ruby/object:Gem::Requirement
|
17
17
|
requirements:
|
18
|
-
- - ~>
|
18
|
+
- - "~>"
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '1.7'
|
21
21
|
type: :runtime
|
22
22
|
prerelease: false
|
23
23
|
version_requirements: !ruby/object:Gem::Requirement
|
24
24
|
requirements:
|
25
|
-
- - ~>
|
25
|
+
- - "~>"
|
26
26
|
- !ruby/object:Gem::Version
|
27
27
|
version: '1.7'
|
28
28
|
- !ruby/object:Gem::Dependency
|
@@ -43,14 +43,14 @@ dependencies:
|
|
43
43
|
name: email_address_validator
|
44
44
|
requirement: !ruby/object:Gem::Requirement
|
45
45
|
requirements:
|
46
|
-
- - ~>
|
46
|
+
- - "~>"
|
47
47
|
- !ruby/object:Gem::Version
|
48
48
|
version: '2.0'
|
49
49
|
type: :runtime
|
50
50
|
prerelease: false
|
51
51
|
version_requirements: !ruby/object:Gem::Requirement
|
52
52
|
requirements:
|
53
|
-
- - ~>
|
53
|
+
- - "~>"
|
54
54
|
- !ruby/object:Gem::Version
|
55
55
|
version: '2.0'
|
56
56
|
- !ruby/object:Gem::Dependency
|
@@ -100,19 +100,18 @@ require_paths:
|
|
100
100
|
- lib
|
101
101
|
required_ruby_version: !ruby/object:Gem::Requirement
|
102
102
|
requirements:
|
103
|
-
- -
|
103
|
+
- - ">="
|
104
104
|
- !ruby/object:Gem::Version
|
105
105
|
version: '0'
|
106
106
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
107
107
|
requirements:
|
108
|
-
- -
|
108
|
+
- - ">="
|
109
109
|
- !ruby/object:Gem::Version
|
110
110
|
version: '0'
|
111
111
|
requirements: []
|
112
112
|
rubyforge_project:
|
113
|
-
rubygems_version: 2.
|
113
|
+
rubygems_version: 2.5.2
|
114
114
|
signing_key:
|
115
115
|
specification_version: 4
|
116
116
|
summary: JCR Validator
|
117
117
|
test_files: []
|
118
|
-
has_rdoc:
|