15
15
# See the License for the specific language governing permissions and
16
16
# limitations under the License.
17
17
#
18
+ require_relative 'helpers/constants'
18
19
require_relative 'helpers/validator'
19
20
20
21
module Optimizely
@@ -38,8 +39,9 @@ class CustomAttributeConditionEvaluator
38
39
39
40
attr_reader :user_attributes
40
41
41
- def initialize ( user_attributes )
42
+ def initialize ( user_attributes , logger )
42
43
@user_attributes = user_attributes
44
+ @logger = logger
43
45
end
44
46
45
47
def evaluate ( leaf_condition )
@@ -51,11 +53,47 @@ def evaluate(leaf_condition)
51
53
# Returns boolean if the given user attributes match/don't match the given conditions,
52
54
# nil if the given conditions can't be evaluated.
53
55
54
- return nil unless leaf_condition [ 'type' ] == CUSTOM_ATTRIBUTE_CONDITION_TYPE
56
+ unless leaf_condition [ 'type' ] == CUSTOM_ATTRIBUTE_CONDITION_TYPE
57
+ @logger . log (
58
+ Logger ::WARN ,
59
+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_TYPE' ] , leaf_condition )
60
+ )
61
+ return nil
62
+ end
55
63
56
64
condition_match = leaf_condition [ 'match' ] || EXACT_MATCH_TYPE
57
65
58
- return nil unless EVALUATORS_BY_MATCH_TYPE . include? ( condition_match )
66
+ if !@user_attributes . key? ( leaf_condition [ 'name' ] ) && condition_match != EXISTS_MATCH_TYPE
67
+ @logger . log (
68
+ Logger ::DEBUG ,
69
+ format (
70
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'MISSING_ATTRIBUTE_VALUE' ] ,
71
+ leaf_condition ,
72
+ leaf_condition [ 'name' ]
73
+ )
74
+ )
75
+ return nil
76
+ end
77
+
78
+ if @user_attributes [ leaf_condition [ 'name' ] ] . nil? && condition_match != EXISTS_MATCH_TYPE
79
+ @logger . log (
80
+ Logger ::DEBUG ,
81
+ format (
82
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'NULL_ATTRIBUTE_VALUE' ] ,
83
+ leaf_condition ,
84
+ leaf_condition [ 'name' ]
85
+ )
86
+ )
87
+ return nil
88
+ end
89
+
90
+ unless EVALUATORS_BY_MATCH_TYPE . include? ( condition_match )
91
+ @logger . log (
92
+ Logger ::WARN ,
93
+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_MATCH_TYPE' ] , leaf_condition )
94
+ )
95
+ return nil
96
+ end
59
97
60
98
send ( EVALUATORS_BY_MATCH_TYPE [ condition_match ] , leaf_condition )
61
99
end
@@ -73,13 +111,40 @@ def exact_evaluator(condition)
73
111
74
112
user_provided_value = @user_attributes [ condition [ 'name' ] ]
75
113
76
- if user_provided_value . is_a? ( Numeric ) && condition_value . is_a? ( Numeric )
77
- return true if condition_value . to_f == user_provided_value . to_f
114
+ if !value_type_valid_for_exact_conditions? ( condition_value ) ||
115
+ ( condition_value . is_a? ( Numeric ) && !Helpers ::Validator . finite_number? ( condition_value ) )
116
+ @logger . log (
117
+ Logger ::WARN ,
118
+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_VALUE' ] , condition )
119
+ )
120
+ return nil
78
121
end
79
122
80
- return nil if !value_valid_for_exact_conditions? ( user_provided_value ) ||
81
- !value_valid_for_exact_conditions? ( condition_value ) ||
82
- !Helpers ::Validator . same_types? ( condition_value , user_provided_value )
123
+ if !value_type_valid_for_exact_conditions? ( user_provided_value ) ||
124
+ !Helpers ::Validator . same_types? ( condition_value , user_provided_value )
125
+ @logger . log (
126
+ Logger ::WARN ,
127
+ format (
128
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNEXPECTED_TYPE' ] ,
129
+ condition ,
130
+ user_provided_value . class ,
131
+ condition [ 'name' ]
132
+ )
133
+ )
134
+ return nil
135
+ end
136
+
137
+ if user_provided_value . is_a? ( Numeric ) && !Helpers ::Validator . finite_number? ( user_provided_value )
138
+ @logger . log (
139
+ Logger ::WARN ,
140
+ format (
141
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'INFINITE_ATTRIBUTE_VALUE' ] ,
142
+ condition ,
143
+ condition [ 'name' ]
144
+ )
145
+ )
146
+ return nil
147
+ end
83
148
84
149
condition_value == user_provided_value
85
150
end
@@ -103,8 +168,7 @@ def greater_than_evaluator(condition)
103
168
condition_value = condition [ 'value' ]
104
169
user_provided_value = @user_attributes [ condition [ 'name' ] ]
105
170
106
- return nil if !Helpers ::Validator . finite_number? ( user_provided_value ) ||
107
- !Helpers ::Validator . finite_number? ( condition_value )
171
+ return nil unless valid_numeric_values? ( user_provided_value , condition_value , condition )
108
172
109
173
user_provided_value > condition_value
110
174
end
@@ -118,8 +182,7 @@ def less_than_evaluator(condition)
118
182
condition_value = condition [ 'value' ]
119
183
user_provided_value = @user_attributes [ condition [ 'name' ] ]
120
184
121
- return nil if !Helpers ::Validator . finite_number? ( user_provided_value ) ||
122
- !Helpers ::Validator . finite_number? ( condition_value )
185
+ return nil unless valid_numeric_values? ( user_provided_value , condition_value , condition )
123
186
124
187
user_provided_value < condition_value
125
188
end
@@ -133,20 +196,78 @@ def substring_evaluator(condition)
133
196
condition_value = condition [ 'value' ]
134
197
user_provided_value = @user_attributes [ condition [ 'name' ] ]
135
198
136
- return nil unless user_provided_value . is_a? ( String ) && condition_value . is_a? ( String )
199
+ unless condition_value . is_a? ( String )
200
+ @logger . log (
201
+ Logger ::WARN ,
202
+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_VALUE' ] , condition )
203
+ )
204
+ return nil
205
+ end
206
+
207
+ unless user_provided_value . is_a? ( String )
208
+ @logger . log (
209
+ Logger ::WARN ,
210
+ format (
211
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNEXPECTED_TYPE' ] ,
212
+ condition ,
213
+ user_provided_value . class ,
214
+ condition [ 'name' ]
215
+ )
216
+ )
217
+ return nil
218
+ end
137
219
138
220
user_provided_value . include? condition_value
139
221
end
140
222
141
223
private
142
224
143
- def value_valid_for_exact_conditions? ( value )
144
- # Returns true if the value is valid for exact conditions. Valid values include
145
- # strings, booleans, and numbers that aren't NaN, -Infinity, or Infinity.
225
+ def valid_numeric_values? ( user_value , condition_value , condition )
226
+ # Returns true if user and condition values are valid numeric.
227
+ # false otherwise.
228
+
229
+ unless Helpers ::Validator . finite_number? ( condition_value )
230
+ @logger . log (
231
+ Logger ::WARN ,
232
+ format ( Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNKNOWN_CONDITION_VALUE' ] , condition )
233
+ )
234
+ return false
235
+ end
236
+
237
+ unless user_value . is_a? ( Numeric )
238
+ @logger . log (
239
+ Logger ::WARN ,
240
+ format (
241
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'UNEXPECTED_TYPE' ] ,
242
+ condition ,
243
+ user_value . class ,
244
+ condition [ 'name' ]
245
+ )
246
+ )
247
+ return false
248
+ end
146
249
147
- return Helpers ::Validator . finite_number? ( value ) if value . is_a? Numeric
250
+ unless Helpers ::Validator . finite_number? ( user_value )
251
+ @logger . log (
252
+ Logger ::WARN ,
253
+ format (
254
+ Helpers ::Constants ::AUDIENCE_EVALUATION_LOGS [ 'INFINITE_ATTRIBUTE_VALUE' ] ,
255
+ condition ,
256
+ condition [ 'name' ]
257
+ )
258
+ )
259
+ return false
260
+ end
261
+
262
+ true
263
+ end
264
+
265
+ def value_type_valid_for_exact_conditions? ( value )
266
+ # Returns true if the value is valid for exact conditions. Valid values include
267
+ # strings or booleans or is a number.
268
+ # false otherwise.
148
269
149
- ( Helpers ::Validator . boolean? value ) || ( value . is_a? String )
270
+ ( Helpers ::Validator . boolean? value ) || ( value . is_a? String ) || value . is_a? ( Numeric )
150
271
end
151
272
end
152
273
end
0 commit comments