Skip to content

Commit 910d183

Browse files
authored
Merge pull request #111 from arineng/0.8.1-alpha1
0.8.1 alpha1 branch for 0.8.1 release
2 parents 8dae67b + 285c67d commit 910d183

24 files changed

+947
-192
lines changed

.travis.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ matrix:
1111
exclude:
1212
- rvm: 2.1.3
1313
os: osx
14-
- rvm: jruby-9.1
14+
- rvm: jruby-9.1.9.0
1515
os: osx
1616
script:
1717
- "bundle exec rake test"

README.md

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,15 @@ which can be found [here](https://raw.githubusercontent.com/arineng/jcr/09/draft
122122
* Much better CLI and programmatic validation failure information and structures
123123
* Fixes to print errors when the JCR fails to parse
124124
* 0.8.0 - Adds the --process-parts command line option
125+
* 0.8.1
126+
* Various issues with stack traces at the command line instead of proper errors
127+
* --process-parts now takes an optional directory
128+
* --process-parts now creates an XML entity reference file snippet
129+
* override rules can now reference rules in the original ruleset
130+
* more readable failure report
131+
* more readable verbose messages
132+
* @{not} annotation on targer rules were not honored but now fixed
133+
* better checking for groups referenced from arrays and objects
125134

126135
The current version of the JCR specification can be found
127136
[here](https://raw.githubusercontent.com/arineng/jcr/07/draft-newton-json-content-rules.txt)
@@ -180,7 +189,7 @@ Options
180189
-r FILE file containing ruleset
181190
-R STRING string containing ruleset. Should probably be quoted
182191
--test-jcr parse and test the JCR only
183-
--process-parts creates smaller files for specification writing
192+
--process-parts [DIRECTORY] creates smaller files for specification writing
184193
-S STRING name of root rule. All roots will be tried if none is specified
185194
-o FILE file containing overide ruleset (option can be repeated)
186195
-O STRING string containing overide rule (option can be repeated)
@@ -191,11 +200,11 @@ Options
191200
192201
Return codes:
193202
0 = success
194-
1 = parsing or other bad condition
195-
2 = fall through bad condition
203+
1 = bad JCR parsing or other bad condition
204+
2 = invalid option or bad use of command
196205
3 = unsuccessful evaluation of JSON
197206
198-
JCR Version 0.8.0
207+
JCR Version 0.8.1
199208
```
200209

201210
## Usage as a Library
@@ -222,8 +231,8 @@ The `callback.rb` demonstrates the usage of custom code for evaluation of rules.
222231

223232
The `--process-parts` option extracts parts of a JCR file into multiple files based
224233
on comments in the file. It can also create a new file without the
225-
comments. This is useful for JCR going into specification documents
226-
where it is nice to break the JCR up for illustrative purposes in
234+
comments. This is useful for rulesets going into specification documents
235+
where it is nice to break the rulesets up for illustrative purposes in
227236
the specification but to also have one JCR file for programmatic
228237
testing purposes.
229238

@@ -241,6 +250,9 @@ though leading whitespace is allowed if desired.
241250
To get a new file with all parts but these comments, use this
242251

243252
; all_parts FILENAME
253+
254+
The `--process-parts` parameter will also take an optional directory name where it
255+
will write the files.
244256

245257
## Building
246258

lib/jcr/check_groups.rb

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -78,8 +78,6 @@ def self.check_member_for_group node, mapping
7878
disallowed_group_in_member?( trule, mapping )
7979
elsif node[:group_rule]
8080
disallowed_group_in_member?( node[:group_rule], mapping )
81-
else
82-
check_groups( node, mapping )
8381
end
8482
end
8583

@@ -117,8 +115,6 @@ def self.check_array_for_group node, mapping
117115
disallowed_group_in_array?(trule, mapping)
118116
elsif node[:group_rule]
119117
disallowed_group_in_array?(node[:group_rule], mapping)
120-
else
121-
check_groups(node, mapping)
122118
end
123119
end
124120
end
@@ -132,9 +128,7 @@ def self.disallowed_group_in_array? node, mapping
132128
disallowed_group_in_array?( groupee[:group_rule], mapping )
133129
elsif groupee[:target_rule_name]
134130
trule = get_name_mapping( groupee[:target_rule_name][:rule_name], mapping )
135-
if trule[:group_rule]
136-
disallowed_group_in_array?( trule[:group_rule], mapping )
137-
end
131+
disallowed_group_in_array?( trule, mapping )
138132
elsif groupee[:member_rule]
139133
raise_group_error( "groups in array rules cannot have member rules", groupee[:member_rule] )
140134
else
@@ -154,8 +148,6 @@ def self.check_object_for_group node, mapping
154148
disallowed_group_in_object?(trule, mapping)
155149
elsif node[:group_rule]
156150
disallowed_group_in_object?(node[:group_rule], mapping)
157-
else
158-
check_groups(node, mapping)
159151
end
160152
end
161153
end
@@ -169,9 +161,7 @@ def self.disallowed_group_in_object? node, mapping
169161
disallowed_group_in_object?( groupee[:group_rule], mapping )
170162
elsif groupee[:target_rule_name]
171163
trule = get_name_mapping( groupee[:target_rule_name][:rule_name], mapping )
172-
if trule[:group_rule]
173-
disallowed_group_in_object?( trule[:group_rule], mapping )
174-
end
164+
disallowed_group_in_object?( trule, mapping )
175165
elsif groupee[:array_rule]
176166
raise_group_error( "groups in object rules cannot have array rules", groupee[:member_rule] )
177167
elsif groupee[:object_rule]
@@ -188,9 +178,9 @@ def self.raise_group_error str, node
188178
if node.is_a?( Parslet::Slice )
189179
pos = node.line_and_column
190180
name = node.to_str
191-
raise "group rule error at line " + pos[0].to_s + " column " + pos[1].to_s + " name '" + name + "' :" + str
181+
raise JCR::JcrValidatorError, "group rule error at line " + pos[0].to_s + " column " + pos[1].to_s + " name '" + name + "' :" + str
192182
else
193-
raise "group rule error with '" + node.to_s + "' :" + str
183+
raise JCR::JcrValidatorError, "group rule error with '" + node.to_s + "' :" + str
194184
end
195185
end
196186

lib/jcr/evaluate_array_rules.rb

Lines changed: 41 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -45,19 +45,28 @@ def initialize( current_behavior = nil )
4545
end
4646
end
4747

48-
def self.evaluate_array_rule jcr, rule_atom, data, econs, behavior = nil
48+
def self.evaluate_array_rule jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil
4949

5050
push_trace_stack( econs, jcr )
51-
trace( econs, "Evaluating array rule starting at #{slice_to_s(jcr)} against", data )
52-
trace_def( econs, "array", jcr, data )
53-
retval = evaluate_array( jcr, rule_atom, data, econs, behavior )
54-
trace_eval( econs, "Array", retval, jcr, data, "array" )
51+
if behavior
52+
trace( econs, "Evaluating group in array rule starting at #{slice_to_s(jcr)} against", data )
53+
trace_def( econs, "array group", jcr, data )
54+
else
55+
trace( econs, "Evaluating array rule starting at #{slice_to_s(jcr)} against", data )
56+
trace_def( econs, "array", jcr, data )
57+
end
58+
retval = evaluate_array( jcr, rule_atom, data, econs, behavior, target_annotations )
59+
if behavior
60+
trace_eval( econs, "Array group", retval, jcr, data, "array" )
61+
else
62+
trace_eval( econs, "Array", retval, jcr, data, "array" )
63+
end
5564
pop_trace_stack( econs )
5665
return retval
5766

5867
end
5968

60-
def self.evaluate_array jcr, rule_atom, data, econs, behavior = nil
69+
def self.evaluate_array jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil
6170

6271
rules, annotations = get_rules_and_annotations( jcr )
6372

@@ -76,20 +85,24 @@ def self.evaluate_array jcr, rule_atom, data, econs, behavior = nil
7685

7786
# if the data is not an array
7887
return evaluate_not( annotations,
79-
Evaluation.new( false, "#{data} is not an array #{raised_rule(jcr,rule_atom)}"), econs ) unless data.is_a? Array
88+
Evaluation.new( false, "#{data} is not an array #{raised_rule(jcr,rule_atom)}"),
89+
econs, target_annotations ) unless data.is_a? Array
8090

8191
# if the array is zero length and there are zero sub-rules (it is suppose to be empty)
8292
return evaluate_not( annotations,
83-
Evaluation.new( true, nil ), econs ) if rules.empty? && data.empty?
93+
Evaluation.new( true, nil ), econs, target_annotations ) if rules.empty? && data.empty?
8494

8595
# if the array is not empty and there are zero sub-rules (it is suppose to be empty)
8696
return evaluate_not( annotations,
87-
Evaluation.new( false, "Non-empty array for #{raised_rule(jcr,rule_atom)}" ), econs ) if rules.empty? && data.length != 0
97+
Evaluation.new( false, "Non-empty array for #{raised_rule(jcr,rule_atom)}" ),
98+
econs, target_annotations ) if rules.empty? && data.length != 0
8899

89100
if ordered
90-
return evaluate_not( annotations, evaluate_array_rule_ordered( rules, rule_atom, data, econs, behavior ), econs )
101+
return evaluate_not( annotations, evaluate_array_rule_ordered( rules, rule_atom, data, econs, behavior ),
102+
econs, target_annotations )
91103
else
92-
return evaluate_not( annotations, evaluate_array_rule_unordered( rules, rule_atom, data, econs, behavior ), econs )
104+
return evaluate_not( annotations, evaluate_array_rule_unordered( rules, rule_atom, data, econs, behavior ),
105+
econs, target_annotations )
93106
end
94107
end
95108

@@ -115,7 +128,8 @@ def self.evaluate_array_rule_ordered jcr, rule_atom, data, econs, behavior = nil
115128
# groups require the effects of the evaluation to be discarded if they are false
116129
# groups must also be given the entire array
117130

118-
if (grule = get_group(rule, econs))
131+
grule, target_annotations = get_group( rule, econs )
132+
if grule
119133

120134
if repeat_min == 0
121135
retval = Evaluation.new( true, nil )
@@ -126,7 +140,7 @@ def self.evaluate_array_rule_ordered jcr, rule_atom, data, econs, behavior = nil
126140
else
127141
group_behavior = ArrayBehavior.new( behavior )
128142
group_behavior.last_index = array_index
129-
retval = evaluate_rule( grule, rule_atom, data, econs, group_behavior )
143+
retval = evaluate_rule( grule, rule_atom, data, econs, group_behavior, target_annotations )
130144
if retval.success
131145
behavior.checked_hash.merge!( group_behavior.checked_hash )
132146
array_index = group_behavior.last_index
@@ -141,7 +155,7 @@ def self.evaluate_array_rule_ordered jcr, rule_atom, data, econs, behavior = nil
141155
break if array_index == data.length
142156
group_behavior = ArrayBehavior.new( behavior )
143157
group_behavior.last_index = array_index
144-
e = evaluate_rule( grule, rule_atom, data, econs, group_behavior )
158+
e = evaluate_rule( grule, rule_atom, data, econs, group_behavior, target_annotations )
145159
if e.success
146160
behavior.checked_hash.merge!( group_behavior.checked_hash )
147161
array_index = group_behavior.last_index
@@ -187,7 +201,7 @@ def self.evaluate_array_rule_ordered jcr, rule_atom, data, econs, behavior = nil
187201
behavior.last_index = array_index
188202

189203
if data.length > array_index && behavior.extra_prohibited
190-
retval = Evaluation.new( false, "More itmes in array than specified for #{raised_rule(jcr,rule_atom)}" )
204+
retval = Evaluation.new( false, "More items in array (#{data.length}) than specified (#{array_index}) for #{raised_rule(jcr,rule_atom)}" )
191205
end
192206

193207
return retval
@@ -218,14 +232,15 @@ def self.evaluate_array_rule_unordered jcr, rule_atom, data, econs, behavior = n
218232
# groups require the effects of the evaluation to be discarded if they are false
219233
# groups must also be given the entire array
220234

221-
if (grule = get_group(rule, econs))
235+
grule,target_annotations = get_group(rule, econs)
236+
if grule
222237

223238
successes = 0
224239
for i in 0..repeat_max-1
225240
group_behavior = ArrayBehavior.new( behavior )
226241
group_behavior.last_index = highest_index
227242
group_behavior.ordered = false
228-
e = evaluate_rule( grule, rule_atom, data, econs, group_behavior )
243+
e = evaluate_rule( grule, rule_atom, data, econs, group_behavior, target_annotations )
229244
if e.success
230245
highest_index = group_behavior.last_index
231246
behavior.checked_hash.merge!( group_behavior.checked_hash )
@@ -236,13 +251,13 @@ def self.evaluate_array_rule_unordered jcr, rule_atom, data, econs, behavior = n
236251
end
237252

238253
if successes == 0 && repeat_min > 0
239-
retval = Evaluation.new( false, "array does not contain #{rule} for #{raised_rule(jcr,rule_atom)}")
254+
retval = Evaluation.new( false, "array does not contain #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
240255
elsif successes < repeat_min
241-
retval = Evaluation.new( false, "array does not have enough #{rule} for #{raised_rule(jcr,rule_atom)}")
256+
retval = Evaluation.new( false, "array does not have enough #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
242257
elsif successes > repeat_max
243-
retval = Evaluation.new( false, "array has too many #{rule} for #{raised_rule(jcr,rule_atom)}")
258+
retval = Evaluation.new( false, "array has too many #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
244259
elsif repeat_step && ( successes - repeat_min ) % repeat_step != 0
245-
retval = Evaluation.new( false, "array matches (#{successes}) do not meet repetition step of #{repeat_max} % #{repeat_step} with #{rule} for #{raised_rule(jcr,rule_atom)}")
260+
retval = Evaluation.new( false, "array matches (#{successes}) do not meet repetition step of #{repeat_max} % #{repeat_step} with #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
246261
else
247262
retval = Evaluation.new( true, nil )
248263
end
@@ -263,13 +278,13 @@ def self.evaluate_array_rule_unordered jcr, rule_atom, data, econs, behavior = n
263278
end
264279

265280
if successes == 0 && repeat_min > 0
266-
retval = Evaluation.new( false, "array does not contain #{rule} for #{raised_rule(jcr,rule_atom)}")
281+
retval = Evaluation.new( false, "array does not contain #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
267282
elsif successes < repeat_min
268-
retval = Evaluation.new( false, "array does not have enough #{rule} for #{raised_rule(jcr,rule_atom)}")
283+
retval = Evaluation.new( false, "array does not have enough #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
269284
elsif successes > repeat_max
270-
retval = Evaluation.new( false, "array has too many #{rule} for #{raised_rule(jcr,rule_atom)}")
285+
retval = Evaluation.new( false, "array has too many #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
271286
elsif repeat_step && ( successes - repeat_min ) % repeat_step != 0
272-
retval = Evaluation.new( false, "array matches (#{successes}) do not meet repetition step of #{repeat_max} % #{repeat_step} with #{rule} for #{raised_rule(jcr,rule_atom)}")
287+
retval = Evaluation.new( false, "array matches (#{successes}) do not meet repetition step of #{repeat_max} % #{repeat_step} with #{jcr_to_s(rule)} for #{raised_rule(jcr,rule_atom)}")
273288
else
274289
retval = Evaluation.new( true, nil)
275290
end
@@ -281,7 +296,7 @@ def self.evaluate_array_rule_unordered jcr, rule_atom, data, econs, behavior = n
281296
behavior.last_index = highest_index
282297

283298
if data.length > behavior.checked_hash.length && behavior.extra_prohibited
284-
retval = Evaluation.new( false, "More itmes in array than specified for #{raised_rule(jcr,rule_atom)}" )
299+
retval = Evaluation.new( false, "More items in array than specified for #{raised_rule(jcr,rule_atom)}" )
285300
end
286301

287302
return retval

lib/jcr/evaluate_group_rules.rb

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -26,34 +26,34 @@
2626

2727
module JCR
2828

29-
def self.evaluate_group_rule jcr, rule_atom, data, econs, behavior = nil
29+
def self.evaluate_group_rule jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil
3030

3131
push_trace_stack( econs, jcr )
3232
trace( econs, "Evaluating group rule against ", data )
3333
trace_def( econs, "group", jcr, data )
34-
retval = evaluate_group( jcr, rule_atom, data, econs, behavior )
34+
retval = evaluate_group( jcr, rule_atom, data, econs, behavior, target_annotations )
3535
trace_eval( econs, "Group", retval, jcr, data, "group" )
3636
pop_trace_stack( econs )
3737
return retval
3838

3939
end
4040

41-
def self.evaluate_group jcr, rule_atom, data, econs, behavior = nil
41+
def self.evaluate_group jcr, rule_atom, data, econs, behavior = nil, target_annotations = nil
4242

4343
rules, annotations = get_rules_and_annotations( jcr )
4444

4545
retval = nil
4646

4747
rules.each do |rule|
4848
if rule[:choice_combiner] && retval && retval.success
49-
return evaluate_not( annotations, retval, econs ) # short circuit
49+
return evaluate_not( annotations, retval, econs, target_annotations ) # short circuit
5050
elsif rule[:sequence_combiner] && retval && !retval.success
51-
return evaluate_not( annotations, retval, econs ) # short circuit
51+
return evaluate_not( annotations, retval, econs, target_annotations ) # short circuit
5252
end
5353
retval = evaluate_rule( rule, rule_atom, data, econs, behavior )
5454
end
5555

56-
return evaluate_not( annotations, retval, econs )
56+
return evaluate_not( annotations, retval, econs, target_annotations )
5757
end
5858

5959
def self.group_to_s( jcr, shallow=true)

lib/jcr/evaluate_member_rules.rb

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -25,19 +25,19 @@
2525

2626
module JCR
2727

28-
def self.evaluate_member_rule jcr, rule_atom, data, econs
28+
def self.evaluate_member_rule jcr, rule_atom, data, econs, behavior, target_annotations
2929

3030
push_trace_stack( econs, jcr )
3131
trace( econs, "Evaluating member rule for key '#{data[0]}' starting at #{slice_to_s(jcr)} against ", data[1])
3232
trace_def( econs, "member", jcr, data )
33-
retval = evaluate_member( jcr, rule_atom, data, econs )
33+
retval = evaluate_member( jcr, rule_atom, data, econs, behavior, target_annotations )
3434
trace_eval( econs, "Member", retval, jcr, data, "member" )
3535
pop_trace_stack( econs )
3636
return retval
3737

3838
end
3939

40-
def self.evaluate_member jcr, rule_atom, data, econs
40+
def self.evaluate_member jcr, rule_atom, data, econs, behavior, target_annotations
4141

4242
# unlike the other evaluate functions, here data is not just the json data.
4343
# it is an array, the first element being the member name or regex and the
@@ -68,13 +68,14 @@ def self.evaluate_member jcr, rule_atom, data, econs
6868
end
6969

7070
if member_match
71-
e = evaluate_rule( rule, rule_atom, data[ 1 ], econs )
71+
e = evaluate_rule( rule, rule_atom, data[ 1 ], econs, nil, target_annotations )
7272
e.member_found = true
73-
return evaluate_not( annotations, e, econs )
73+
return evaluate_not( annotations, e, econs, target_annotations )
7474
end
7575

7676
return evaluate_not( annotations,
77-
Evaluation.new( false, "#{match_spec} does not match #{data[0]} for #{raised_rule( jcr, rule_atom)}" ), econs )
77+
Evaluation.new( false, "#{match_spec} does not match #{data[0]} for #{raised_rule( jcr, rule_atom)}" ),
78+
econs, target_annotations )
7879

7980
end
8081

0 commit comments

Comments
 (0)