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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e456ba6147ad0fa9bd8f9e38e8c042816f501d4f
4
- data.tar.gz: 8114d7992f86d0396e0508121f8a07e62c712f15
3
+ metadata.gz: 1092c1613500ed477ee3eb26367ed73fee3a940f
4
+ data.tar.gz: 824cdfcc22c6dc6a03d55bc10ad75857c881c627
5
5
  SHA512:
6
- metadata.gz: 25f08291b2a347a7d22f50de3ae182cc395b56a235004bfb454bcca7a8d1ebe43297aaba7573bee57491103378cc52119142fcf5cc4fc780ae31dbfd7561d623
7
- data.tar.gz: 7c002e9126134b957ec032a06ec98e547ae59cb097be17142e75aba8582ad59bbb7c5986261c6d4a9eb1319194ef9f0c7add95986bba9547fdea296652a635e3
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)} [ #{rules_to_s( rules, shallow )} ]"
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)} ( #{rules_to_s(rules,shallow)} )"
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)} { #{rules_to_s(rules,shallow)} }"
177
+ return "#{annotations_to_s( annotations)}{ #{rules_to_s(rules,shallow)} }"
178
178
  end
179
179
  end
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2015-2016 American Registry for Internet Numbers
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, :first_failure
57
+ attr_accessor :mapping, :callbacks, :trace, :trace_stack, :failures
58
58
  def initialize mapping, callbacks, trace = false
59
- @first_failure = nil
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 > 60
275
- s = s[0..56]
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
- if data.is_a? String
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, "#{type} definition: #{s}", data)
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 + " @{unordered}"
473
+ retval = retval + "@{unordered}"
419
474
  when a[:not_annotation]
420
- retval = retval + " @{not}"
475
+ retval = retval + "@{not}"
421
476
  when a[:root_annotation]
422
- retval = retval + " @{root}"
477
+ retval = retval + "@{root}"
423
478
  else
424
- retval = retval + " @{ ** unknown annotation ** }"
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] ) + " target: " + jcr[:rule_name].to_s
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?( Fixnum )
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?( Fixnum )
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?( Fixnum )
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?( Fixnum )
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?( Fixnum )
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?( Fixnum )
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 = "URI with specific scheme #{rule[:uri][:uri_scheme].to_s}"
473
+ retval = "uri..#{rule[:uri][:uri_scheme].to_s}"
474
474
  else
475
- retval = "URI"
475
+ retval = "uri"
476
476
  end
477
477
 
478
478
  when rule[:email]
@@ -1,4 +1,4 @@
1
- # Copyright (c) 2015-2016 American Registry for Internet Numbers
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
- if ruledef
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( node, rn )
60
- elsif (subrule = get_rule_by_type( rdi ))
61
- roots.concat( find_roots_in_unnamed( subrule ) )
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( ruledef )
66
- roots.concat( find_roots_in_unnamed( subrule ) ) if subrule
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-2016 American Registry for Internet Numbers
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
- root_rules = []
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
- root_rules << root_rule
117
+ root = JCR::Root.new( root_rule, root_name )
118
+ roots << root
117
119
  else
118
- ctx.roots.each do |r|
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 root_rules.empty?
123
+ raise "No root rule defined. Specify a root rule name" if roots.empty?
124
124
 
125
125
  retval = nil
126
- root_rules.each do |r|
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
- retval = JCR.evaluate_rule( r, r, data, EvalConditions.new( ctx.mapping, ctx.callbacks, ctx.trace ) )
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
- pp "Ruleset Map"
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[:verbose] )
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[:verbose] )
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
- data = JSON.parse( ARGF.read )
277
- ec = cli_eval( ctx, data, options[:root_name], options[:verbose] )
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.cause.ascii_tree
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, verbose
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
- if verbose
340
+ unless quiet
293
341
  puts "Success!"
294
342
  end
295
343
  ec = 0
296
344
  else
297
- if verbose
298
- puts "Failure: #{e.reason}"
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) { match('[a-zA-Z]') >> match('[\S]').repeat }
76
- #! extension_id = ALPHA *not-space
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) { match('[a-zA-Z]') >> match('[\S]').repeat }
86
- #! ruleset_id = ALPHA *not-space
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 >> (( spcCmnt? >> sequence_combiner >> spcCmnt? >> object_item ).repeat(1) |
313
- ( spcCmnt? >> choice_combiner >> spcCmnt? >> object_item ).repeat(1) ).maybe }
314
- #! object_items = object_item (*( sequence_combiner 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 >> (( spcCmnt? >> sequence_combiner >> spcCmnt? >> array_item ).repeat(1) |
328
- ( spcCmnt? >> choice_combiner >> spcCmnt? >> array_item ).repeat(1) ).maybe }
329
- #! array_items = array_item (*( sequence_combiner 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 >> (( spcCmnt? >> sequence_combiner >> spcCmnt? >> group_item ).repeat(1) |
342
- ( spcCmnt? >> choice_combiner >> spcCmnt? >> group_item ).repeat(1) ).maybe }
343
- #! group_items = group_item (*( sequence_combiner 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 = spcCmnt? "," spcCmnt?
356
- rule(:choice_combiner) { str('|').as(:choice_combiner) }
357
- #! choice_combiner = spcCmnt? "|" spcCmnt?
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
@@ -15,6 +15,6 @@
15
15
 
16
16
  module JCR
17
17
 
18
- VERSION = "0.6.5"
18
+ VERSION = "0.7.0"
19
19
 
20
20
  end
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.6.5
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: 2016-09-19 00:00:00.000000000 Z
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.4.5
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: