jcrvalidator 0.5.3 → 0.6.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/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
|