cel 0.2.3 → 0.3.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 +28 -0
- data/README.md +62 -8
- data/lib/cel/ast/elements/protobuf.rb +438 -90
- data/lib/cel/ast/elements.rb +367 -121
- data/lib/cel/ast/types.rb +153 -17
- data/lib/cel/checker.rb +133 -30
- data/lib/cel/context.rb +60 -12
- data/lib/cel/encoder.rb +31 -13
- data/lib/cel/environment.rb +63 -13
- data/lib/cel/errors.rb +22 -1
- data/lib/cel/macro.rb +94 -28
- data/lib/cel/parser.rb +603 -387
- data/lib/cel/program.rb +262 -48
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +232 -1
- metadata +19 -10
- data/lib/cel/parser.tab.rb +0 -1023
data/lib/cel/program.rb
CHANGED
@@ -2,8 +2,16 @@
|
|
2
2
|
|
3
3
|
module Cel
|
4
4
|
class Program
|
5
|
-
|
5
|
+
attr_reader :context
|
6
|
+
|
7
|
+
def initialize(context, environment)
|
6
8
|
@context = context
|
9
|
+
@environment = environment
|
10
|
+
@convert_to_cel = true
|
11
|
+
end
|
12
|
+
|
13
|
+
def with_extra_context(context)
|
14
|
+
self.class.new(@context.merge(context), @environment)
|
7
15
|
end
|
8
16
|
|
9
17
|
def evaluate(ast)
|
@@ -15,7 +23,7 @@ module Cel
|
|
15
23
|
when Operation
|
16
24
|
evaluate_operation(ast)
|
17
25
|
when Message
|
18
|
-
ast
|
26
|
+
evaluate_message(ast)
|
19
27
|
when Literal
|
20
28
|
evaluate_literal(ast)
|
21
29
|
when Identifier
|
@@ -27,13 +35,36 @@ module Cel
|
|
27
35
|
|
28
36
|
alias_method :call, :evaluate
|
29
37
|
|
38
|
+
def disable_cel_conversion
|
39
|
+
convert_to_cel = @convert_to_cel
|
40
|
+
begin
|
41
|
+
@convert_to_cel = false
|
42
|
+
yield(convert_to_cel)
|
43
|
+
ensure
|
44
|
+
@convert_to_cel = convert_to_cel
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
30
48
|
private
|
31
49
|
|
50
|
+
def try_evaluate_lookup(key)
|
51
|
+
Protobuf.convert_to_proto_type(key, @package) || begin
|
52
|
+
Literal.to_cel_type(evaluate_identifier(key))
|
53
|
+
rescue EvaluateError # rubocop:disable Lint/SuppressedException
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
32
57
|
def evaluate_identifier(identifier)
|
33
58
|
if Cel::PRIMITIVE_TYPES.include?(identifier.to_sym)
|
34
59
|
TYPES[identifier.to_sym]
|
35
60
|
else
|
36
|
-
@context.lookup(identifier)
|
61
|
+
val, func = @context.lookup(identifier)
|
62
|
+
|
63
|
+
if func
|
64
|
+
evaluate_invoke(Cel::Invoke.new(var: val, func: func))
|
65
|
+
else
|
66
|
+
Literal.to_cel_type(val)
|
67
|
+
end
|
37
68
|
end
|
38
69
|
end
|
39
70
|
|
@@ -46,30 +77,113 @@ module Cel
|
|
46
77
|
end
|
47
78
|
end
|
48
79
|
|
49
|
-
def
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
80
|
+
def evaluate_message(val)
|
81
|
+
disable_cel_conversion do |should_have_converted|
|
82
|
+
values = val.struct.transform_values do |value|
|
83
|
+
v = call(value)
|
84
|
+
v = v.to_ruby_type if v.respond_to?(:to_ruby_type)
|
85
|
+
v
|
86
|
+
end
|
87
|
+
value = Protobuf.convert_to_proto(val.message_type, values)
|
54
88
|
|
55
|
-
|
89
|
+
return value unless should_have_converted
|
56
90
|
|
57
|
-
|
91
|
+
Literal.to_cel_type(value)
|
58
92
|
end
|
93
|
+
end
|
94
|
+
|
95
|
+
def evaluate_operation(operation)
|
96
|
+
op = operation.op
|
97
|
+
|
98
|
+
operands = operation.operands
|
59
99
|
|
60
100
|
if operation.unary? &&
|
61
101
|
op != "!" # https://bugs.ruby-lang.org/issues/18246
|
62
102
|
# unary operations
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
103
|
+
operand = operands.first
|
104
|
+
op_value = call(operand)
|
105
|
+
value = Literal.to_cel_type(op_value.__send__(:"#{op}@"))
|
106
|
+
value.check_overflow unless operand.is_a?(Literal)
|
107
|
+
return value
|
108
|
+
end
|
109
|
+
|
110
|
+
case op
|
111
|
+
when "&&"
|
112
|
+
error = nil
|
113
|
+
last_op = nil
|
114
|
+
|
115
|
+
operands.each do |x|
|
116
|
+
op_value = call(x)
|
117
|
+
|
118
|
+
raise NoMatchingOverloadError, op unless op_value.type == TYPES[:bool]
|
119
|
+
|
120
|
+
result = true == op_value.value # rubocop:disable Style/YodaCondition
|
121
|
+
|
122
|
+
if error
|
123
|
+
# save for later processing
|
124
|
+
last_op = result
|
125
|
+
next
|
126
|
+
end
|
127
|
+
|
128
|
+
return Bool.cast(false) unless result
|
129
|
+
rescue StandardError => e
|
130
|
+
error = e
|
131
|
+
end
|
132
|
+
|
133
|
+
# if an error happened, but it was succeeded by an operation evaluating to true,
|
134
|
+
# then the latter wins
|
135
|
+
raise error if error && (last_op.nil? || last_op == true)
|
136
|
+
|
137
|
+
Bool.cast(last_op.nil? || last_op)
|
138
|
+
when "||"
|
139
|
+
error = nil
|
140
|
+
last_op = nil
|
141
|
+
|
142
|
+
operands.each do |x|
|
143
|
+
op_value = call(x)
|
144
|
+
|
145
|
+
raise NoMatchingOverloadError, op unless op_value.type == TYPES[:bool]
|
146
|
+
|
147
|
+
result = true == op_value.value # rubocop:disable Style/YodaCondition
|
148
|
+
|
149
|
+
if error
|
150
|
+
# save for later processing
|
151
|
+
last_op = result
|
152
|
+
next
|
153
|
+
end
|
154
|
+
|
155
|
+
return Bool.cast(true) if result
|
156
|
+
rescue StandardError => e
|
157
|
+
error = e
|
158
|
+
end
|
159
|
+
|
160
|
+
# if an error happened, but it was succeeded by an operation evaluating to true,
|
161
|
+
# then the latter wins
|
162
|
+
raise error if error && (last_op.nil? || last_op == false)
|
163
|
+
|
164
|
+
Bool.cast(last_op.nil? ? false : last_op)
|
165
|
+
when "in"
|
166
|
+
collection, element = operands.reverse_each.map(&method(:call))
|
167
|
+
Bool.cast(collection.include?(element))
|
168
|
+
when "!"
|
169
|
+
op_value, = operands.map(&method(:call))
|
170
|
+
|
171
|
+
raise InvalidArgumentError, op_value unless op_value.type == TYPES[:bool]
|
172
|
+
|
173
|
+
Bool.cast(!op_value.value)
|
174
|
+
when "=="
|
175
|
+
operands = operands.map(&method(:call))
|
176
|
+
|
177
|
+
# ensure that the op is called on the cel-side override
|
178
|
+
lhs, rhs = operands.sort_by do |t|
|
179
|
+
t.is_a?(Class) && t < Protobuf.base_class ? 1 : 0
|
180
|
+
end
|
181
|
+
|
182
|
+
val = lhs.public_send(op, rhs)
|
183
|
+
|
184
|
+
Literal.to_cel_type(val)
|
71
185
|
else
|
72
|
-
op_value, *values =
|
186
|
+
op_value, *values = operands.map(&method(:call))
|
73
187
|
val = op_value.public_send(op, *values)
|
74
188
|
|
75
189
|
Literal.to_cel_type(val)
|
@@ -77,52 +191,138 @@ module Cel
|
|
77
191
|
end
|
78
192
|
|
79
193
|
def evaluate_invoke(invoke, var = invoke.var)
|
194
|
+
return evaluate_standard_func(invoke) unless var
|
195
|
+
|
80
196
|
func = invoke.func
|
81
197
|
args = invoke.args
|
82
198
|
|
83
|
-
|
199
|
+
var =
|
200
|
+
case var
|
201
|
+
when Identifier
|
202
|
+
if (proto_type = var.try_convert_to_proto_type)
|
203
|
+
return evaluate_invoke(invoke, proto_type)
|
204
|
+
end
|
84
205
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
206
|
+
# try stuff like a.b.c
|
207
|
+
return evaluate_identifier(invoke.to_s) if args.nil?
|
208
|
+
|
209
|
+
evaluate_identifier(var)
|
210
|
+
|
211
|
+
when Invoke
|
212
|
+
if args.nil?
|
213
|
+
# try stuff like a.b.c before trying a.b then c
|
214
|
+
val = try_evaluate_lookup(invoke.to_s)
|
215
|
+
|
216
|
+
return val if val
|
217
|
+
end
|
218
|
+
|
219
|
+
evaluate_invoke(var)
|
220
|
+
else
|
221
|
+
call(var)
|
222
|
+
end || var
|
93
223
|
|
94
224
|
case var
|
95
225
|
when String
|
96
226
|
raise EvaluateError, "#{invoke} is not supported" unless String.method_defined?(func, false)
|
97
227
|
|
98
228
|
var.public_send(func, *args.map(&method(:call)))
|
99
|
-
when
|
100
|
-
|
101
|
-
# runtime error no_such_field is raised.
|
102
|
-
raise NoSuchFieldError.new(var, func) unless var.field?(func)
|
229
|
+
when Map
|
230
|
+
return Macro.__send__(func, var, *args, program: self) if !Module.respond_to?(func) && Macro.respond_to?(func)
|
103
231
|
|
104
|
-
|
105
|
-
|
106
|
-
|
232
|
+
# If e evaluates to a map, then e.f is equivalent to e['f'] (where f is
|
233
|
+
# still being used as a meta-variable, e.g. the expression x.foo is equivalent
|
234
|
+
# to the expression x['foo'] when x evaluates to a map).
|
235
|
+
|
236
|
+
if args
|
237
|
+
var.public_send(func, *args)
|
238
|
+
else
|
239
|
+
begin
|
240
|
+
var.public_send(func)
|
241
|
+
rescue NoMethodError
|
242
|
+
raise NoSuchKeyError.new(var, func)
|
243
|
+
end
|
244
|
+
end
|
245
|
+
when List
|
246
|
+
return Macro.__send__(func, var, *args, program: self) if !Module.respond_to?(func) && Macro.respond_to?(func)
|
107
247
|
|
108
248
|
# If e evaluates to a map, then e.f is equivalent to e['f'] (where f is
|
109
249
|
# still being used as a meta-variable, e.g. the expression x.foo is equivalent
|
110
250
|
# to the expression x['foo'] when x evaluates to a map).
|
111
251
|
|
112
252
|
args ?
|
113
|
-
var.public_send(func, *args) :
|
253
|
+
var.public_send(func, *Array(args).map(&method(:call))) :
|
114
254
|
var.public_send(func)
|
115
255
|
when Timestamp, Duration
|
116
256
|
raise EvaluateError, "#{invoke} is not supported" unless var.class.method_defined?(func, false)
|
117
257
|
|
258
|
+
# eliminate protobuf API from the lookup
|
259
|
+
raise NoMatchingOverloadError.new(var, func) if Protobuf.base_class.instance_methods.include?(func)
|
260
|
+
|
261
|
+
# If e evaluates to a message and f is not declared in this message, the
|
262
|
+
# runtime error no_such_field is raised.
|
263
|
+
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
264
|
+
|
118
265
|
var.public_send(func, *args)
|
266
|
+
when Literal
|
267
|
+
# eliminate ruby API from the lookup
|
268
|
+
raise NoMatchingOverloadError.new(var, func) if Literal.instance_methods.include?(func)
|
269
|
+
|
270
|
+
# If e evaluates to a message and f is not declared in this message, the
|
271
|
+
# runtime error no_such_field is raised.
|
272
|
+
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
273
|
+
|
274
|
+
var.public_send(func)
|
275
|
+
when Protobuf.base_class
|
276
|
+
# eliminate protobuf API from the lookup
|
277
|
+
raise NoMatchingOverloadError.new(var, func) if Protobuf.base_class.instance_methods.include?(func)
|
278
|
+
|
279
|
+
# If e evaluates to a message and f is not declared in this message, the
|
280
|
+
# runtime error no_such_field is raised.
|
281
|
+
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
282
|
+
|
283
|
+
value = Protobuf.lookup(var, func)
|
284
|
+
|
285
|
+
Literal.to_cel_type(value)
|
119
286
|
else
|
287
|
+
if var.is_a?(Module) && var.const_defined?(func)
|
288
|
+
# this block assumes a message based call on a protobuf message, either to a
|
289
|
+
# subclass/namespace (Foo.Bar), or an enum (Foo.BAR)
|
290
|
+
# protobuf accessing enum module
|
291
|
+
enum = var.const_get(func)
|
292
|
+
|
293
|
+
if args.nil?
|
294
|
+
case enum
|
295
|
+
when Integer
|
296
|
+
# enum lookup
|
297
|
+
return Protobuf.convert_to_enum(enum, var)
|
298
|
+
else
|
299
|
+
return enum
|
300
|
+
end
|
301
|
+
else
|
302
|
+
arg = call(args.first)
|
303
|
+
value = case arg
|
304
|
+
when Number
|
305
|
+
Protobuf.convert_to_enum(arg.value, enum)
|
306
|
+
when String
|
307
|
+
resolved_arg = enum.resolve(arg.to_sym)
|
308
|
+
raise EvaluateError, "#{arg} is invalid" unless resolved_arg
|
309
|
+
|
310
|
+
Protobuf.convert_to_enum(resolved_arg, enum)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
return Literal.to_cel_type(value)
|
314
|
+
end
|
315
|
+
|
120
316
|
raise EvaluateError, "#{invoke} is not supported"
|
121
317
|
end
|
122
318
|
end
|
123
319
|
|
124
320
|
def evaluate_condition(condition)
|
125
|
-
|
321
|
+
if_value = call(condition.if)
|
322
|
+
|
323
|
+
raise InvalidArgument, condition.if unless if_value.type == TYPES[:bool]
|
324
|
+
|
325
|
+
if_value.value ? call(condition.then) : call(condition.else)
|
126
326
|
end
|
127
327
|
|
128
328
|
def evaluate_standard_func(funcall)
|
@@ -131,25 +331,39 @@ module Cel
|
|
131
331
|
|
132
332
|
case func
|
133
333
|
when :type
|
134
|
-
|
135
|
-
|
334
|
+
operand = args.first
|
335
|
+
val = call(operand)
|
336
|
+
case val
|
337
|
+
when Protobuf.enum_class
|
338
|
+
val.enum_type
|
339
|
+
else
|
340
|
+
if val.respond_to?(:type)
|
341
|
+
val.type
|
342
|
+
else
|
343
|
+
val.class
|
344
|
+
end
|
345
|
+
end
|
136
346
|
|
137
|
-
val.class
|
138
347
|
# MACROS
|
139
|
-
when :has
|
140
|
-
Macro.__send__(func, *args)
|
141
|
-
when :
|
142
|
-
Cel::Number.new(:int, Macro.__send__(func, *args))
|
143
|
-
when :matches
|
144
|
-
Macro.__send__(func, *args.map(&method(:call)))
|
145
|
-
when :int, :uint, :string, :double, :bytes, :duration, :timestamp
|
348
|
+
when :has, :matches, :size
|
349
|
+
Macro.__send__(func, *args, program: self)
|
350
|
+
when :int, :uint, :string, :double, :bytes, :duration, :timestamp, :bool
|
146
351
|
type = TYPES[func]
|
147
|
-
|
352
|
+
op_value = call(args.first)
|
353
|
+
type.cast(op_value)
|
148
354
|
when :dyn
|
149
355
|
call(args.first)
|
150
356
|
else
|
151
357
|
return evaluate_custom_func(@context.declarations[func], funcall) if @context.declarations.key?(func)
|
152
358
|
|
359
|
+
# enum conversion
|
360
|
+
proto_type = Protobuf.convert_to_proto_type(func.to_s, @environment.package)
|
361
|
+
|
362
|
+
if proto_type && proto_type.respond_to?(:resolve)
|
363
|
+
op_value = call(args.first)
|
364
|
+
return Protobuf.convert_to_enum(op_value.value)
|
365
|
+
end
|
366
|
+
|
153
367
|
raise EvaluateError, "#{funcall} is not supported"
|
154
368
|
end
|
155
369
|
end
|
data/lib/cel/version.rb
CHANGED
data/lib/cel.rb
CHANGED
@@ -4,6 +4,7 @@ require "bigdecimal"
|
|
4
4
|
require "cel/version"
|
5
5
|
require "cel/errors"
|
6
6
|
require "cel/ast/types"
|
7
|
+
require "cel/ast/elements"
|
7
8
|
require "cel/parser"
|
8
9
|
require "cel/macro"
|
9
10
|
require "cel/context"
|
@@ -12,8 +13,227 @@ require "cel/checker"
|
|
12
13
|
require "cel/program"
|
13
14
|
require "cel/environment"
|
14
15
|
|
16
|
+
begin
|
17
|
+
require "tzinfo"
|
18
|
+
rescue LoadError # rubocop:disable Lint/SuppressedException
|
19
|
+
end
|
20
|
+
|
21
|
+
begin
|
22
|
+
require "cel/ast/elements/protobuf"
|
23
|
+
rescue LoadError => e
|
24
|
+
puts e
|
25
|
+
module Cel
|
26
|
+
class << self
|
27
|
+
# returns a struct class containing the attributes that one would
|
28
|
+
# have expected from the protobuf stub equivalent.
|
29
|
+
def message_container(name, struct)
|
30
|
+
mod = Cel.package_to_module_name(name.to_s)
|
31
|
+
|
32
|
+
if Object.const_defined?(mod)
|
33
|
+
Object.const_get(mod)
|
34
|
+
else
|
35
|
+
struct_keys = container_struct_keys(mod, struct)
|
36
|
+
struct_class = container_struct(mod, struct_keys)
|
37
|
+
|
38
|
+
klass = Object
|
39
|
+
|
40
|
+
*namespaces, mod = mod.split("::")
|
41
|
+
|
42
|
+
namespaces.each do |nm|
|
43
|
+
klass = if klass.const_defined?(nm)
|
44
|
+
klass.const_get(nm)
|
45
|
+
else
|
46
|
+
klass.const_set(nm, Module.new)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
klass.const_set(mod, struct_class)
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def container_struct(mod, struct_keys)
|
55
|
+
::Struct.new(*struct_keys, keyword_init: true) do
|
56
|
+
case mod
|
57
|
+
when "Google::Protobuf::BytesValue",
|
58
|
+
"Google::Protobuf::Int32Value",
|
59
|
+
"Google::Protobuf::Int64Value",
|
60
|
+
"Google::Protobuf::UInt32Value",
|
61
|
+
"Google::Protobuf::UInt64Value",
|
62
|
+
"Google::Protobuf::DoubleValue",
|
63
|
+
"Google::Protobuf::FloatValue"
|
64
|
+
|
65
|
+
def initialize(*, **)
|
66
|
+
super
|
67
|
+
self.value ||= 0
|
68
|
+
end
|
69
|
+
when "Google::Protobuf::StringValue"
|
70
|
+
def initialize(*, **)
|
71
|
+
super
|
72
|
+
self.value ||= ""
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def container_struct_keys(mod, struct)
|
79
|
+
keys = struct.nil? ? [] : struct.keys
|
80
|
+
|
81
|
+
# handle wrapper types
|
82
|
+
case mod
|
83
|
+
when "Google::Protobuf::Any"
|
84
|
+
keys.push(:type_url, :value)
|
85
|
+
when "Google::Protobuf::ListValue"
|
86
|
+
keys << :values
|
87
|
+
when "Google::Protobuf::Struct"
|
88
|
+
keys << :fields
|
89
|
+
when "Google::Protobuf::Value"
|
90
|
+
keys.push(:bool_value, :number_value, :int64_value, :uint64_value, :double_value, :string_value,
|
91
|
+
:bytes_value, :enum_value, :object_value, :struct_value, :map_value, :list_value, :type_value)
|
92
|
+
when "Google::Protobuf::BytesValue",
|
93
|
+
"Google::Protobuf::Int32Value",
|
94
|
+
"Google::Protobuf::Int64Value",
|
95
|
+
"Google::Protobuf::UInt32Value",
|
96
|
+
"Google::Protobuf::UInt64Value",
|
97
|
+
"Google::Protobuf::DoubleValue",
|
98
|
+
"Google::Protobuf::FloatValue",
|
99
|
+
"Google::Protobuf::BoolValue",
|
100
|
+
"Google::Protobuf::NullValue",
|
101
|
+
"Google::Protobuf::StringValue"
|
102
|
+
keys << :value
|
103
|
+
when "Google::Protobuf::Timestamp",
|
104
|
+
"Google::Protobuf::Duration"
|
105
|
+
keys.push(:seconds, :nanos)
|
106
|
+
end
|
107
|
+
|
108
|
+
keys.uniq
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
module Protobuf
|
113
|
+
module_function
|
114
|
+
|
115
|
+
BASE_CLASS = Class.new(Object)
|
116
|
+
|
117
|
+
def base_class
|
118
|
+
Struct
|
119
|
+
end
|
120
|
+
|
121
|
+
def enum_class
|
122
|
+
BASE_CLASS
|
123
|
+
end
|
124
|
+
|
125
|
+
def map_class
|
126
|
+
BASE_CLASS
|
127
|
+
end
|
128
|
+
|
129
|
+
def timestamp_class
|
130
|
+
BASE_CLASS
|
131
|
+
end
|
132
|
+
|
133
|
+
def duration_class
|
134
|
+
BASE_CLASS
|
135
|
+
end
|
136
|
+
|
137
|
+
def convert_to_proto(message_type, values)
|
138
|
+
message_type.new(**values)
|
139
|
+
end
|
140
|
+
|
141
|
+
def convert_to_proto_type(*); end
|
142
|
+
|
143
|
+
def try_invoke_from(var, func, args)
|
144
|
+
case var
|
145
|
+
when "NullValue", "google.protobuf.NullValue"
|
146
|
+
|
147
|
+
Cel::Null.new if func == "NULL_VALUE" && args.nil?
|
148
|
+
|
149
|
+
end
|
150
|
+
end
|
151
|
+
|
152
|
+
def try_convert_from_wrapper(struct)
|
153
|
+
case struct.class.name
|
154
|
+
when "ListValue", "Google::Protobuf::ListValue"
|
155
|
+
struct.values
|
156
|
+
when "Struct", "Google::Protobuf::Struct"
|
157
|
+
struct.fields
|
158
|
+
when "Value", "Google::Protobuf::Value"
|
159
|
+
_, value = struct.each_pair.find { |_, v| !v.nil? }
|
160
|
+
|
161
|
+
try_convert_from_wrapper(value)
|
162
|
+
when "BytesValue", "Google::Protobuf::BytesValue"
|
163
|
+
Cel::Bytes.new(struct.value.bytes)
|
164
|
+
when "Int32Value", "Google::Protobuf::Int32Value",
|
165
|
+
"Int64Value", "Google::Protobuf::Int64Value"
|
166
|
+
Cel::Number.new(:int, struct.value)
|
167
|
+
when "UInt32Value", "Google::Protobuf::UInt32Value",
|
168
|
+
"UInt64Value", "Google::Protobuf::UInt64Value"
|
169
|
+
Cel::Number.new(:uint, struct.value)
|
170
|
+
when "DoubleValue", "Google::Protobuf::DoubleValue",
|
171
|
+
"FloatValue", "Google::Protobuf::FloatValue"
|
172
|
+
Cel::Number.new(:double, struct.value)
|
173
|
+
when "BoolValue", "Google::Protobuf::BoolValue",
|
174
|
+
"NullValue", "Google::Protobuf::NullValue",
|
175
|
+
"StringValue", "Google::Protobuf::StringValue"
|
176
|
+
struct.value
|
177
|
+
when "Google::Protobuf::Timestamp"
|
178
|
+
value = (struct.seconds || 0) +
|
179
|
+
((struct.nanos || 0) / 1_000_000)
|
180
|
+
Cel::Timestamp.new(value)
|
181
|
+
when "Google::Protobuf::Duration"
|
182
|
+
value = (struct.seconds || 0) +
|
183
|
+
((struct.nanos || 0) / 1_000_000)
|
184
|
+
Cel::Duration.new(value)
|
185
|
+
else
|
186
|
+
struct
|
187
|
+
end
|
188
|
+
end
|
189
|
+
|
190
|
+
def try_convert_from_wrapper_type(type)
|
191
|
+
case type
|
192
|
+
when "Any", "google.protobuf.Any",
|
193
|
+
"Value", "google.protobuf.Value"
|
194
|
+
TYPES[:any]
|
195
|
+
when "ListValue", "google.protobuf.ListValue"
|
196
|
+
TYPES[:list]
|
197
|
+
when "BytesValue", "google.protobuf.BytesValue"
|
198
|
+
TYPES[:bytes]
|
199
|
+
when "Int32Value", "google.protobuf.Int32Value",
|
200
|
+
"Int64Value", "google.protobuf.Int64Value"
|
201
|
+
TYPES[:int]
|
202
|
+
when "UInt32Value", "google.protobuf.UInt32Value",
|
203
|
+
"UInt64Value", "google.protobuf.UInt64Value"
|
204
|
+
TYPES[:uint]
|
205
|
+
when "DoubleValue", "google.protobuf.DoubleValue",
|
206
|
+
"FloatValue", "google.protobuf.FloatValue"
|
207
|
+
TYPES[:double]
|
208
|
+
when "BoolValue", "google.protobuf.BoolValue"
|
209
|
+
TYPES[:bool]
|
210
|
+
when "NullValue", "google.protobuf.NullValue"
|
211
|
+
TYPES[:null]
|
212
|
+
when "StringValue", "google.protobuf.StringValue"
|
213
|
+
TYPES[:string]
|
214
|
+
when "google.protobuf.Timestamp"
|
215
|
+
TYPES[:timestamp]
|
216
|
+
when "google.protobuf.Duration"
|
217
|
+
TYPES[:duration]
|
218
|
+
else
|
219
|
+
TYPES[:map]
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
def method_missing(*) # rubocop:disable Style/MissingRespondToMissing
|
224
|
+
raise Cel::Error, "\"google/protobuf\" is required in order to use this feature"
|
225
|
+
end
|
226
|
+
end
|
227
|
+
end
|
228
|
+
end
|
229
|
+
|
15
230
|
module Cel
|
16
|
-
|
231
|
+
MAX_INT = (2**63)
|
232
|
+
MAX_FLOAT = (2**63)
|
233
|
+
|
234
|
+
module_function
|
235
|
+
|
236
|
+
def to_numeric(anything)
|
17
237
|
num = BigDecimal(anything.to_s)
|
18
238
|
if num.frac.zero?
|
19
239
|
num.to_i
|
@@ -21,4 +241,15 @@ module Cel
|
|
21
241
|
num.to_f
|
22
242
|
end
|
23
243
|
end
|
244
|
+
|
245
|
+
def package_to_module_name(type)
|
246
|
+
namespace, type_msg = type.split("/", 2)
|
247
|
+
type_msg ||= namespace # sometimes there's no namespace
|
248
|
+
|
249
|
+
return unless /[[:upper:]]/.match?(type_msg)
|
250
|
+
|
251
|
+
type_msg.split(".").map do |typ|
|
252
|
+
/[[:upper:]]/.match?(typ[0]) ? typ : typ.capitalize
|
253
|
+
end.join("::")
|
254
|
+
end
|
24
255
|
end
|