cel 0.1.1 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +56 -0
- data/README.md +14 -2
- data/lib/cel/ast/elements/protobuf.rb +127 -0
- data/lib/cel/ast/elements.rb +246 -4
- data/lib/cel/ast/types.rb +7 -1
- data/lib/cel/checker.rb +113 -35
- data/lib/cel/context.rb +8 -3
- data/lib/cel/encoder.rb +102 -0
- data/lib/cel/environment.rb +19 -6
- data/lib/cel/parser.rb +28 -12
- data/lib/cel/program.rb +17 -5
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +1 -6
- metadata +22 -7
- data/lib/cel/protobuf.rb +0 -175
data/lib/cel/checker.rb
CHANGED
@@ -31,10 +31,9 @@ module Cel
|
|
31
31
|
Checker.new(@declarations ? @declarations.merge(declarations) : declarations)
|
32
32
|
end
|
33
33
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
SUB_EXPECTED_TYPES = %i[int uint double].freeze
|
34
|
+
LOGICAL_EXPECTED_TYPES = %i[bool int uint double string bytes timestamp duration].freeze
|
35
|
+
ADD_EXPECTED_TYPES = %i[int uint double string bytes list duration].freeze
|
36
|
+
SUB_EXPECTED_TYPES = %i[int uint double duration].freeze
|
38
37
|
MULTIDIV_EXPECTED_TYPES = %i[int uint double].freeze
|
39
38
|
REMAINDER_EXPECTED_TYPES = %i[int uint].freeze
|
40
39
|
|
@@ -73,26 +72,48 @@ module Cel
|
|
73
72
|
else
|
74
73
|
|
75
74
|
case op
|
76
|
-
when "&&", "||", "
|
77
|
-
return TYPES[:bool]
|
75
|
+
when "&&", "||", "<", "<=", ">=", ">"
|
76
|
+
return TYPES[:bool] if find_match_all_types(LOGICAL_EXPECTED_TYPES, values) || values.include?(:any)
|
77
|
+
when "!=", "=="
|
78
|
+
return TYPES[:bool] if values.uniq.size == 1 ||
|
79
|
+
values.all? { |v| v == :list } ||
|
80
|
+
values.all? { |v| v == :map } ||
|
81
|
+
values.include?(:any)
|
78
82
|
when "in"
|
79
|
-
return TYPES[:bool] if find_match_all_types(%i[list map], values.last)
|
83
|
+
return TYPES[:bool] if find_match_all_types(%i[list map any], values.last)
|
80
84
|
when "+"
|
81
|
-
if (type = find_match_all_types(ADD_EXPECTED_TYPES, values))
|
82
|
-
|
83
|
-
|
85
|
+
return type if (type = find_match_all_types(ADD_EXPECTED_TYPES, values))
|
86
|
+
|
87
|
+
return TYPES[:timestamp] if %i[timestamp duration].any? { |typ| values.first == typ }
|
88
|
+
|
89
|
+
return values.last if values.first == :any
|
90
|
+
|
84
91
|
when "-"
|
85
|
-
if (type = find_match_all_types(SUB_EXPECTED_TYPES, values))
|
86
|
-
|
92
|
+
return type if (type = find_match_all_types(SUB_EXPECTED_TYPES, values))
|
93
|
+
|
94
|
+
case values.first
|
95
|
+
when TYPES[:timestamp]
|
96
|
+
return TYPES[:duration] if values.last == :timestamp
|
97
|
+
|
98
|
+
return TYPES[:timestamp] if values.last == :duration
|
99
|
+
|
100
|
+
return TYPES[:any] if values.last == :any
|
101
|
+
|
102
|
+
when TYPES[:any]
|
103
|
+
return values.last
|
87
104
|
end
|
88
105
|
when "*", "/"
|
89
|
-
if (type = find_match_all_types(MULTIDIV_EXPECTED_TYPES, values))
|
90
|
-
|
91
|
-
|
106
|
+
return type if (type = find_match_all_types(MULTIDIV_EXPECTED_TYPES, values))
|
107
|
+
|
108
|
+
values.include?(:any)
|
109
|
+
values.find { |typ| typ != :any } || TYPES[:any]
|
110
|
+
|
92
111
|
when "%"
|
93
|
-
if (type = find_match_all_types(REMAINDER_EXPECTED_TYPES, values))
|
94
|
-
|
95
|
-
|
112
|
+
return type if (type = find_match_all_types(REMAINDER_EXPECTED_TYPES, values))
|
113
|
+
|
114
|
+
values.include?(:any)
|
115
|
+
values.find { |typ| typ != :any } || TYPES[:any]
|
116
|
+
|
96
117
|
else
|
97
118
|
unsupported_type(operation)
|
98
119
|
end
|
@@ -100,6 +121,17 @@ module Cel
|
|
100
121
|
unsupported_type(operation)
|
101
122
|
end
|
102
123
|
|
124
|
+
def infer_variable_type(var)
|
125
|
+
case var
|
126
|
+
when Identifier
|
127
|
+
check_identifier(var)
|
128
|
+
when Invoke
|
129
|
+
check_invoke(var)
|
130
|
+
else
|
131
|
+
var.type
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
103
135
|
def check_invoke(funcall, var_type = nil)
|
104
136
|
var = funcall.var
|
105
137
|
func = funcall.func
|
@@ -107,14 +139,7 @@ module Cel
|
|
107
139
|
|
108
140
|
return check_standard_func(funcall) unless var
|
109
141
|
|
110
|
-
var_type ||=
|
111
|
-
when Identifier
|
112
|
-
check_identifier(var)
|
113
|
-
when Invoke
|
114
|
-
check_invoke(var)
|
115
|
-
else
|
116
|
-
var.type
|
117
|
-
end
|
142
|
+
var_type ||= infer_variable_type(var)
|
118
143
|
|
119
144
|
case var_type
|
120
145
|
when MapType
|
@@ -153,6 +178,8 @@ module Cel
|
|
153
178
|
|
154
179
|
unsupported_type(funcall) unless identifier.is_a?(Identifier)
|
155
180
|
|
181
|
+
identifier.type = var_type.element_type
|
182
|
+
|
156
183
|
element_checker = merge(identifier.to_sym => var_type.element_type)
|
157
184
|
|
158
185
|
unsupported_type(funcall) if element_checker.check(predicate) != :bool
|
@@ -195,17 +222,38 @@ module Cel
|
|
195
222
|
unsupported_type(funcall)
|
196
223
|
end
|
197
224
|
unsupported_operation(funcall)
|
225
|
+
when TYPES[:timestamp]
|
226
|
+
case func
|
227
|
+
when :getDate, :getDayOfMonth, :getDayOfWeek, :getDayOfYear, :getFullYear, :getHours,
|
228
|
+
:getMilliseconds, :getMinutes, :getMonth, :getSeconds
|
229
|
+
check_arity(func, args, 0..1)
|
230
|
+
return TYPES[:int] if args.empty? || (args.size.positive? && args[0] == :string)
|
231
|
+
else
|
232
|
+
unsupported_type(funcall)
|
233
|
+
end
|
234
|
+
unsupported_operation(funcall)
|
235
|
+
when TYPES[:duration]
|
236
|
+
case func
|
237
|
+
when :getMilliseconds, :getMinutes, :getHours, :getSeconds
|
238
|
+
check_arity(func, args, 0)
|
239
|
+
return TYPES[:int]
|
240
|
+
else
|
241
|
+
unsupported_type(funcall)
|
242
|
+
end
|
243
|
+
unsupported_operation(funcall)
|
198
244
|
else
|
199
245
|
TYPES[:any]
|
200
246
|
end
|
201
247
|
end
|
202
248
|
|
203
249
|
CAST_ALLOWED_TYPES = {
|
204
|
-
int: %i[uint double string], # TODO: enum
|
250
|
+
int: %i[uint double string timestamp], # TODO: enum
|
205
251
|
uint: %i[int double string],
|
206
|
-
string: %i[int uint double bytes
|
252
|
+
string: %i[int uint double bytes timestamp duration],
|
207
253
|
double: %i[int uint string],
|
208
254
|
bytes: %i[string],
|
255
|
+
duration: %i[string],
|
256
|
+
timestamp: %i[string],
|
209
257
|
}.freeze
|
210
258
|
|
211
259
|
def check_standard_func(funcall)
|
@@ -223,15 +271,18 @@ module Cel
|
|
223
271
|
return TYPES[:bool]
|
224
272
|
when :size
|
225
273
|
check_arity(func, args, 1)
|
226
|
-
|
227
|
-
|
274
|
+
|
275
|
+
arg = call(args.first)
|
276
|
+
return TYPES[:int] if find_match_all_types(%i[string bytes list map], arg)
|
277
|
+
when *CAST_ALLOWED_TYPES.keys
|
228
278
|
check_arity(func, args, 1)
|
229
279
|
allowed_types = CAST_ALLOWED_TYPES[func]
|
230
280
|
|
231
|
-
|
281
|
+
arg = call(args.first)
|
282
|
+
return TYPES[func] if find_match_all_types(allowed_types, arg)
|
232
283
|
when :matches
|
233
284
|
check_arity(func, args, 2)
|
234
|
-
return TYPES[:bool] if find_match_all_types(%i[string], args.map
|
285
|
+
return TYPES[:bool] if find_match_all_types(%i[string], args.map(&method(:call)))
|
235
286
|
when :dyn
|
236
287
|
check_arity(func, args, 1)
|
237
288
|
arg_type = call(args.first)
|
@@ -241,14 +292,37 @@ module Cel
|
|
241
292
|
end
|
242
293
|
return arg_type
|
243
294
|
else
|
295
|
+
return check_custom_func(@declarations[func], funcall) if @declarations.key?(func)
|
296
|
+
|
244
297
|
unsupported_type(funcall)
|
245
298
|
end
|
246
299
|
|
247
300
|
unsupported_operation(funcall)
|
248
301
|
end
|
249
302
|
|
303
|
+
def check_custom_func(func, funcall)
|
304
|
+
args = funcall.args
|
305
|
+
|
306
|
+
unless func.is_a?(Cel::Function)
|
307
|
+
raise CheckError, "#{func} must respond to #call" unless func.respond_to?(:call)
|
308
|
+
|
309
|
+
func = Cel::Function(&func)
|
310
|
+
end
|
311
|
+
|
312
|
+
unless func.types.empty?
|
313
|
+
unsupported_type(funcall) unless func.types.zip(args.map(&method(:call)))
|
314
|
+
.all? do |expected_type, type|
|
315
|
+
expected_type == :any || expected_type == type
|
316
|
+
end
|
317
|
+
|
318
|
+
return func.type
|
319
|
+
end
|
320
|
+
|
321
|
+
unsupported_operation(funcall)
|
322
|
+
end
|
323
|
+
|
250
324
|
def check_identifier(identifier)
|
251
|
-
return unless identifier.type == :any
|
325
|
+
return identifier.type unless identifier.type == :any
|
252
326
|
|
253
327
|
return TYPES[:type] if Cel::PRIMITIVE_TYPES.include?(identifier.to_sym)
|
254
328
|
|
@@ -262,6 +336,10 @@ module Cel
|
|
262
336
|
end
|
263
337
|
|
264
338
|
def check_condition(condition)
|
339
|
+
if_type = call(condition.if)
|
340
|
+
|
341
|
+
raise CheckError, "`#{condition.if}` must evaluate to a bool" unless if_type == :bool
|
342
|
+
|
265
343
|
then_type = call(condition.then)
|
266
344
|
else_type = call(condition.else)
|
267
345
|
|
@@ -286,7 +364,7 @@ module Cel
|
|
286
364
|
case typ
|
287
365
|
when Symbol
|
288
366
|
TYPES[typ] or
|
289
|
-
raise CheckError, "#{typ} is not
|
367
|
+
raise CheckError, "#{typ} is not a valid type"
|
290
368
|
else
|
291
369
|
typ
|
292
370
|
end
|
@@ -307,7 +385,7 @@ module Cel
|
|
307
385
|
end
|
308
386
|
|
309
387
|
def check_arity(func, args, arity)
|
310
|
-
return if args.size
|
388
|
+
return if arity === args.size # rubocop:disable Style/CaseEquality
|
311
389
|
|
312
390
|
raise CheckError, "`#{func}` invoked with wrong number of arguments (should be #{arity})"
|
313
391
|
end
|
data/lib/cel/context.rb
CHANGED
@@ -2,13 +2,18 @@
|
|
2
2
|
|
3
3
|
module Cel
|
4
4
|
class Context
|
5
|
-
|
5
|
+
attr_reader :declarations
|
6
|
+
|
7
|
+
def initialize(declarations, bindings)
|
8
|
+
@declarations = declarations
|
6
9
|
@bindings = bindings.dup
|
7
10
|
|
8
11
|
return unless @bindings
|
9
12
|
|
10
13
|
@bindings.each do |k, v|
|
11
|
-
|
14
|
+
val = to_cel_type(v)
|
15
|
+
val = TYPES[@declarations[k]].cast(val) if @declarations && @declarations.key?(k)
|
16
|
+
@bindings[k] = val
|
12
17
|
end
|
13
18
|
end
|
14
19
|
|
@@ -24,7 +29,7 @@ module Cel
|
|
24
29
|
end
|
25
30
|
|
26
31
|
def merge(bindings)
|
27
|
-
Context.new(@bindings ? @bindings.merge(bindings) : bindings)
|
32
|
+
Context.new(@declarations, @bindings ? @bindings.merge(bindings) : bindings)
|
28
33
|
end
|
29
34
|
|
30
35
|
private
|
data/lib/cel/encoder.rb
ADDED
@@ -0,0 +1,102 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Cel
|
4
|
+
module Encoder
|
5
|
+
module_function
|
6
|
+
|
7
|
+
def encode(expr)
|
8
|
+
case expr
|
9
|
+
when Group
|
10
|
+
["group", encode(expr.value)]
|
11
|
+
when Invoke
|
12
|
+
enc = [
|
13
|
+
"inv",
|
14
|
+
(encode(expr.var) if expr.var),
|
15
|
+
expr.func.to_s,
|
16
|
+
*(if expr.args
|
17
|
+
expr.func == :[] ? [encode(expr.args)] : expr.args.map(&method(:encode))
|
18
|
+
end),
|
19
|
+
]
|
20
|
+
enc.compact!
|
21
|
+
enc
|
22
|
+
when Operation
|
23
|
+
[
|
24
|
+
"op",
|
25
|
+
expr.op.to_s,
|
26
|
+
*expr.operands.map(&method(:encode)),
|
27
|
+
]
|
28
|
+
when Condition
|
29
|
+
[
|
30
|
+
"cond",
|
31
|
+
encode(expr.if),
|
32
|
+
encode(expr.then),
|
33
|
+
encode(expr.else),
|
34
|
+
]
|
35
|
+
when Identifier
|
36
|
+
[
|
37
|
+
"id",
|
38
|
+
expr.type.to_s,
|
39
|
+
expr.id.to_s,
|
40
|
+
]
|
41
|
+
when List
|
42
|
+
["lit",
|
43
|
+
expr.type.to_s,
|
44
|
+
*expr.value.map(&method(:encode))]
|
45
|
+
when Map
|
46
|
+
["lit",
|
47
|
+
expr.type.to_s,
|
48
|
+
*expr.value.map { |kv| kv.map(&method(:encode)) }]
|
49
|
+
when Number, Bool, String, Bytes
|
50
|
+
["lit", expr.type.to_s, expr.value]
|
51
|
+
when Null
|
52
|
+
%w[lit null]
|
53
|
+
when Type
|
54
|
+
["lit", "type", expr.to_s]
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def decode(enc)
|
59
|
+
case enc
|
60
|
+
in ["group", stmt]
|
61
|
+
Group.new(decode(stmt))
|
62
|
+
in ["inv", var, ::String => func, *args]
|
63
|
+
args = if func == "[]" && args.size == 1
|
64
|
+
decode(args.first)
|
65
|
+
elsif args.empty?
|
66
|
+
nil
|
67
|
+
else
|
68
|
+
args.map(&method(:decode))
|
69
|
+
end
|
70
|
+
Invoke.new(func: func, var: decode(var), args: args)
|
71
|
+
in ["inv", ::String => func, *args]
|
72
|
+
args = nil if args.empty?
|
73
|
+
Invoke.new(func: func, args: args.map(&method(:decode)))
|
74
|
+
in ["op", ::String => op, *args]
|
75
|
+
Operation.new(op, args.map(&method(:decode)))
|
76
|
+
in ["cond", f, th, el]
|
77
|
+
Condition.new(decode(f), decode(th), decode(el))
|
78
|
+
in ["id", ::String => type, ::String => val]
|
79
|
+
id = Identifier.new(val)
|
80
|
+
id.type = TYPES[type.to_sym]
|
81
|
+
id
|
82
|
+
in ["lit", "list", *items]
|
83
|
+
list = List.new(items.map(&method(:decode)))
|
84
|
+
list
|
85
|
+
in ["lit", "map", items]
|
86
|
+
Map.new(items.map(&method(:decode)).each_slice(2))
|
87
|
+
in ["lit", /\Aint|uint|double\z/ => type, Integer => val]
|
88
|
+
Number.new(type.to_sym, val)
|
89
|
+
in ["lit", "bool", val]
|
90
|
+
Bool.new(val)
|
91
|
+
in ["lit", "string", val]
|
92
|
+
String.new(val)
|
93
|
+
in ["lit", "bytes", val]
|
94
|
+
Bytes.new(val)
|
95
|
+
in ["lit", "null"]
|
96
|
+
Null.new
|
97
|
+
in ["lit", "type", type]
|
98
|
+
TYPES[type.to_sym]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
data/lib/cel/environment.rb
CHANGED
@@ -14,19 +14,31 @@ module Cel
|
|
14
14
|
ast
|
15
15
|
end
|
16
16
|
|
17
|
+
def encode(expr)
|
18
|
+
Encoder.encode(compile(expr))
|
19
|
+
end
|
20
|
+
|
21
|
+
def decode(encoded_expr)
|
22
|
+
ast = Encoder.decode(encoded_expr)
|
23
|
+
@checker.check(ast)
|
24
|
+
ast
|
25
|
+
end
|
26
|
+
|
17
27
|
def check(expr)
|
18
28
|
ast = @parser.parse(expr)
|
19
29
|
@checker.check(ast)
|
20
30
|
end
|
21
31
|
|
22
32
|
def program(expr)
|
23
|
-
expr =
|
24
|
-
|
33
|
+
expr = @parser.parse(expr) if expr.is_a?(::String)
|
34
|
+
@checker.check(expr)
|
35
|
+
Runner.new(@declarations, expr)
|
25
36
|
end
|
26
37
|
|
27
38
|
def evaluate(expr, bindings = nil)
|
28
|
-
context = Context.new(bindings)
|
29
|
-
expr =
|
39
|
+
context = Context.new(@declarations, bindings)
|
40
|
+
expr = @parser.parse(expr) if expr.is_a?(::String)
|
41
|
+
@checker.check(expr)
|
30
42
|
Program.new(context).evaluate(expr)
|
31
43
|
end
|
32
44
|
|
@@ -36,12 +48,13 @@ module Cel
|
|
36
48
|
end
|
37
49
|
|
38
50
|
class Runner
|
39
|
-
def initialize(ast)
|
51
|
+
def initialize(declarations, ast)
|
52
|
+
@declarations = declarations
|
40
53
|
@ast = ast
|
41
54
|
end
|
42
55
|
|
43
56
|
def evaluate(bindings = nil)
|
44
|
-
context = Context.new(bindings)
|
57
|
+
context = Context.new(@declarations, bindings)
|
45
58
|
Program.new(context).evaluate(@ast)
|
46
59
|
end
|
47
60
|
end
|
data/lib/cel/parser.rb
CHANGED
@@ -63,9 +63,18 @@ def parse(str)
|
|
63
63
|
tokenize(str)
|
64
64
|
do_parse
|
65
65
|
rescue Racc::ParseError => err
|
66
|
-
|
67
|
-
|
68
|
-
|
66
|
+
raise parse_error(err)
|
67
|
+
end
|
68
|
+
|
69
|
+
def parse_error(error)
|
70
|
+
parse_error = case error.message
|
71
|
+
when /parse error on value "([^"]+)" \(tRESERVED\)/
|
72
|
+
Cel::ParseError.new("invalid usage of the reserved word \"#{$1}\"")
|
73
|
+
else
|
74
|
+
Cel::ParseError.new(error.message)
|
75
|
+
end
|
76
|
+
parse_error.set_backtrace(error.backtrace)
|
77
|
+
parse_error
|
69
78
|
end
|
70
79
|
|
71
80
|
def tokenize(str)
|
@@ -83,10 +92,6 @@ def tokenize(str)
|
|
83
92
|
# skip comment lines
|
84
93
|
when scanner.scan(NUMBER_REGEX)
|
85
94
|
@q << convert_to_number(scanner)
|
86
|
-
when scanner.scan(/true|false/)
|
87
|
-
@q << [:tBOOL, scanner.matched == "true"]
|
88
|
-
when scanner.scan(/null/)
|
89
|
-
@q << [:tNULL, nil]
|
90
95
|
when scanner.scan(/[bB]?[rR]?#{STRING_LIT_REGEX}/) # string
|
91
96
|
# s = scanner.matched.yield_self {|s| s[1, s.length - 2] }
|
92
97
|
# .gsub(DBL_QUOTE_STR_ESCAPE_SEQUENCES_RE) do |match|
|
@@ -115,7 +120,13 @@ def tokenize(str)
|
|
115
120
|
end
|
116
121
|
when scanner.scan(IDENTIFIER_REGEX)
|
117
122
|
word = scanner.matched
|
118
|
-
if
|
123
|
+
if word == "null"
|
124
|
+
@q << [:tNULL, nil]
|
125
|
+
elsif word == "true"
|
126
|
+
@q << [:tBOOL, true]
|
127
|
+
elsif word == "false"
|
128
|
+
@q << [:tBOOL, false]
|
129
|
+
elsif RESERVED.include?(word)
|
119
130
|
@q << [:tRESERVED, scanner.matched]
|
120
131
|
elsif word == "in"
|
121
132
|
@q << [OPERATORS[scanner.matched], scanner.matched]
|
@@ -470,7 +481,7 @@ racc_reduce_table = [
|
|
470
481
|
1, 49, :_reduce_42,
|
471
482
|
0, 45, :_reduce_43,
|
472
483
|
1, 45, :_reduce_none,
|
473
|
-
5, 51, :
|
484
|
+
5, 51, :_reduce_45,
|
474
485
|
3, 51, :_reduce_46,
|
475
486
|
5, 50, :_reduce_47,
|
476
487
|
3, 50, :_reduce_48,
|
@@ -738,7 +749,7 @@ module_eval(<<'.,.,', 'parser.ry', 54)
|
|
738
749
|
|
739
750
|
module_eval(<<'.,.,', 'parser.ry', 55)
|
740
751
|
def _reduce_30(val, _values, result)
|
741
|
-
|
752
|
+
result = Cel::Invoke.new(func: val[0], args: [val[2]].flatten(1))
|
742
753
|
result
|
743
754
|
end
|
744
755
|
.,.,
|
@@ -774,7 +785,7 @@ module_eval(<<'.,.,', 'parser.ry', 58)
|
|
774
785
|
|
775
786
|
module_eval(<<'.,.,', 'parser.ry', 65)
|
776
787
|
def _reduce_38(val, _values, result)
|
777
|
-
result =
|
788
|
+
result = []
|
778
789
|
result
|
779
790
|
end
|
780
791
|
.,.,
|
@@ -811,7 +822,12 @@ module_eval(<<'.,.,', 'parser.ry', 73)
|
|
811
822
|
|
812
823
|
# reduce 44 omitted
|
813
824
|
|
814
|
-
|
825
|
+
module_eval(<<'.,.,', 'parser.ry', 76)
|
826
|
+
def _reduce_45(val, _values, result)
|
827
|
+
result = val[0].merge(Cel::Identifier.new(val[2]) => val[4])
|
828
|
+
result
|
829
|
+
end
|
830
|
+
.,.,
|
815
831
|
|
816
832
|
module_eval(<<'.,.,', 'parser.ry', 77)
|
817
833
|
def _reduce_46(val, _values, result)
|
data/lib/cel/program.rb
CHANGED
@@ -40,7 +40,7 @@ module Cel
|
|
40
40
|
def evaluate_literal(val)
|
41
41
|
case val
|
42
42
|
when List
|
43
|
-
List.new(val.value.map
|
43
|
+
List.new(val.value.map(&method(:call)))
|
44
44
|
else
|
45
45
|
val
|
46
46
|
end
|
@@ -62,9 +62,9 @@ module Cel
|
|
62
62
|
# unary operations
|
63
63
|
values.first.__send__(:"#{op}@")
|
64
64
|
elsif op == "&&"
|
65
|
-
Bool.new(values.all? { |x|
|
65
|
+
Bool.new(values.all? { |x| true == x }) # rubocop:disable Style/YodaCondition
|
66
66
|
elsif op == "||"
|
67
|
-
Bool.new(values.any? { |x|
|
67
|
+
Bool.new(values.any? { |x| true == x }) # rubocop:disable Style/YodaCondition
|
68
68
|
elsif op == "in"
|
69
69
|
element, collection = values
|
70
70
|
Bool.new(collection.include?(element))
|
@@ -110,6 +110,10 @@ module Cel
|
|
110
110
|
args ?
|
111
111
|
var.public_send(func, *args) :
|
112
112
|
var.public_send(func)
|
113
|
+
when Timestamp, Duration
|
114
|
+
raise EvaluateError, "#{invoke} is not supported" unless var.class.method_defined?(func, false)
|
115
|
+
|
116
|
+
var.public_send(func, *args)
|
113
117
|
else
|
114
118
|
raise EvaluateError, "#{invoke} is not supported"
|
115
119
|
end
|
@@ -133,15 +137,23 @@ module Cel
|
|
133
137
|
when :has, :size
|
134
138
|
Macro.__send__(func, *args)
|
135
139
|
when :matches
|
136
|
-
Macro.__send__(func, *args.map
|
137
|
-
when :int, :uint, :string, :double, :bytes
|
140
|
+
Macro.__send__(func, *args.map(&method(:call)))
|
141
|
+
when :int, :uint, :string, :double, :bytes, :duration, :timestamp
|
138
142
|
type = TYPES[func]
|
139
143
|
type.cast(call(args.first))
|
140
144
|
when :dyn
|
141
145
|
call(args.first)
|
142
146
|
else
|
147
|
+
return evaluate_custom_func(@context.declarations[func], funcall) if @context.declarations.key?(func)
|
148
|
+
|
143
149
|
raise EvaluateError, "#{funcall} is not supported"
|
144
150
|
end
|
145
151
|
end
|
152
|
+
|
153
|
+
def evaluate_custom_func(func, funcall)
|
154
|
+
args = funcall.args
|
155
|
+
|
156
|
+
func.call(*args.map(&method(:call)))
|
157
|
+
end
|
146
158
|
end
|
147
159
|
end
|
data/lib/cel/version.rb
CHANGED
data/lib/cel.rb
CHANGED
@@ -7,16 +7,11 @@ require "cel/ast/types"
|
|
7
7
|
require "cel/parser"
|
8
8
|
require "cel/macro"
|
9
9
|
require "cel/context"
|
10
|
+
require "cel/encoder" if RUBY_VERSION >= "3.1.0"
|
10
11
|
require "cel/checker"
|
11
12
|
require "cel/program"
|
12
13
|
require "cel/environment"
|
13
14
|
|
14
|
-
begin
|
15
|
-
require "google/protobuf/well_known_types"
|
16
|
-
require "cel/protobuf"
|
17
|
-
rescue LoadError # rubocop:disable Lint/SuppressedException
|
18
|
-
end
|
19
|
-
|
20
15
|
module Cel
|
21
16
|
def self.to_numeric(anything)
|
22
17
|
num = BigDecimal(anything.to_s)
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: cel
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Tiago Cardoso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2023-01-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: minitest
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: tzinfo
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
description: Pure Ruby implementation of Google Common Expression Language, https://opensource.google/projects/cel.
|
28
42
|
email:
|
29
43
|
- cardoso_tiago@hotmail.com
|
@@ -39,24 +53,25 @@ files:
|
|
39
53
|
- README.md
|
40
54
|
- lib/cel.rb
|
41
55
|
- lib/cel/ast/elements.rb
|
56
|
+
- lib/cel/ast/elements/protobuf.rb
|
42
57
|
- lib/cel/ast/types.rb
|
43
58
|
- lib/cel/checker.rb
|
44
59
|
- lib/cel/context.rb
|
60
|
+
- lib/cel/encoder.rb
|
45
61
|
- lib/cel/environment.rb
|
46
62
|
- lib/cel/errors.rb
|
47
63
|
- lib/cel/macro.rb
|
48
64
|
- lib/cel/parser.rb
|
49
65
|
- lib/cel/program.rb
|
50
|
-
- lib/cel/protobuf.rb
|
51
66
|
- lib/cel/version.rb
|
52
67
|
homepage:
|
53
68
|
licenses:
|
54
69
|
- Apache 2.0
|
55
70
|
metadata:
|
56
|
-
bug_tracker_uri: https://gitlab.com/
|
57
|
-
changelog_uri: https://gitlab.com/
|
58
|
-
source_code_uri: https://gitlab.com/
|
59
|
-
homepage_uri: https://gitlab.com/
|
71
|
+
bug_tracker_uri: https://gitlab.com/os85/cel-ruby/issues
|
72
|
+
changelog_uri: https://gitlab.com/os85/cel-ruby/-/blob/master/CHANGELOG.md
|
73
|
+
source_code_uri: https://gitlab.com/os85/cel-ruby
|
74
|
+
homepage_uri: https://gitlab.com/os85/cel-ruby
|
60
75
|
rubygems_mfa_required: 'true'
|
61
76
|
post_install_message:
|
62
77
|
rdoc_options: []
|