cel 0.3.1 → 0.4.1
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/CHANGELOG.md +32 -1
- data/README.md +26 -3
- data/lib/cel/ast/cel_methods.rb +58 -0
- data/lib/cel/ast/elements/bool.rb +34 -0
- data/lib/cel/ast/elements/bytes.rb +34 -0
- data/lib/cel/ast/elements/condition.rb +22 -0
- data/lib/cel/ast/elements/duration.rb +114 -0
- data/lib/cel/ast/elements/function.rb +33 -0
- data/lib/cel/ast/elements/group.rb +19 -0
- data/lib/cel/ast/elements/identifier.rb +32 -0
- data/lib/cel/ast/elements/invoke.rb +64 -0
- data/lib/cel/ast/elements/list.rb +70 -0
- data/lib/cel/ast/elements/literal.rb +74 -0
- data/lib/cel/ast/elements/map.rb +120 -0
- data/lib/cel/ast/elements/message.rb +50 -0
- data/lib/cel/ast/elements/null.rb +11 -0
- data/lib/cel/ast/elements/number.rb +70 -0
- data/lib/cel/ast/elements/operation.rb +39 -0
- data/lib/cel/ast/elements/protobuf.rb +4 -0
- data/lib/cel/ast/elements/string.rb +54 -0
- data/lib/cel/ast/elements/timestamp.rb +109 -0
- data/lib/cel/ast/elements.rb +18 -828
- data/lib/cel/ast/types.rb +49 -4
- data/lib/cel/checker.rb +47 -31
- data/lib/cel/context.rb +1 -1
- data/lib/cel/environment.rb +15 -2
- data/lib/cel/errors.rb +11 -0
- data/lib/cel/extensions/bind.rb +35 -0
- data/lib/cel/extensions/encoders.rb +41 -0
- data/lib/cel/extensions/math.rb +211 -0
- data/lib/cel/extensions/string.rb +230 -0
- data/lib/cel/extensions.rb +15 -0
- data/lib/cel/parser.rb +14 -13
- data/lib/cel/program.rb +28 -13
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +27 -12
- metadata +39 -2
|
@@ -0,0 +1,230 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module Cel
|
|
4
|
+
module Extensions
|
|
5
|
+
module String
|
|
6
|
+
module_function
|
|
7
|
+
|
|
8
|
+
def __check(funcall, checker:)
|
|
9
|
+
var = funcall.var
|
|
10
|
+
func = funcall.func
|
|
11
|
+
args = funcall.args
|
|
12
|
+
|
|
13
|
+
case func
|
|
14
|
+
when :quote
|
|
15
|
+
checker.check_arity(func, args, 1)
|
|
16
|
+
arg = checker.call(args.first)
|
|
17
|
+
return TYPES[:string] if checker.find_match_all_types(%i[string], arg)
|
|
18
|
+
when :indexOf, :lastIndexOf
|
|
19
|
+
if checker.call(var) == TYPES[:string]
|
|
20
|
+
checker.check_arity(func, args, 2, :>=)
|
|
21
|
+
arg, pos = args
|
|
22
|
+
arg = checker.call(arg)
|
|
23
|
+
if checker.find_match_all_types(%i[string], arg)
|
|
24
|
+
return TYPES[:int] if pos.nil?
|
|
25
|
+
|
|
26
|
+
pos = checker.call(pos)
|
|
27
|
+
return TYPES[:int] if checker.find_match_all_types(%i[int], pos)
|
|
28
|
+
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
when :split
|
|
32
|
+
if checker.call(var) == TYPES[:string]
|
|
33
|
+
checker.check_arity(func, args, 2, :>=)
|
|
34
|
+
arg, pos = args
|
|
35
|
+
arg = checker.call(arg)
|
|
36
|
+
if checker.find_match_all_types(%i[string], arg)
|
|
37
|
+
return TYPES[:list, :string] if pos.nil?
|
|
38
|
+
|
|
39
|
+
pos = checker.call(pos)
|
|
40
|
+
return TYPES[:list, :string] if checker.find_match_all_types(%i[int], pos)
|
|
41
|
+
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
when :substring
|
|
45
|
+
if checker.call(var) == TYPES[:string]
|
|
46
|
+
checker.check_arity(func, args, 2, :>=)
|
|
47
|
+
arg, pos = args
|
|
48
|
+
arg = checker.call(arg)
|
|
49
|
+
if checker.find_match_all_types(%i[int], arg)
|
|
50
|
+
return TYPES[:string] if pos.nil?
|
|
51
|
+
|
|
52
|
+
pos = checker.call(pos)
|
|
53
|
+
return TYPES[:string] if checker.find_match_all_types(%i[int], pos)
|
|
54
|
+
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
when :trim, :lowerAscii, :upperAscii, :reverse
|
|
58
|
+
if checker.call(var) == TYPES[:string]
|
|
59
|
+
checker.check_arity(func, args, 0)
|
|
60
|
+
return TYPES[:string]
|
|
61
|
+
end
|
|
62
|
+
when :format
|
|
63
|
+
if checker.call(var) == TYPES[:string]
|
|
64
|
+
checker.check_arity(func, args, 1)
|
|
65
|
+
arg = checker.call(args.first)
|
|
66
|
+
return TYPES[:string] if checker.find_match_all_types(%i[list], arg)
|
|
67
|
+
end
|
|
68
|
+
when :charAt
|
|
69
|
+
if checker.call(var) == TYPES[:string]
|
|
70
|
+
checker.check_arity(func, args, 1)
|
|
71
|
+
arg = checker.call(args.first)
|
|
72
|
+
return TYPES[:string] if checker.find_match_all_types(%i[int], arg)
|
|
73
|
+
end
|
|
74
|
+
when :replace
|
|
75
|
+
if checker.call(var) == TYPES[:string]
|
|
76
|
+
checker.check_arity(func, args, 2..3, :include?)
|
|
77
|
+
p, r, limit = args.map(&checker.method(:call))
|
|
78
|
+
if limit
|
|
79
|
+
return TYPES[:string] if checker.find_match_all_types(%i[string], [p, r]) &&
|
|
80
|
+
checker.find_match_all_types(%i[int], limit)
|
|
81
|
+
elsif checker.find_match_all_types(%i[string], [p, r])
|
|
82
|
+
return TYPES[:string]
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
when :join
|
|
86
|
+
if checker.call(var) == TYPES[:list, :string] || checker.call(var) == TYPES[:list, :any]
|
|
87
|
+
checker.check_arity(func, args, 1, :>=)
|
|
88
|
+
arg = checker.call(args.first)
|
|
89
|
+
return TYPES[:string] unless arg
|
|
90
|
+
return TYPES[:string] if checker.find_match_all_types(%i[string], arg)
|
|
91
|
+
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
checker.unsupported_operation(funcall)
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
def quote(str, program:)
|
|
99
|
+
value = program.call(str).value
|
|
100
|
+
|
|
101
|
+
# this should use String#dump, but this also replaces printable UTF8 characters
|
|
102
|
+
|
|
103
|
+
# replace quotes
|
|
104
|
+
value = value.gsub(/[\\'"\t\r\a\b\v\f\n]/) { |m| m.dump[1..-2] }
|
|
105
|
+
|
|
106
|
+
# replace invalid utf-8 chars
|
|
107
|
+
value = value.encode(Encoding::UTF_8, invalid: :replace)
|
|
108
|
+
|
|
109
|
+
# adding leading quotes if not quoted already
|
|
110
|
+
value = "\"#{value}\"" unless value.start_with?("\"") && value.end_with?("\"")
|
|
111
|
+
|
|
112
|
+
Cel::String.new(value)
|
|
113
|
+
end
|
|
114
|
+
end
|
|
115
|
+
end
|
|
116
|
+
|
|
117
|
+
class String
|
|
118
|
+
define_cel_method(:charAt) do |idx|
|
|
119
|
+
raise EvaluateError, "index out of range: #{idx}" unless idx.between?(0, @value.size)
|
|
120
|
+
|
|
121
|
+
String.new(@value[idx] || "")
|
|
122
|
+
end
|
|
123
|
+
|
|
124
|
+
define_cel_method(:indexOf) do |substr, *args|
|
|
125
|
+
idx, = args
|
|
126
|
+
|
|
127
|
+
raise EvaluateError, "index out of range: #{idx}" if idx && !idx.between?(0, @value.size)
|
|
128
|
+
|
|
129
|
+
Number.new(:int, @value.index(substr, *args) || -1)
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
define_cel_method(:lastIndexOf) do |substr, *args|
|
|
133
|
+
idx, = args
|
|
134
|
+
|
|
135
|
+
raise EvaluateError, "index out of range: #{idx}" if idx && !idx.between?(0, @value.size)
|
|
136
|
+
|
|
137
|
+
Number.new(:int, @value.rindex(substr, *args) || -1)
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
define_cel_method(:lowerAscii) do
|
|
141
|
+
String.new(@value.downcase(:ascii))
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
define_cel_method(:upperAscii) do
|
|
145
|
+
String.new(@value.upcase(:ascii))
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
UNICODE_WHITESPACE = /[ \t\r\n\u000C\u000D\u0020\u0085\u00A0\u1680\u2000-\u200A\u2028-\u2029\u202F\u205F\u3000]+/
|
|
149
|
+
|
|
150
|
+
define_cel_method(:trim) do
|
|
151
|
+
# why this? because String#split only takes null, horizontal tab, line feed, vertical tab, form feed,
|
|
152
|
+
# carriage return, space into account. We need the unicode definition of whitespace.
|
|
153
|
+
value = @value.gsub(/\A#{UNICODE_WHITESPACE}/o, "")
|
|
154
|
+
.gsub(/#{UNICODE_WHITESPACE}\z/o, "")
|
|
155
|
+
|
|
156
|
+
String.new(value.strip)
|
|
157
|
+
end
|
|
158
|
+
|
|
159
|
+
define_cel_method(:reverse) do
|
|
160
|
+
String.new(@value.reverse)
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
define_cel_method(:split) do |pattern, *args|
|
|
164
|
+
raise NoOverloadError unless pattern.is_a?(String) && args.size.between?(0, 1)
|
|
165
|
+
|
|
166
|
+
limit, = args
|
|
167
|
+
|
|
168
|
+
raise NoOverloadError if limit && !limit.is_a?(Number)
|
|
169
|
+
|
|
170
|
+
if limit && limit.zero?
|
|
171
|
+
List.new([])
|
|
172
|
+
else
|
|
173
|
+
List.new(@value.split(pattern, *args))
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
define_cel_method(:substring) do |*args|
|
|
178
|
+
raise NoOverloadError unless args.size.between?(1, 2)
|
|
179
|
+
|
|
180
|
+
start_idx, end_idx = *args
|
|
181
|
+
end_idx ||= @value.size
|
|
182
|
+
|
|
183
|
+
raise EvaluateError, "index out of range: #{start_idx}" unless start_idx.between?(0, @value.size)
|
|
184
|
+
|
|
185
|
+
raise EvaluateError, "index out of range: #{end_idx}" if end_idx >= @value.size + 1
|
|
186
|
+
|
|
187
|
+
raise EvaluateError, "end index can't be higher than start index" if end_idx < start_idx
|
|
188
|
+
|
|
189
|
+
String.new(@value[start_idx..(end_idx - 1)])
|
|
190
|
+
end
|
|
191
|
+
|
|
192
|
+
define_cel_method(:replace) do |pattern, replacement, *args|
|
|
193
|
+
raise NoOverloadError unless args.size.between?(0, 1)
|
|
194
|
+
|
|
195
|
+
limit, = args
|
|
196
|
+
|
|
197
|
+
raise NoOverloadError unless pattern.is_a?(String) && replacement.is_a?(String)
|
|
198
|
+
|
|
199
|
+
pattern = pattern.value
|
|
200
|
+
replacement = replacement.value
|
|
201
|
+
|
|
202
|
+
value = if limit
|
|
203
|
+
raise NoOverloadError unless limit.is_a?(Number)
|
|
204
|
+
|
|
205
|
+
@value.gsub(pattern) do |m|
|
|
206
|
+
if limit.zero?
|
|
207
|
+
m
|
|
208
|
+
else
|
|
209
|
+
limit -= 1
|
|
210
|
+
replacement
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
else
|
|
214
|
+
@value.gsub(pattern, replacement)
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
String.new(value)
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
define_cel_method(:format) do |mappings|
|
|
221
|
+
String.new(format(@value, *mappings))
|
|
222
|
+
end
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
class List
|
|
226
|
+
define_cel_method(:join) do |*args|
|
|
227
|
+
String.new(super(*args))
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
end
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require_relative "extensions/math"
|
|
4
|
+
require_relative "extensions/string"
|
|
5
|
+
require_relative "extensions/bind"
|
|
6
|
+
require_relative "extensions/encoders"
|
|
7
|
+
|
|
8
|
+
module Cel
|
|
9
|
+
EXTENSIONS = {
|
|
10
|
+
math: Extensions::Math,
|
|
11
|
+
strings: Extensions::String,
|
|
12
|
+
base64: Extensions::Encoders::Base64,
|
|
13
|
+
cel: Extensions::Bind,
|
|
14
|
+
}.freeze
|
|
15
|
+
end
|
data/lib/cel/parser.rb
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
1
2
|
#
|
|
2
3
|
# DO NOT MODIFY!!!!
|
|
3
4
|
# This file is automatically generated by Racc 1.8.1
|
|
@@ -32,7 +33,7 @@ else
|
|
|
32
33
|
}
|
|
33
34
|
end.freeze
|
|
34
35
|
|
|
35
|
-
OPERATORS_RE = Regexp.union(*OPERATORS.keys)
|
|
36
|
+
OPERATORS_RE = Regexp.union(*OPERATORS.keys).freeze
|
|
36
37
|
|
|
37
38
|
BACKSLASH = "\\\\" # Must be literally two backslashes for proper interpolation
|
|
38
39
|
DIGIT = "[0-9]"
|
|
@@ -46,24 +47,24 @@ ESC_BYTE_SEQ = "#{BACKSLASH}[xX]#{HEXDIGIT}{2}"
|
|
|
46
47
|
ESC_UNI_SEQ = "#{BACKSLASH}u#{HEXDIGIT}{4}|#{BACKSLASH}U#{HEXDIGIT}{8}"
|
|
47
48
|
ESC_SEQ = "#{ESC_CHAR_SEQ}|#{ESC_BYTE_SEQ}|#{ESC_UNI_SEQ}|#{ESC_OCT_SEQ}"
|
|
48
49
|
|
|
49
|
-
WHITESPACE_REGEX = /[ \t\r\n\u000C]
|
|
50
|
-
COMMENT_REGEX = %r{//[^\n]*}
|
|
50
|
+
WHITESPACE_REGEX = /[ \t\r\n\u000C]+/.freeze
|
|
51
|
+
COMMENT_REGEX = %r{//[^\n]*}.freeze
|
|
51
52
|
|
|
52
53
|
NUM_FLOAT_REGEX = Regexp.union(
|
|
53
54
|
/#{DIGIT}+\.#{DIGIT}+#{EXPONENT}?/,
|
|
54
55
|
/#{DIGIT}+#{EXPONENT}/,
|
|
55
56
|
/\.#{DIGIT}+#{EXPONENT}?/
|
|
56
|
-
)
|
|
57
|
+
).freeze
|
|
57
58
|
|
|
58
59
|
NUM_INT_REGEX = Regexp.union(
|
|
59
60
|
/0x(?<hex>#{HEXDIGIT}+)/,
|
|
60
61
|
/(?<dec>#{DIGIT}+)/
|
|
61
|
-
)
|
|
62
|
+
).freeze
|
|
62
63
|
|
|
63
64
|
NUM_UINT_REGEX = Regexp.union(
|
|
64
65
|
/0x(?<hex>#{HEXDIGIT}+)[uU]/,
|
|
65
66
|
/(?<dec>#{DIGIT}+)[uU]/
|
|
66
|
-
)
|
|
67
|
+
).freeze
|
|
67
68
|
|
|
68
69
|
STRING_REGEX = Regexp.union(
|
|
69
70
|
/"""(?<str>(?:#{ESC_SEQ}|[^\\])*)"""/,
|
|
@@ -74,20 +75,20 @@ STRING_REGEX = Regexp.union(
|
|
|
74
75
|
/#{RAW}'''(?<str>.*?)'''/m,
|
|
75
76
|
/#{RAW}"(?<str>[^"\n\r]*)"/,
|
|
76
77
|
/#{RAW}'(?<str>[^'\n\r]*)'/,
|
|
77
|
-
)
|
|
78
|
+
).freeze
|
|
78
79
|
|
|
79
|
-
QUOTED_MAP_FIELD_REGEX =
|
|
80
|
+
QUOTED_MAP_FIELD_REGEX = /`/.freeze
|
|
80
81
|
|
|
81
|
-
BYTES_REGEX = /[bB]#{STRING_REGEX}
|
|
82
|
+
BYTES_REGEX = /[bB]#{STRING_REGEX}/.freeze
|
|
82
83
|
|
|
83
84
|
RESERVED = %W[
|
|
84
85
|
as break const continue else
|
|
85
86
|
for function if import let
|
|
86
87
|
loop package namespace return
|
|
87
88
|
var void while
|
|
88
|
-
].freeze
|
|
89
|
+
].each(&:freeze).freeze
|
|
89
90
|
|
|
90
|
-
IDENTIFIER_REGEX = /[_a-zA-Z][_a-zA-Z0-9]
|
|
91
|
+
IDENTIFIER_REGEX = /[_a-zA-Z][_a-zA-Z0-9]*/.freeze
|
|
91
92
|
|
|
92
93
|
def initialize(
|
|
93
94
|
package = nil,
|
|
@@ -404,9 +405,9 @@ def math_operation(op, operands)
|
|
|
404
405
|
when "*", "/", "%"
|
|
405
406
|
depth = lhs.depth + 1
|
|
406
407
|
end
|
|
407
|
-
when "+"
|
|
408
|
+
when "+"
|
|
408
409
|
case lhs.op
|
|
409
|
-
when "+"
|
|
410
|
+
when "+"
|
|
410
411
|
depth = lhs.depth + 1
|
|
411
412
|
end
|
|
412
413
|
end
|
data/lib/cel/program.rb
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
module Cel
|
|
4
4
|
class Program
|
|
5
|
-
attr_reader :context
|
|
5
|
+
attr_reader :environment, :context
|
|
6
6
|
|
|
7
7
|
def initialize(context, environment)
|
|
8
8
|
@context = context
|
|
@@ -55,7 +55,11 @@ module Cel
|
|
|
55
55
|
end
|
|
56
56
|
|
|
57
57
|
def evaluate_identifier(identifier)
|
|
58
|
-
|
|
58
|
+
id_sym = identifier.to_sym
|
|
59
|
+
|
|
60
|
+
if Cel::EXTENSIONS.key?(id_sym)
|
|
61
|
+
Cel::EXTENSIONS[id_sym]
|
|
62
|
+
elsif Cel::PRIMITIVE_TYPES.include?(id_sym)
|
|
59
63
|
TYPES[identifier.to_sym]
|
|
60
64
|
else
|
|
61
65
|
val, func = @context.lookup(identifier)
|
|
@@ -179,12 +183,12 @@ module Cel
|
|
|
179
183
|
t.is_a?(Class) && t < Protobuf.base_class ? 1 : 0
|
|
180
184
|
end
|
|
181
185
|
|
|
182
|
-
val = lhs.
|
|
186
|
+
val = lhs.cel_send(op, rhs)
|
|
183
187
|
|
|
184
188
|
Literal.to_cel_type(val)
|
|
185
189
|
else
|
|
186
190
|
op_value, *values = operands.map(&method(:call))
|
|
187
|
-
val = op_value.
|
|
191
|
+
val = op_value.cel_send(op, *values)
|
|
188
192
|
|
|
189
193
|
Literal.to_cel_type(val)
|
|
190
194
|
end
|
|
@@ -193,7 +197,8 @@ module Cel
|
|
|
193
197
|
def evaluate_invoke(invoke, var = invoke.var)
|
|
194
198
|
return evaluate_standard_func(invoke) unless var
|
|
195
199
|
|
|
196
|
-
func = invoke.func
|
|
200
|
+
func = call(invoke.func) || invoke.func
|
|
201
|
+
|
|
197
202
|
args = invoke.args
|
|
198
203
|
|
|
199
204
|
var =
|
|
@@ -225,7 +230,7 @@ module Cel
|
|
|
225
230
|
when String
|
|
226
231
|
raise EvaluateError, "#{invoke} is not supported" unless String.method_defined?(func, false)
|
|
227
232
|
|
|
228
|
-
var.
|
|
233
|
+
var.cel_send(func, *args.map(&method(:call)))
|
|
229
234
|
when Map
|
|
230
235
|
return Macro.__send__(func, var, *args, program: self) if !Module.respond_to?(func) && Macro.respond_to?(func)
|
|
231
236
|
|
|
@@ -234,9 +239,13 @@ module Cel
|
|
|
234
239
|
# to the expression x['foo'] when x evaluates to a map).
|
|
235
240
|
|
|
236
241
|
if args
|
|
237
|
-
var.
|
|
242
|
+
var.cel_send(func, *args)
|
|
238
243
|
else
|
|
244
|
+
# this should only be a data accessor, calling functions is disallowed
|
|
245
|
+
raise EvaluateError, "#{invoke} is not supported" unless var.key?(func)
|
|
246
|
+
|
|
239
247
|
begin
|
|
248
|
+
# TODO: use explicit lookup method to circumvent the need to method_missing it
|
|
240
249
|
var.public_send(func)
|
|
241
250
|
rescue NoMethodError
|
|
242
251
|
raise NoSuchKeyError.new(var, func)
|
|
@@ -250,8 +259,8 @@ module Cel
|
|
|
250
259
|
# to the expression x['foo'] when x evaluates to a map).
|
|
251
260
|
|
|
252
261
|
args ?
|
|
253
|
-
var.
|
|
254
|
-
var.
|
|
262
|
+
var.cel_send(func, *Array(args).map(&method(:call))) :
|
|
263
|
+
var.cel_send(func)
|
|
255
264
|
when Timestamp, Duration
|
|
256
265
|
raise EvaluateError, "#{invoke} is not supported" unless var.class.method_defined?(func, false)
|
|
257
266
|
|
|
@@ -262,7 +271,7 @@ module Cel
|
|
|
262
271
|
# runtime error no_such_field is raised.
|
|
263
272
|
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
|
264
273
|
|
|
265
|
-
var.
|
|
274
|
+
var.cel_send(func, *args)
|
|
266
275
|
when Literal
|
|
267
276
|
# eliminate ruby API from the lookup
|
|
268
277
|
raise NoMatchingOverloadError.new(var, func) if Literal.instance_methods.include?(func)
|
|
@@ -271,7 +280,7 @@ module Cel
|
|
|
271
280
|
# runtime error no_such_field is raised.
|
|
272
281
|
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
|
273
282
|
|
|
274
|
-
var.
|
|
283
|
+
var.cel_send(func)
|
|
275
284
|
when Protobuf.base_class
|
|
276
285
|
# eliminate protobuf API from the lookup
|
|
277
286
|
raise NoMatchingOverloadError.new(var, func) if Protobuf.base_class.instance_methods.include?(func)
|
|
@@ -283,8 +292,10 @@ module Cel
|
|
|
283
292
|
value = Protobuf.lookup(var, func)
|
|
284
293
|
|
|
285
294
|
Literal.to_cel_type(value)
|
|
286
|
-
|
|
287
|
-
if var.
|
|
295
|
+
when Module
|
|
296
|
+
if var.respond_to?(func) && !Module.respond_to?(func)
|
|
297
|
+
return var.__send__(func, *args, program: self)
|
|
298
|
+
elsif var.const_defined?(func) && !Module.const_defined?(func)
|
|
288
299
|
# this block assumes a message based call on a protobuf message, either to a
|
|
289
300
|
# subclass/namespace (Foo.Bar), or an enum (Foo.BAR)
|
|
290
301
|
# protobuf accessing enum module
|
|
@@ -313,8 +324,12 @@ module Cel
|
|
|
313
324
|
return Literal.to_cel_type(value)
|
|
314
325
|
end
|
|
315
326
|
|
|
327
|
+
raise EvaluateError, "#{invoke} is not supported"
|
|
328
|
+
else
|
|
316
329
|
raise EvaluateError, "#{invoke} is not supported"
|
|
317
330
|
end
|
|
331
|
+
rescue NoCelMethodError
|
|
332
|
+
raise EvaluateError, "#{invoke} is not supported"
|
|
318
333
|
end
|
|
319
334
|
|
|
320
335
|
def evaluate_condition(condition)
|
data/lib/cel/version.rb
CHANGED
data/lib/cel.rb
CHANGED
|
@@ -1,17 +1,19 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require "bigdecimal"
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
4
|
+
require_relative "cel/version"
|
|
5
|
+
require_relative "cel/errors"
|
|
6
|
+
require_relative "cel/ast/cel_methods"
|
|
7
|
+
require_relative "cel/ast/types"
|
|
8
|
+
require_relative "cel/ast/elements"
|
|
9
|
+
require_relative "cel/extensions"
|
|
10
|
+
require_relative "cel/parser"
|
|
11
|
+
require_relative "cel/macro"
|
|
12
|
+
require_relative "cel/context"
|
|
13
|
+
require_relative "cel/encoder" if RUBY_VERSION >= "3.1.0"
|
|
14
|
+
require_relative "cel/checker"
|
|
15
|
+
require_relative "cel/program"
|
|
16
|
+
require_relative "cel/environment"
|
|
15
17
|
|
|
16
18
|
begin
|
|
17
19
|
require "tzinfo"
|
|
@@ -19,7 +21,7 @@ rescue LoadError # rubocop:disable Lint/SuppressedException
|
|
|
19
21
|
end
|
|
20
22
|
|
|
21
23
|
begin
|
|
22
|
-
|
|
24
|
+
require_relative "cel/ast/elements/protobuf"
|
|
23
25
|
rescue LoadError => e
|
|
24
26
|
puts e
|
|
25
27
|
module Cel
|
|
@@ -252,4 +254,17 @@ module Cel
|
|
|
252
254
|
/[[:upper:]]/.match?(typ[0]) ? typ : typ.capitalize
|
|
253
255
|
end.join("::")
|
|
254
256
|
end
|
|
257
|
+
|
|
258
|
+
# freeze constants to make cel ractor-friendly
|
|
259
|
+
Number.freeze
|
|
260
|
+
Bool.freeze
|
|
261
|
+
Null.freeze
|
|
262
|
+
String.freeze
|
|
263
|
+
Bytes.freeze
|
|
264
|
+
List.freeze
|
|
265
|
+
Map.freeze
|
|
266
|
+
Timestamp.freeze
|
|
267
|
+
Duration.freeze
|
|
268
|
+
Type.freeze
|
|
269
|
+
TYPES.each_value(&:freeze).freeze
|
|
255
270
|
end
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cel
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.4.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tiago Cardoso
|
|
@@ -51,6 +51,20 @@ dependencies:
|
|
|
51
51
|
- - ">="
|
|
52
52
|
- !ruby/object:Gem::Version
|
|
53
53
|
version: '0'
|
|
54
|
+
- !ruby/object:Gem::Dependency
|
|
55
|
+
name: tzinfo-data
|
|
56
|
+
requirement: !ruby/object:Gem::Requirement
|
|
57
|
+
requirements:
|
|
58
|
+
- - ">="
|
|
59
|
+
- !ruby/object:Gem::Version
|
|
60
|
+
version: '0'
|
|
61
|
+
type: :development
|
|
62
|
+
prerelease: false
|
|
63
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
64
|
+
requirements:
|
|
65
|
+
- - ">="
|
|
66
|
+
- !ruby/object:Gem::Version
|
|
67
|
+
version: '0'
|
|
54
68
|
description: Pure Ruby implementation of Google Common Expression Language, https://opensource.google/projects/cel.
|
|
55
69
|
email:
|
|
56
70
|
- cardoso_tiago@hotmail.com
|
|
@@ -65,14 +79,37 @@ files:
|
|
|
65
79
|
- LICENSE.txt
|
|
66
80
|
- README.md
|
|
67
81
|
- lib/cel.rb
|
|
82
|
+
- lib/cel/ast/cel_methods.rb
|
|
68
83
|
- lib/cel/ast/elements.rb
|
|
84
|
+
- lib/cel/ast/elements/bool.rb
|
|
85
|
+
- lib/cel/ast/elements/bytes.rb
|
|
86
|
+
- lib/cel/ast/elements/condition.rb
|
|
87
|
+
- lib/cel/ast/elements/duration.rb
|
|
88
|
+
- lib/cel/ast/elements/function.rb
|
|
89
|
+
- lib/cel/ast/elements/group.rb
|
|
90
|
+
- lib/cel/ast/elements/identifier.rb
|
|
91
|
+
- lib/cel/ast/elements/invoke.rb
|
|
92
|
+
- lib/cel/ast/elements/list.rb
|
|
93
|
+
- lib/cel/ast/elements/literal.rb
|
|
94
|
+
- lib/cel/ast/elements/map.rb
|
|
95
|
+
- lib/cel/ast/elements/message.rb
|
|
96
|
+
- lib/cel/ast/elements/null.rb
|
|
97
|
+
- lib/cel/ast/elements/number.rb
|
|
98
|
+
- lib/cel/ast/elements/operation.rb
|
|
69
99
|
- lib/cel/ast/elements/protobuf.rb
|
|
100
|
+
- lib/cel/ast/elements/string.rb
|
|
101
|
+
- lib/cel/ast/elements/timestamp.rb
|
|
70
102
|
- lib/cel/ast/types.rb
|
|
71
103
|
- lib/cel/checker.rb
|
|
72
104
|
- lib/cel/context.rb
|
|
73
105
|
- lib/cel/encoder.rb
|
|
74
106
|
- lib/cel/environment.rb
|
|
75
107
|
- lib/cel/errors.rb
|
|
108
|
+
- lib/cel/extensions.rb
|
|
109
|
+
- lib/cel/extensions/bind.rb
|
|
110
|
+
- lib/cel/extensions/encoders.rb
|
|
111
|
+
- lib/cel/extensions/math.rb
|
|
112
|
+
- lib/cel/extensions/string.rb
|
|
76
113
|
- lib/cel/macro.rb
|
|
77
114
|
- lib/cel/parser.rb
|
|
78
115
|
- lib/cel/program.rb
|
|
@@ -99,7 +136,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
99
136
|
- !ruby/object:Gem::Version
|
|
100
137
|
version: '0'
|
|
101
138
|
requirements: []
|
|
102
|
-
rubygems_version: 3.6.
|
|
139
|
+
rubygems_version: 3.6.9
|
|
103
140
|
specification_version: 4
|
|
104
141
|
summary: Pure Ruby implementation of Google Common Expression Language, https://opensource.google/projects/cel.
|
|
105
142
|
test_files: []
|