/
expr_evaluator.rb
122 lines (106 loc) · 2.61 KB
/
expr_evaluator.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
# frozen_string_literal: true
require "bigdecimal"
require_relative "../string"
require_relative "./evaluator"
EMPTY_MAP = {}
EMPTY_LIST = []
class ExprEvaluator < Evaluator
attr_accessor :operators
attr_accessor :vars
NUMERIC_REGEX = /\A[-+]?[0-9]*\.?[0-9]+\Z/
def initialize(operators, vars)
@operators = operators
@vars = vars
end
def evaluate(expr)
if expr.is_a? Array
return @operators[:and].evaluate(self, expr)
elsif expr.is_a? Hash
expr.transform_keys(&:to_sym).each do |key, value|
if @operators[key]
return @operators[key].evaluate(self, value)
end
end
end
nil
end
def boolean_convert(x)
if x.is_a?(TrueClass) || x.is_a?(FalseClass)
return x
elsif x.is_a?(Numeric) || !(x.to_s =~ NUMERIC_REGEX).nil?
return !x.to_f.zero?
elsif x.is_a?(String)
return x != "false" && x != "0" && x != ""
end
!x.nil?
end
def number_convert(x)
return if x.nil? || x.to_s.empty?
if x.is_a?(Numeric) || !(x.to_s =~ NUMERIC_REGEX).nil?
return x.to_f
elsif x.is_a?(TrueClass) || x.is_a?(FalseClass)
return x ? 1.0 : 0.0
end
nil
end
def string_convert(x)
if x.is_a?(String)
return x
elsif x.is_a?(TrueClass) || x.is_a?(FalseClass)
return x.to_s
elsif x.is_a?(Numeric) || !(x.to_s =~ NUMERIC_REGEX).nil?
return x == x.to_i ? x.to_i.to_s : x.to_s
end
nil
end
def extract_var(path)
frags = path.split("/")
target = !vars.nil? ? vars : {}
frags.each do |frag|
list = target
value = nil
if target.is_a?(Array)
value = list[frag.to_i]
elsif target.is_a?(Hash)
value = list[frag].nil? ? list[frag.to_sym] : list[frag]
end
unless value.nil?
target = value
next
end
return nil
end
target
end
def compare(lhs, rhs)
if lhs.nil?
return rhs.nil? ? 0 : nil
elsif rhs.nil?
return nil
end
if lhs.is_a?(Numeric)
rvalue = number_convert(rhs)
return lhs.to_f.to_s.casecmp(rvalue.to_s) unless rvalue.nil?
elsif lhs.is_a?(String)
rvalue = string_convert(rhs)
return lhs.compare_to(rvalue) unless rvalue.nil?
elsif lhs.is_a?(TrueClass) || lhs.is_a?(FalseClass)
rvalue = boolean_convert(rhs)
return lhs.to_s.casecmp(rvalue.to_s) unless rvalue.nil?
elsif lhs.class == rhs.class && lhs === rhs
return 0
end
nil
end
end
class Array
def self.wrap(object)
if object.nil?
[]
elsif object.respond_to?(:to_ary)
object.to_ary || [object]
else
[object]
end
end
end