class Sqreen::ConditionEvaluator
Evaluate a condition, resolving literals using BindingAccessor
.
{ "%and" => ["true", "true"] } -> true { "%or" => ["true", "false"] } -> true { "%and" => ["false", "true"] } -> false { "%equal" => ["coucou", "#.args[0]"] } -> "coucou" == args[0] { "%hash_val_include" => ["toto is a small guy", "#.request_params"] } -> true if one value of request params in included in the sentence 'toto is a small guy'.
Combine expressions:
{ "%or" => [ { "%hash_val_include" => ["AAA", "#.request_params"] }, { "%hash_val_include" => ["BBB", "#.request_params"] }, ] }
will return true if one of the request_params include either AAA or BBB.
Constants
- AND_OPERATOR
- EQ_OPERATOR
- GTE_OPERATOR
- GT_OPERATOR
- HASH_INC_OPERATOR
- HASH_KEY_OPERATOR
- INC_OPERATOR
- LTE_OPERATOR
- LT_OPERATOR
- NEQ_OPERATOR
- OPERATORS_ARITY
- OR_OPERATOR
Public Class Methods
hash_key_include?(values, hash, min_value_size, rem = 10)
click to toggle source
Predicate: Is one of values deeply present in keys of hash @params value [Array] Array of objects to find @params hash [Hash] Hash to search into @params min_value_size [Fixnum] to compare against
# File lib/sqreen/condition_evaluator.rb, line 66 def self.hash_key_include?(values, hash, min_value_size, rem = 10) return true if rem <= 0 if hash.is_a?(Array) return hash.any? do |v| hash_key_include?(values, v, min_value_size, rem - 1) end end return false unless hash.is_a?(Hash) hash.any? do |hkey, hval| case hkey when NilClass false else if hkey.respond_to?(:empty?) && hkey.empty? false else key_incl = if values.is_a?(String) str_include?(values, hkey.to_s) else values.include?(hkey.to_s) end key_incl || hash_key_include?(values, hval, min_value_size, rem - 1) end end end end
hash_val_include?(value, hash, min_value_size, rem = 20)
click to toggle source
Predicate: Is value deeply included in hash @params value [Object] object to find @params hash [Hash] Hash to search into @params min_value_size [Fixnum] to compare against
# File lib/sqreen/condition_evaluator.rb, line 35 def self.hash_val_include?(value, hash, min_value_size, rem = 20) return true if rem <= 0 vals = hash vals = hash.values if hash.is_a?(Hash) vals.any? do |hval| case hval when Hash, Array ConditionEvaluator.hash_val_include?(value, hval, min_value_size, rem - 1) when NilClass false else if hval.respond_to?(:empty?) && hval.empty? false else v = hval.to_s if v.size < min_value_size false else ConditionEvaluator.str_include?(value.to_s, v) end end end end end
new(cond)
click to toggle source
Initialize evaluator @param cond [Hash] condition Hash
# File lib/sqreen/condition_evaluator.rb, line 115 def initialize(cond) unless cond == true || cond == false unless cond.respond_to? :each raise(Sqreen::Exception, "cond should be a Hash (was #{cond.class})") end end @raw = cond @compiled = compile_expr(cond, 10) end
str_include?(str, what)
click to toggle source
Test is a str contains what. Rencode if necessary
# File lib/sqreen/condition_evaluator.rb, line 97 def self.str_include?(str, what) str1 = if str.encoding != Encoding::UTF_8 str.encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace) else str end str2 = if what.encoding != Encoding::UTF_8 what.encode(Encoding::UTF_8, :invalid => :replace, :undef => :replace) else what end str1.include?(str2) end
Public Instance Methods
evaluate(*args)
click to toggle source
Evaluate the condition @params *args: BindingAccessor
evaluate arguments
# File lib/sqreen/condition_evaluator.rb, line 127 def evaluate(*args) evaluate_expr(@compiled, 10, *args) end
Protected Instance Methods
compile_expr(exp, rem)
click to toggle source
# File lib/sqreen/condition_evaluator.rb, line 133 def compile_expr(exp, rem) return exp if exp == true || exp == false return true if exp.empty? raise(Sqreen::Exception, 'too deep call detected') if rem <= 0 h = {} exp.each do |op, values| unless op.is_a? String raise Sqreen::Exception, "op should be a String (was #{op.class})" end unless values.is_a?(Array) raise Sqreen::Exception, "values should be an Array (was #{values.class})" end h[op] = values.map do |v| case v when Hash compile_expr(v, rem - 1) when 'true' true when 'false' false else BindingAccessor.new(v.to_s) end end end h end
evaluate_expr(exp, rem, *args)
click to toggle source
# File lib/sqreen/condition_evaluator.rb, line 185 def evaluate_expr(exp, rem, *args) return exp if exp == true || exp == false return true if exp.empty? raise(Sqreen::Exception, 'too deep call detected') if rem <= 0 exp.all? do |op, values| val_to_res = lambda do |v| case v when Hash evaluate_expr(v, rem - 1, *args) when true, false v else v.resolve(*args) end end arity = OPERATORS_ARITY[op] if !arity.nil? && values.size != arity raise(Sqreen::Exception, "bad arg count #{values.inspect} (op #{op} wanted #{arity})") end bool = case op when OR_OPERATOR values.reduce(false) do |_, v| r = val_to_res.call(v) break r if r r end when AND_OPERATOR values.reduce(true) do |_, v| r = val_to_res.call(v) break r unless r r end when EQ_OPERATOR res = values.map(&val_to_res) res[0] == res[1] when NEQ_OPERATOR res = values.map(&val_to_res) res[0] != res[1] when GT_OPERATOR res = values.map(&val_to_res) res[0] > res[1] when GTE_OPERATOR res = values.map(&val_to_res) res[0] >= res[1] when LT_OPERATOR res = values.map(&val_to_res) res[0] < res[1] when LTE_OPERATOR res = values.map(&val_to_res) res[0] <= res[1] when INC_OPERATOR res = values.map(&val_to_res) unless res[0].respond_to?(:include?) raise(Sqreen::Exception, "no include on res #{res[0].inspect}") end if res[0].is_a?(String) ConditionEvaluator.str_include?(res[0], res[1]) else res[0].include?(res[1]) end when HASH_INC_OPERATOR res = values.map(&val_to_res) ConditionEvaluator.hash_val_include?(res[0], res[1], res[2]) when HASH_KEY_OPERATOR res = values.map(&val_to_res) ConditionEvaluator.hash_key_include?(res[0], res[1], res[2]) else # FIXME: this should be check in compile raise(Sqreen::Exception, "unknown op #{op})") end bool end end