jcrvalidator 0.5.3 → 0.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/jcr/check_groups.rb +1 -3
- data/lib/jcr/evaluate_array_rules.rb +44 -20
- data/lib/jcr/evaluate_group_rules.rb +21 -3
- data/lib/jcr/evaluate_member_rules.rb +32 -3
- data/lib/jcr/evaluate_object_rules.rb +74 -20
- data/lib/jcr/evaluate_rules.rb +207 -10
- data/lib/jcr/evaluate_value_rules.rb +256 -19
- data/lib/jcr/jcr.rb +54 -27
- data/lib/jcr/parser.rb +170 -110
- metadata +2 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0e68e95dd86cf0ba170eae8a3ead3acb7c44ab59
|
4
|
+
data.tar.gz: fe3a8c25bf2e420c43db8c32f33e764f7356d766
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6d8a19a053ff78eeb76b2b46ee0c48be126465a80825737e87881cbdf4c9f7e4e1b9dae9c15b0768ddb27f091f4196e761f44ab2c65cc19a19a86288bbdb8d51
|
7
|
+
data.tar.gz: ba031e433185f9857056a62759caee2d7edf396cc6067d35e1bd4d3114c9dc9b27985f0bc0a299bd2128095739f0b48724afdda750e14dad575040cdb78a7a0e
|
data/lib/jcr/check_groups.rb
CHANGED
@@ -27,8 +27,6 @@ module JCR
|
|
27
27
|
check_groups( tree[:rule], mapping )
|
28
28
|
elsif tree[:primitive_rule]
|
29
29
|
check_value_for_group( tree[:primitive_rule], mapping )
|
30
|
-
elsif tree[:type_choice_signifier]
|
31
|
-
check_value_for_group( tree, mapping )
|
32
30
|
elsif tree[:member_rule]
|
33
31
|
check_member_for_group( tree[:member_rule], mapping )
|
34
32
|
elsif tree[:array_rule]
|
@@ -40,7 +38,7 @@ module JCR
|
|
40
38
|
end
|
41
39
|
|
42
40
|
def self.check_value_for_group node, mapping
|
43
|
-
if node[:group_rule]
|
41
|
+
if node.is_a?( Hash ) && node[:group_rule]
|
44
42
|
disallowed_group_in_value?( node[:group_rule], mapping )
|
45
43
|
end
|
46
44
|
end
|
@@ -47,6 +47,18 @@ module JCR
|
|
47
47
|
|
48
48
|
def self.evaluate_array_rule jcr, rule_atom, data, econs, behavior = nil
|
49
49
|
|
50
|
+
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 )
|
55
|
+
pop_trace_stack( econs )
|
56
|
+
return retval
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def self.evaluate_array jcr, rule_atom, data, econs, behavior = nil
|
61
|
+
|
50
62
|
rules, annotations = get_rules_and_annotations( jcr )
|
51
63
|
|
52
64
|
ordered = true
|
@@ -63,21 +75,21 @@ module JCR
|
|
63
75
|
end
|
64
76
|
|
65
77
|
# if the data is not an array
|
66
|
-
return
|
67
|
-
Evaluation.new( false, "#{data} is not an array
|
78
|
+
return evaluate_not( annotations,
|
79
|
+
Evaluation.new( false, "#{data} is not an array #{raised_rule(jcr,rule_atom)}"), econs ) unless data.is_a? Array
|
68
80
|
|
69
81
|
# if the array is zero length and there are zero sub-rules (it is suppose to be empty)
|
70
|
-
return
|
71
|
-
Evaluation.new( true, nil ) ) if rules.empty? && data.empty?
|
82
|
+
return evaluate_not( annotations,
|
83
|
+
Evaluation.new( true, nil ), econs ) if rules.empty? && data.empty?
|
72
84
|
|
73
85
|
# if the array is not empty and there are zero sub-rules (it is suppose to be empty)
|
74
|
-
return
|
75
|
-
Evaluation.new( false, "Non-empty array
|
86
|
+
return evaluate_not( annotations,
|
87
|
+
Evaluation.new( false, "Non-empty array for #{raised_rule(jcr,rule_atom)}" ), econs ) if rules.empty? && data.length != 0
|
76
88
|
|
77
89
|
if ordered
|
78
|
-
return
|
90
|
+
return evaluate_not( annotations, evaluate_array_rule_ordered( rules, rule_atom, data, econs, behavior ), econs )
|
79
91
|
else
|
80
|
-
return
|
92
|
+
return evaluate_not( annotations, evaluate_array_rule_unordered( rules, rule_atom, data, econs, behavior ), econs )
|
81
93
|
end
|
82
94
|
end
|
83
95
|
|
@@ -97,7 +109,7 @@ module JCR
|
|
97
109
|
break
|
98
110
|
end
|
99
111
|
|
100
|
-
repeat_min, repeat_max = get_repetitions( rule )
|
112
|
+
repeat_min, repeat_max, repeat_step = get_repetitions( rule, econs )
|
101
113
|
|
102
114
|
# group rules must be evaluated differently
|
103
115
|
# groups require the effects of the evaluation to be discarded if they are false
|
@@ -110,7 +122,7 @@ module JCR
|
|
110
122
|
else
|
111
123
|
for i in 1..repeat_min do
|
112
124
|
if array_index == data.length
|
113
|
-
return Evaluation.new( false, "array is not large enough for #{jcr
|
125
|
+
return Evaluation.new( false, "array is not large enough for #{raised_rule(jcr,rule_atom)}" )
|
114
126
|
else
|
115
127
|
group_behavior = ArrayBehavior.new( behavior )
|
116
128
|
group_behavior.last_index = array_index
|
@@ -146,7 +158,7 @@ module JCR
|
|
146
158
|
else
|
147
159
|
for i in 1..repeat_min do
|
148
160
|
if array_index == data.length
|
149
|
-
return Evaluation.new( false, "array is not large enough for #{jcr
|
161
|
+
return Evaluation.new( false, "array is not large enough for #{raised_rule(jcr,rule_atom)}" )
|
150
162
|
else
|
151
163
|
retval = evaluate_rule( rule, rule_atom, data[ array_index ], econs, nil )
|
152
164
|
break unless retval.success
|
@@ -166,12 +178,16 @@ module JCR
|
|
166
178
|
|
167
179
|
end # end if grule else
|
168
180
|
|
181
|
+
if repeat_step && array_index % repeat_step != 0
|
182
|
+
retval = Evaluation.new( false, "Matches (#{array_index }) do not meat repetition step for #{repeat_max} % #{repeat_step}")
|
183
|
+
end
|
184
|
+
|
169
185
|
end
|
170
186
|
|
171
187
|
behavior.last_index = array_index
|
172
188
|
|
173
189
|
if data.length > array_index && behavior.extra_prohibited
|
174
|
-
retval = Evaluation.new( false, "More itmes in array than specified for #{jcr
|
190
|
+
retval = Evaluation.new( false, "More itmes in array than specified for #{raised_rule(jcr,rule_atom)}" )
|
175
191
|
end
|
176
192
|
|
177
193
|
return retval
|
@@ -196,7 +212,7 @@ module JCR
|
|
196
212
|
break
|
197
213
|
end
|
198
214
|
|
199
|
-
repeat_min, repeat_max = get_repetitions( rule )
|
215
|
+
repeat_min, repeat_max, repeat_step = get_repetitions( rule, econs )
|
200
216
|
|
201
217
|
# group rules must be evaluated differently
|
202
218
|
# groups require the effects of the evaluation to be discarded if they are false
|
@@ -220,11 +236,13 @@ module JCR
|
|
220
236
|
end
|
221
237
|
|
222
238
|
if successes == 0 && repeat_min > 0
|
223
|
-
retval = Evaluation.new( false, "array does not contain #{rule} for #{jcr
|
239
|
+
retval = Evaluation.new( false, "array does not contain #{rule} for #{raised_rule(jcr,rule_atom)}")
|
224
240
|
elsif successes < repeat_min
|
225
|
-
retval = Evaluation.new( false, "array does not have enough #{rule} for #{jcr
|
241
|
+
retval = Evaluation.new( false, "array does not have enough #{rule} for #{raised_rule(jcr,rule_atom)}")
|
226
242
|
elsif successes > repeat_max
|
227
|
-
retval = Evaluation.new( false, "array has too many #{rule} for #{jcr
|
243
|
+
retval = Evaluation.new( false, "array has too many #{rule} for #{raised_rule(jcr,rule_atom)}")
|
244
|
+
elsif repeat_step && successes % 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)}")
|
228
246
|
else
|
229
247
|
retval = Evaluation.new( true, nil )
|
230
248
|
end
|
@@ -245,11 +263,13 @@ module JCR
|
|
245
263
|
end
|
246
264
|
|
247
265
|
if successes == 0 && repeat_min > 0
|
248
|
-
retval = Evaluation.new( false, "array does not contain #{rule} for #{jcr
|
266
|
+
retval = Evaluation.new( false, "array does not contain #{rule} for #{raised_rule(jcr,rule_atom)}")
|
249
267
|
elsif successes < repeat_min
|
250
|
-
retval = Evaluation.new( false, "array does not have enough #{rule} for #{jcr
|
268
|
+
retval = Evaluation.new( false, "array does not have enough #{rule} for #{raised_rule(jcr,rule_atom)}")
|
251
269
|
elsif successes > repeat_max
|
252
|
-
retval = Evaluation.new( false, "array has too many #{rule} for #{jcr
|
270
|
+
retval = Evaluation.new( false, "array has too many #{rule} for #{raised_rule(jcr,rule_atom)}")
|
271
|
+
elsif repeat_step && successes % 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)}")
|
253
273
|
else
|
254
274
|
retval = Evaluation.new( true, nil)
|
255
275
|
end
|
@@ -261,10 +281,14 @@ module JCR
|
|
261
281
|
behavior.last_index = highest_index
|
262
282
|
|
263
283
|
if data.length > behavior.checked_hash.length && behavior.extra_prohibited
|
264
|
-
retval = Evaluation.new( false, "More itmes in array than specified for #{jcr
|
284
|
+
retval = Evaluation.new( false, "More itmes in array than specified for #{raised_rule(jcr,rule_atom)}" )
|
265
285
|
end
|
266
286
|
|
267
287
|
return retval
|
268
288
|
end
|
269
289
|
|
290
|
+
def self.array_to_s( jcr, shallow=true )
|
291
|
+
rules, annotations = get_rules_and_annotations( jcr )
|
292
|
+
return "#{annotations_to_s( annotations)} [ #{rules_to_s( rules, shallow )} ]"
|
293
|
+
end
|
270
294
|
end
|
@@ -22,25 +22,43 @@ require 'big-phoney'
|
|
22
22
|
require 'jcr/parser'
|
23
23
|
require 'jcr/map_rule_names'
|
24
24
|
require 'jcr/check_groups'
|
25
|
+
require 'jcr/evaluate_rules'
|
25
26
|
|
26
27
|
module JCR
|
27
28
|
|
28
29
|
def self.evaluate_group_rule jcr, rule_atom, data, econs, behavior = nil
|
29
30
|
|
31
|
+
push_trace_stack( econs, jcr )
|
32
|
+
trace( econs, "Evaluating group rule against ", data )
|
33
|
+
trace_def( econs, "group", jcr, data )
|
34
|
+
retval = evaluate_group( jcr, rule_atom, data, econs, behavior )
|
35
|
+
trace_eval( econs, "Group", retval )
|
36
|
+
pop_trace_stack( econs )
|
37
|
+
return retval
|
38
|
+
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.evaluate_group jcr, rule_atom, data, econs, behavior = nil
|
42
|
+
|
30
43
|
rules, annotations = get_rules_and_annotations( jcr )
|
31
44
|
|
32
45
|
retval = nil
|
33
46
|
|
34
47
|
rules.each do |rule|
|
35
48
|
if rule[:choice_combiner] && retval && retval.success
|
36
|
-
return
|
49
|
+
return evaluate_not( annotations, retval, econs ) # short circuit
|
37
50
|
elsif rule[:sequence_combiner] && retval && !retval.success
|
38
|
-
return
|
51
|
+
return evaluate_not( annotations, retval, econs ) # short circuit
|
39
52
|
end
|
40
53
|
retval = evaluate_rule( rule, rule_atom, data, econs, behavior )
|
41
54
|
end
|
42
55
|
|
43
|
-
return
|
56
|
+
return evaluate_not( annotations, retval, econs )
|
57
|
+
end
|
58
|
+
|
59
|
+
def self.group_to_s( jcr, shallow=true)
|
60
|
+
rules, annotations = get_rules_and_annotations( jcr )
|
61
|
+
return "#{annotations_to_s( annotations)} ( #{rules_to_s(rules,shallow)} )"
|
44
62
|
end
|
45
63
|
|
46
64
|
end
|
@@ -27,10 +27,23 @@ module JCR
|
|
27
27
|
|
28
28
|
def self.evaluate_member_rule jcr, rule_atom, data, econs
|
29
29
|
|
30
|
+
push_trace_stack( econs, jcr )
|
31
|
+
trace( econs, "Evaluating member rule for key '#{data[0]}' starting at #{slice_to_s(jcr)} against ", data[1])
|
32
|
+
trace_def( econs, "member", jcr, data )
|
33
|
+
retval = evaluate_member( jcr, rule_atom, data, econs )
|
34
|
+
trace_eval( econs, "Member", retval )
|
35
|
+
pop_trace_stack( econs )
|
36
|
+
return retval
|
37
|
+
|
38
|
+
end
|
39
|
+
|
40
|
+
def self.evaluate_member jcr, rule_atom, data, econs
|
41
|
+
|
30
42
|
# unlike the other evaluate functions, here data is not just the json data.
|
31
43
|
# it is an array, the first element being the member name or regex and the
|
32
44
|
# second being the json data to be furthered on to other evaluation functions
|
33
45
|
|
46
|
+
|
34
47
|
rules, annotations = get_rules_and_annotations( jcr )
|
35
48
|
rule = rules[0]
|
36
49
|
|
@@ -50,12 +63,28 @@ module JCR
|
|
50
63
|
|
51
64
|
if member_match
|
52
65
|
e = evaluate_rule( rule, rule_atom, data[ 1 ], econs )
|
53
|
-
return
|
66
|
+
return evaluate_not( annotations, e, econs )
|
54
67
|
end
|
55
68
|
|
56
|
-
return
|
57
|
-
Evaluation.new( false, "#{match_spec} does not match #{data[0]} for #{jcr
|
69
|
+
return evaluate_not( annotations,
|
70
|
+
Evaluation.new( false, "#{match_spec} does not match #{data[0]} for #{raised_rule( jcr, rule_atom)}" ), econs )
|
58
71
|
|
59
72
|
end
|
60
73
|
|
74
|
+
def self.member_to_s( jcr, shallow=true )
|
75
|
+
rules, annotations = get_rules_and_annotations( jcr )
|
76
|
+
retval = ""
|
77
|
+
rule = rules[ 0 ]
|
78
|
+
case
|
79
|
+
when rule[:member_name]
|
80
|
+
retval = %Q|"#{rule[:member_name][:q_string].to_s}"|
|
81
|
+
when rule[:member_regex]
|
82
|
+
retval = "/#{rule[:member_regex][:regex].to_s}/"
|
83
|
+
else
|
84
|
+
retval = "** unknown member rule **"
|
85
|
+
end
|
86
|
+
retval = retval + " : " + rule_to_s( rule, shallow )
|
87
|
+
return annotations_to_s( annotations ) + retval
|
88
|
+
end
|
89
|
+
|
61
90
|
end
|
@@ -29,19 +29,31 @@ module JCR
|
|
29
29
|
|
30
30
|
def self.evaluate_object_rule jcr, rule_atom, data, econs, behavior = nil
|
31
31
|
|
32
|
+
push_trace_stack( econs, jcr )
|
33
|
+
trace( econs, "Evaluating object rule starting at #{slice_to_s(jcr)} against", data )
|
34
|
+
trace_def( econs, "object", jcr, data )
|
35
|
+
retval = evaluate_object( jcr, rule_atom, data, econs, behavior )
|
36
|
+
trace_eval( econs, "Object", retval )
|
37
|
+
pop_trace_stack( econs )
|
38
|
+
return retval
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
def self.evaluate_object jcr, rule_atom, data, econs, behavior = nil
|
43
|
+
|
32
44
|
rules, annotations = get_rules_and_annotations( jcr )
|
33
45
|
|
34
46
|
# if the data is not an object (Hash)
|
35
|
-
return
|
36
|
-
Evaluation.new( false, "#{data} is not an object
|
47
|
+
return evaluate_not( annotations,
|
48
|
+
Evaluation.new( false, "#{data} is not an object for #{raised_rule(jcr,rule_atom)}"), econs ) unless data.is_a? Hash
|
37
49
|
|
38
50
|
# if the object has no members and there are zero sub-rules (it is suppose to be empty)
|
39
|
-
return
|
40
|
-
Evaluation.new( true, nil ) ) if rules.empty? && data.length == 0
|
51
|
+
return evaluate_not( annotations,
|
52
|
+
Evaluation.new( true, nil ), econs ) if rules.empty? && data.length == 0
|
41
53
|
|
42
54
|
# if the object has members and there are zero sub-rules (it is suppose to be empty)
|
43
|
-
return
|
44
|
-
Evaluation.new( false, "Non-empty object
|
55
|
+
return evaluate_not( annotations,
|
56
|
+
Evaluation.new( false, "Non-empty object for #{raised_rule(jcr,rule_atom)}" ), econs ) if rules.empty? && data.length != 0
|
45
57
|
|
46
58
|
retval = nil
|
47
59
|
behavior = ObjectBehavior.new unless behavior
|
@@ -52,10 +64,10 @@ module JCR
|
|
52
64
|
if rule[:choice_combiner] && retval && retval.success
|
53
65
|
next
|
54
66
|
elsif rule[:sequence_combiner] && retval && !retval.success
|
55
|
-
return
|
67
|
+
return evaluate_not( annotations, retval, econs ) # short circuit
|
56
68
|
end
|
57
69
|
|
58
|
-
repeat_min, repeat_max = get_repetitions( rule )
|
70
|
+
repeat_min, repeat_max, repeat_step = get_repetitions( rule, econs )
|
59
71
|
|
60
72
|
# Pay attention here:
|
61
73
|
# Group rules need to be treated differently than other rules
|
@@ -67,8 +79,9 @@ module JCR
|
|
67
79
|
if (grule = get_group(rule, econs))
|
68
80
|
|
69
81
|
successes = 0
|
70
|
-
for i in 0..repeat_max
|
82
|
+
for i in 0..repeat_max-1
|
71
83
|
group_behavior = ObjectBehavior.new
|
84
|
+
group_behavior.checked_hash.merge!( behavior.checked_hash )
|
72
85
|
e = evaluate_rule( grule, rule_atom, data, econs, group_behavior )
|
73
86
|
if e.success
|
74
87
|
behavior.checked_hash.merge!( group_behavior.checked_hash )
|
@@ -79,29 +92,66 @@ module JCR
|
|
79
92
|
end
|
80
93
|
|
81
94
|
if successes == 0 && repeat_min > 0
|
82
|
-
retval = Evaluation.new( false, "object does not contain group #{rule} for #{jcr
|
95
|
+
retval = Evaluation.new( false, "object does not contain group #{rule} for #{raised_rule(jcr,rule_atom)}")
|
83
96
|
elsif successes < repeat_min
|
84
|
-
retval = Evaluation.new( false, "object does not have contain necessary number of group #{rule} for #{jcr
|
97
|
+
retval = Evaluation.new( false, "object does not have contain necessary number of group #{rule} for #{raised_rule(jcr,rule_atom)}")
|
98
|
+
elsif repeat_step && successes % repeat_step != 0
|
99
|
+
retval = Evaluation.new( false, "object matches (#{successes}) do not have contain repetition #{repeat_max} % #{repeat_step} of group #{rule} for #{raised_rule(jcr,rule_atom)}")
|
85
100
|
else
|
86
101
|
retval = Evaluation.new( true, nil )
|
87
102
|
end
|
88
103
|
|
89
104
|
else # if not grule
|
90
105
|
|
91
|
-
repeat_results =
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
106
|
+
repeat_results = nil
|
107
|
+
|
108
|
+
# do a little lookahead for member rules defined by names
|
109
|
+
# if defined by a name, and not a regex, just pluck it from the object
|
110
|
+
# and short-circuit the enumeration
|
111
|
+
|
112
|
+
lookahead = get_leaf_rule( rule, econs )
|
113
|
+
lrules, lannotations = get_rules_and_annotations( lookahead[:member_rule] )
|
114
|
+
if lrules[0][:member_name]
|
115
|
+
|
116
|
+
repeat_results = {}
|
117
|
+
k = lrules[0][:member_name][:q_string].to_s
|
118
|
+
v = data[k]
|
119
|
+
if v
|
120
|
+
unless behavior.checked_hash[k]
|
121
|
+
e = evaluate_rule(rule, rule_atom, [k, v], econs, nil)
|
122
|
+
behavior.checked_hash[k] = e.success
|
123
|
+
repeat_results[ k ] = v if e.success
|
124
|
+
end
|
125
|
+
else
|
126
|
+
trace( econs, "No member '#{k}' found in object.")
|
127
|
+
end
|
128
|
+
|
129
|
+
else
|
130
|
+
|
131
|
+
trace( econs, "Scanning object.")
|
132
|
+
i = 0
|
133
|
+
repeat_results = data.select do |k,v|
|
134
|
+
unless behavior.checked_hash[k]
|
135
|
+
if i < repeat_max
|
136
|
+
e = evaluate_rule(rule, rule_atom, [k, v], econs, nil)
|
137
|
+
behavior.checked_hash[k] = e.success
|
138
|
+
i = i + 1 if e.success
|
139
|
+
e.success
|
140
|
+
end
|
141
|
+
end
|
96
142
|
end
|
143
|
+
|
97
144
|
end
|
98
145
|
|
146
|
+
trace( econs, "Found #{repeat_results.length} matching members repetitions in object with min #{repeat_min} and max #{repeat_max}" )
|
99
147
|
if repeat_results.length == 0 && repeat_min > 0
|
100
|
-
retval = Evaluation.new( false, "object does not contain #{rule} for #{jcr
|
148
|
+
retval = Evaluation.new( false, "object does not contain #{rule} for #{raised_rule(jcr,rule_atom)}")
|
101
149
|
elsif repeat_results.length < repeat_min
|
102
|
-
retval = Evaluation.new( false, "object does not have enough #{rule} for #{jcr
|
150
|
+
retval = Evaluation.new( false, "object does not have enough #{rule} for #{raised_rule(jcr,rule_atom)}")
|
103
151
|
elsif repeat_results.length > repeat_max
|
104
|
-
retval = Evaluation.new( false, "object has too many #{rule} for #{jcr
|
152
|
+
retval = Evaluation.new( false, "object has too many #{rule} for #{raised_rule(jcr,rule_atom)}")
|
153
|
+
elsif repeat_step && repeat_results.length % repeat_step != 0
|
154
|
+
retval = Evaluation.new( false, "object matches (#{repeat_results.length}) does not match repetition step of #{repeat_max} & #{repeat_step} for #{rule} for #{raised_rule(jcr,rule_atom)}")
|
105
155
|
else
|
106
156
|
retval = Evaluation.new( true, nil)
|
107
157
|
end
|
@@ -109,7 +159,11 @@ module JCR
|
|
109
159
|
|
110
160
|
end # end if grule else
|
111
161
|
|
112
|
-
return
|
162
|
+
return evaluate_not( annotations, retval, econs )
|
113
163
|
end
|
114
164
|
|
165
|
+
def self.object_to_s( jcr, shallow=true )
|
166
|
+
rules, annotations = get_rules_and_annotations( jcr )
|
167
|
+
return "#{annotations_to_s( annotations)} { #{rules_to_s(rules,shallow)} }"
|
168
|
+
end
|
115
169
|
end
|
data/lib/jcr/evaluate_rules.rb
CHANGED
@@ -14,6 +14,7 @@
|
|
14
14
|
|
15
15
|
require 'ipaddr'
|
16
16
|
require 'time'
|
17
|
+
require 'pp'
|
17
18
|
require 'addressable/uri'
|
18
19
|
require 'addressable/template'
|
19
20
|
require 'email_address_validator'
|
@@ -52,9 +53,11 @@ module JCR
|
|
52
53
|
end
|
53
54
|
|
54
55
|
class EvalConditions
|
55
|
-
attr_accessor :mapping, :callbacks
|
56
|
-
def initialize mapping, callbacks
|
56
|
+
attr_accessor :mapping, :callbacks, :trace, :trace_stack
|
57
|
+
def initialize mapping, callbacks, trace = false
|
57
58
|
@mapping = mapping
|
59
|
+
@trace = trace
|
60
|
+
@trace_stack = []
|
58
61
|
if callbacks
|
59
62
|
@callbacks = callbacks
|
60
63
|
else
|
@@ -64,6 +67,13 @@ module JCR
|
|
64
67
|
end
|
65
68
|
|
66
69
|
def self.evaluate_rule jcr, rule_atom, data, econs, behavior = nil
|
70
|
+
if jcr.is_a?( Hash )
|
71
|
+
if jcr[:rule_name]
|
72
|
+
rn = slice_to_s( jcr[:rule_name] )
|
73
|
+
trace( econs, "Named Rule: #{rn}" )
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
67
77
|
retval = Evaluation.new( false, "failed to evaluate rule properly" )
|
68
78
|
case
|
69
79
|
when behavior.is_a?( ArrayBehavior )
|
@@ -75,6 +85,7 @@ module JCR
|
|
75
85
|
when jcr[:target_rule_name]
|
76
86
|
target = econs.mapping[ jcr[:target_rule_name][:rule_name].to_s ]
|
77
87
|
raise "Target rule not in mapping. This should have been checked earlier." unless target
|
88
|
+
trace( econs, "Referencing target rule #{slice_to_s(target)} from #{slice_to_s( jcr[:target_rule_name][:rule_name] )}" )
|
78
89
|
retval = evaluate_rule( target, target, data, econs, behavior )
|
79
90
|
when jcr[:primitive_rule]
|
80
91
|
retval = evaluate_value_rule( jcr[:primitive_rule], rule_atom, data, econs)
|
@@ -113,19 +124,26 @@ module JCR
|
|
113
124
|
elsif retval.is_a? String
|
114
125
|
retval = Evaluation.new( false, retval )
|
115
126
|
end
|
127
|
+
trace( econs, "Callback #{callback} given evaluation of #{e.success} and returned #{retval}")
|
116
128
|
return retval
|
117
129
|
end
|
118
130
|
|
119
|
-
def self.get_repetitions rule
|
131
|
+
def self.get_repetitions rule, econs
|
120
132
|
|
121
133
|
repeat_min = 1
|
122
134
|
repeat_max = 1
|
135
|
+
repeat_step = nil
|
123
136
|
if rule[:optional]
|
124
137
|
repeat_min = 0
|
125
138
|
repeat_max = 1
|
126
139
|
elsif rule[:one_or_more]
|
127
140
|
repeat_min = 1
|
128
141
|
repeat_max = Float::INFINITY
|
142
|
+
repeat_step = rule[:repetition_step].to_s.to_i if rule[:repetition_step]
|
143
|
+
elsif rule[:zero_or_more]
|
144
|
+
repeat_min = 0
|
145
|
+
repeat_max = Float::INFINITY
|
146
|
+
repeat_step = rule[:repetition_step].to_s.to_i if rule[:repetition_step]
|
129
147
|
elsif rule[:specific_repetition] && rule[:specific_repetition].is_a?( Parslet::Slice )
|
130
148
|
repeat_min = repeat_max = rule[:specific_repetition].to_s.to_i
|
131
149
|
else
|
@@ -146,9 +164,16 @@ module JCR
|
|
146
164
|
repeat_max = o.to_s.to_i
|
147
165
|
end
|
148
166
|
end
|
167
|
+
o = rule[:repetition_step]
|
168
|
+
if o
|
169
|
+
if o.is_a?( Parslet::Slice )
|
170
|
+
repeat_step = o.to_s.to_i
|
171
|
+
end
|
172
|
+
end
|
149
173
|
end
|
150
174
|
|
151
|
-
|
175
|
+
trace( econs, "rule repetition min = #{repeat_min} max = #{repeat_max} repetition step = #{repeat_step}" )
|
176
|
+
return repeat_min, repeat_max, repeat_step
|
152
177
|
end
|
153
178
|
|
154
179
|
def self.get_rules_and_annotations jcr
|
@@ -166,7 +191,7 @@ module JCR
|
|
166
191
|
when sub[:unordered_annotation]
|
167
192
|
annotations << sub
|
168
193
|
i = i + 1
|
169
|
-
when sub[:
|
194
|
+
when sub[:not_annotation]
|
170
195
|
annotations << sub
|
171
196
|
i = i + 1
|
172
197
|
when sub[:root_annotation]
|
@@ -182,16 +207,17 @@ module JCR
|
|
182
207
|
return rules, annotations
|
183
208
|
end
|
184
209
|
|
185
|
-
def self.
|
186
|
-
|
210
|
+
def self.evaluate_not annotations, evaluation, econs
|
211
|
+
is_not = false
|
187
212
|
annotations.each do |a|
|
188
|
-
if a[:
|
189
|
-
|
213
|
+
if a[:not_annotation]
|
214
|
+
is_not = true
|
190
215
|
break
|
191
216
|
end
|
192
217
|
end
|
193
218
|
|
194
|
-
if
|
219
|
+
if is_not
|
220
|
+
trace( econs, "Not annotation changing result from #{evaluation.success} to #{!evaluation.success}")
|
195
221
|
evaluation.success = !evaluation.success
|
196
222
|
end
|
197
223
|
return evaluation
|
@@ -203,9 +229,180 @@ module JCR
|
|
203
229
|
if rule[:target_rule_name]
|
204
230
|
target = econs.mapping[ rule[:target_rule_name][:rule_name].to_s ]
|
205
231
|
raise "Target rule not in mapping. This should have been checked earlier." unless target
|
232
|
+
trace( econs, "Referencing target rule #{slice_to_s(target)} from #{slice_to_s( rule[:target_rule_name][:rule_name] )}" )
|
206
233
|
return get_group( target, econs )
|
207
234
|
end
|
208
235
|
#else
|
209
236
|
return false
|
210
237
|
end
|
238
|
+
|
239
|
+
def self.get_leaf_rule rule, econs
|
240
|
+
if rule[:target_rule_name ]
|
241
|
+
target = econs.mapping[ rule[:target_rule_name][:rule_name].to_s ]
|
242
|
+
raise "Target rule not in mapping. This should have been checked earlier." unless target
|
243
|
+
trace( econs, "Referencing target rule #{slice_to_s(target)} from #{slice_to_s( rule[:target_rule_name][:rule_name] )}" )
|
244
|
+
return target
|
245
|
+
end
|
246
|
+
#else
|
247
|
+
return rule
|
248
|
+
end
|
249
|
+
|
250
|
+
def self.push_trace_stack econs, jcr
|
251
|
+
econs.trace_stack.push( find_first_slice( jcr ) )
|
252
|
+
end
|
253
|
+
|
254
|
+
def self.pop_trace_stack econs
|
255
|
+
econs.trace_stack.pop
|
256
|
+
end
|
257
|
+
|
258
|
+
def self.elide s
|
259
|
+
if s.length > 60
|
260
|
+
s = s[0..56]
|
261
|
+
s = s + " ..."
|
262
|
+
end
|
263
|
+
return s
|
264
|
+
end
|
265
|
+
|
266
|
+
def self.trace econs, message, data = nil
|
267
|
+
if econs.trace
|
268
|
+
if data
|
269
|
+
if data.is_a? String
|
270
|
+
s = '"' + data + '"'
|
271
|
+
else
|
272
|
+
s = data.pretty_print_inspect
|
273
|
+
end
|
274
|
+
message = "#{message} data: #{elide(s)}"
|
275
|
+
end
|
276
|
+
last = econs.trace_stack.last
|
277
|
+
pos = "#{last.line_and_column}@#{last.offset}" if last
|
278
|
+
puts "[ #{econs.trace_stack.length}:#{pos} ] #{message}"
|
279
|
+
end
|
280
|
+
end
|
281
|
+
|
282
|
+
def self.trace_def econs, type, jcr, data
|
283
|
+
if econs.trace
|
284
|
+
s = ""
|
285
|
+
case type
|
286
|
+
when "value"
|
287
|
+
s = elide( value_to_s( jcr ) )
|
288
|
+
when "member"
|
289
|
+
s = elide( member_to_s( jcr ) )
|
290
|
+
when "object"
|
291
|
+
s = elide( object_to_s( jcr ) )
|
292
|
+
when "array"
|
293
|
+
s = elide( array_to_s( jcr ) )
|
294
|
+
when "group"
|
295
|
+
s = elide( group_to_s( jcr ) )
|
296
|
+
else
|
297
|
+
s = "** unknown rule **"
|
298
|
+
end
|
299
|
+
trace( econs, "#{type}: #{s}", data)
|
300
|
+
end
|
301
|
+
end
|
302
|
+
|
303
|
+
def self.trace_eval econs, message, evaluation
|
304
|
+
if evaluation.success
|
305
|
+
trace( econs, "#{message} evaluation is true" )
|
306
|
+
else
|
307
|
+
trace( econs, "#{message} evaluation failed: #{evaluation.reason}")
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def self.find_first_slice slice
|
312
|
+
if slice.is_a? Parslet::Slice
|
313
|
+
return slice
|
314
|
+
elsif slice.is_a?( Hash ) && !slice.empty?
|
315
|
+
s = nil
|
316
|
+
slice.values.each do |v|
|
317
|
+
s = find_first_slice( v )
|
318
|
+
break if s
|
319
|
+
end
|
320
|
+
return s if s
|
321
|
+
elsif slice.is_a?( Array ) && !slice.empty?
|
322
|
+
s = nil
|
323
|
+
slice.each do |i|
|
324
|
+
s = find_first_slice( i )
|
325
|
+
break if s
|
326
|
+
end
|
327
|
+
return s if s
|
328
|
+
end
|
329
|
+
#else
|
330
|
+
return nil
|
331
|
+
end
|
332
|
+
|
333
|
+
def self.slice_to_s slice
|
334
|
+
s = find_first_slice( slice )
|
335
|
+
if s.is_a? Parslet::Slice
|
336
|
+
pos = s.line_and_column
|
337
|
+
retval = "'#{s.inspect}' ( line #{pos[0]} column #{pos[1]} )"
|
338
|
+
else
|
339
|
+
retval = slice.to_s
|
340
|
+
end
|
341
|
+
retval
|
342
|
+
end
|
343
|
+
|
344
|
+
def self.raised_rule jcr, rule_atom
|
345
|
+
" rule at #{slice_to_s(jcr)} [ #{jcr} ] from rule at #{slice_to_s(rule_atom)}"
|
346
|
+
end
|
347
|
+
|
348
|
+
def self.rule_to_s( rule, shallow=true)
|
349
|
+
if rule[:primitive_rule]
|
350
|
+
retval = value_to_s( rule[:primitive_rule] )
|
351
|
+
elsif rule[:member_rule]
|
352
|
+
retval = member_to_s( rule[:member_rule], shallow )
|
353
|
+
elsif rule[:object_rule]
|
354
|
+
retval = object_to_s( rule[:object_rule], shallow )
|
355
|
+
elsif rule[:array_rule]
|
356
|
+
retval = array_to_s( rule[:array_rule], shallow )
|
357
|
+
elsif rule[:group_rule]
|
358
|
+
retval = group_to_s( rule[:group_rule], shallow )
|
359
|
+
elsif rule[:target_rule_name]
|
360
|
+
retval = target_to_s( rule[:target_rule_name] )
|
361
|
+
elsif rule[:rule_name]
|
362
|
+
retval = "rule: #{rule[:rule_name].to_s}"
|
363
|
+
elsif rule[:rule]
|
364
|
+
retval = rule_to_s( rule[:rule], shallow )
|
365
|
+
else
|
366
|
+
retval = "** unknown rule definition **"
|
367
|
+
end
|
368
|
+
return retval
|
369
|
+
end
|
370
|
+
|
371
|
+
def self.rules_to_s( rules, shallow=true)
|
372
|
+
retval = ""
|
373
|
+
rules.each do |rule|
|
374
|
+
if rule[:rule_name]
|
375
|
+
next
|
376
|
+
elsif rule[:choice_combiner]
|
377
|
+
retval = retval + " | "
|
378
|
+
elsif rule[:sequence_combiner]
|
379
|
+
retval = retval + " , "
|
380
|
+
end
|
381
|
+
retval = retval + rule_to_s( rule, shallow )
|
382
|
+
end
|
383
|
+
return retval
|
384
|
+
end
|
385
|
+
|
386
|
+
def self.annotations_to_s( annotations )
|
387
|
+
retval = ""
|
388
|
+
annotations.each do |a|
|
389
|
+
case
|
390
|
+
when a[:unordered_annotation]
|
391
|
+
retval = retval + " @{unordered}"
|
392
|
+
when a[:not_annotation]
|
393
|
+
retval = retval + " @{not}"
|
394
|
+
when a[:root_annotation]
|
395
|
+
retval = retval + " @{root}"
|
396
|
+
else
|
397
|
+
retval = retval + " @{ ** unknown annotation ** }"
|
398
|
+
end
|
399
|
+
end if annotations
|
400
|
+
retval = retval + " " if retval.length != 0
|
401
|
+
return retval
|
402
|
+
end
|
403
|
+
|
404
|
+
def self.target_to_s( jcr )
|
405
|
+
return annotations_to_s( jcr[:annotations] ) + " target: " + jcr[:rule_name].to_s
|
406
|
+
end
|
407
|
+
|
211
408
|
end
|