cel 0.2.3 → 0.3.0
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 +17 -0
- data/README.md +23 -1
- data/lib/cel/ast/elements/protobuf.rb +411 -66
- data/lib/cel/ast/elements.rb +339 -113
- data/lib/cel/ast/types.rb +151 -15
- data/lib/cel/checker.rb +133 -30
- data/lib/cel/context.rb +55 -6
- data/lib/cel/encoder.rb +31 -13
- data/lib/cel/environment.rb +58 -13
- data/lib/cel/errors.rb +19 -1
- data/lib/cel/macro.rb +91 -26
- data/lib/cel/parser.rb +428 -396
- data/lib/cel/program.rb +255 -48
- data/lib/cel/version.rb +1 -1
- data/lib/cel.rb +232 -1
- metadata +18 -9
- 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
|
@@ -29,11 +37,24 @@ module Cel
|
|
29
37
|
|
30
38
|
private
|
31
39
|
|
40
|
+
def try_evaluate_lookup(key)
|
41
|
+
Protobuf.convert_to_proto_type(key, @package) || begin
|
42
|
+
Literal.to_cel_type(evaluate_identifier(key))
|
43
|
+
rescue EvaluateError # rubocop:disable Lint/SuppressedException
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
32
47
|
def evaluate_identifier(identifier)
|
33
48
|
if Cel::PRIMITIVE_TYPES.include?(identifier.to_sym)
|
34
49
|
TYPES[identifier.to_sym]
|
35
50
|
else
|
36
|
-
@context.lookup(identifier)
|
51
|
+
val, func = @context.lookup(identifier)
|
52
|
+
|
53
|
+
if func
|
54
|
+
evaluate_invoke(Cel::Invoke.new(var: val, func: func))
|
55
|
+
else
|
56
|
+
Literal.to_cel_type(val)
|
57
|
+
end
|
37
58
|
end
|
38
59
|
end
|
39
60
|
|
@@ -46,30 +67,116 @@ module Cel
|
|
46
67
|
end
|
47
68
|
end
|
48
69
|
|
49
|
-
def
|
50
|
-
|
70
|
+
def evaluate_message(val)
|
71
|
+
convert_to_cel = @convert_to_cel
|
72
|
+
|
73
|
+
@convert_to_cel = false
|
74
|
+
values = val.struct.transform_values do |value|
|
75
|
+
v = call(value)
|
76
|
+
v = v.to_ruby_type if v.respond_to?(:to_ruby_type)
|
77
|
+
v
|
78
|
+
end
|
79
|
+
value = Protobuf.convert_to_proto(val.message_type, values)
|
51
80
|
|
52
|
-
|
53
|
-
ev_operand = call(operand)
|
81
|
+
return value unless convert_to_cel
|
54
82
|
|
55
|
-
|
83
|
+
Literal.to_cel_type(value)
|
84
|
+
ensure
|
85
|
+
@convert_to_cel = convert_to_cel
|
86
|
+
end
|
56
87
|
|
57
|
-
|
58
|
-
|
88
|
+
def evaluate_operation(operation)
|
89
|
+
op = operation.op
|
90
|
+
|
91
|
+
operands = operation.operands
|
59
92
|
|
60
93
|
if operation.unary? &&
|
61
94
|
op != "!" # https://bugs.ruby-lang.org/issues/18246
|
62
95
|
# unary operations
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
96
|
+
operand = operands.first
|
97
|
+
op_value = call(operand)
|
98
|
+
value = Literal.to_cel_type(op_value.__send__(:"#{op}@"))
|
99
|
+
value.check_overflow unless operand.is_a?(Literal)
|
100
|
+
return value
|
101
|
+
end
|
102
|
+
|
103
|
+
case op
|
104
|
+
when "&&"
|
105
|
+
error = nil
|
106
|
+
last_op = nil
|
107
|
+
|
108
|
+
operands.each do |x|
|
109
|
+
op_value = call(x)
|
110
|
+
|
111
|
+
raise NoMatchingOverloadError, op unless op_value.type == TYPES[:bool]
|
112
|
+
|
113
|
+
result = true == op_value.value # rubocop:disable Style/YodaCondition
|
114
|
+
|
115
|
+
if error
|
116
|
+
# save for later processing
|
117
|
+
last_op = result
|
118
|
+
next
|
119
|
+
end
|
120
|
+
|
121
|
+
return Bool.cast(false) unless result
|
122
|
+
rescue StandardError => e
|
123
|
+
error = e
|
124
|
+
end
|
125
|
+
|
126
|
+
# if an error happened, but it was succeeded by an operation evaluating to true,
|
127
|
+
# then the latter wins
|
128
|
+
raise error if error && (last_op.nil? || last_op == true)
|
129
|
+
|
130
|
+
Bool.cast(last_op.nil? || last_op)
|
131
|
+
when "||"
|
132
|
+
error = nil
|
133
|
+
last_op = nil
|
134
|
+
|
135
|
+
operands.each do |x|
|
136
|
+
op_value = call(x)
|
137
|
+
|
138
|
+
raise NoMatchingOverloadError, op unless op_value.type == TYPES[:bool]
|
139
|
+
|
140
|
+
result = true == op_value.value # rubocop:disable Style/YodaCondition
|
141
|
+
|
142
|
+
if error
|
143
|
+
# save for later processing
|
144
|
+
last_op = result
|
145
|
+
next
|
146
|
+
end
|
147
|
+
|
148
|
+
return Bool.cast(true) if result
|
149
|
+
rescue StandardError => e
|
150
|
+
error = e
|
151
|
+
end
|
152
|
+
|
153
|
+
# if an error happened, but it was succeeded by an operation evaluating to true,
|
154
|
+
# then the latter wins
|
155
|
+
raise error if error && (last_op.nil? || last_op == false)
|
156
|
+
|
157
|
+
Bool.cast(last_op.nil? ? false : last_op)
|
158
|
+
when "in"
|
159
|
+
collection, element = operands.reverse_each.map(&method(:call))
|
160
|
+
Bool.cast(collection.include?(element))
|
161
|
+
when "!"
|
162
|
+
op_value, = operands.map(&method(:call))
|
163
|
+
|
164
|
+
raise InvalidArgumentError, op_value unless op_value.type == TYPES[:bool]
|
165
|
+
|
166
|
+
Bool.cast(!op_value.value)
|
167
|
+
when "=="
|
168
|
+
operands = operands.map(&method(:call))
|
169
|
+
|
170
|
+
# ensure that the op is called on the cel-side override
|
171
|
+
lhs, rhs = operands.sort_by do |t|
|
172
|
+
t.is_a?(Class) && t < Protobuf.base_class ? 1 : 0
|
173
|
+
end
|
174
|
+
|
175
|
+
val = lhs.public_send(op, rhs)
|
176
|
+
|
177
|
+
Literal.to_cel_type(val)
|
71
178
|
else
|
72
|
-
op_value, *values =
|
179
|
+
op_value, *values = operands.map(&method(:call))
|
73
180
|
val = op_value.public_send(op, *values)
|
74
181
|
|
75
182
|
Literal.to_cel_type(val)
|
@@ -77,52 +184,138 @@ module Cel
|
|
77
184
|
end
|
78
185
|
|
79
186
|
def evaluate_invoke(invoke, var = invoke.var)
|
187
|
+
return evaluate_standard_func(invoke) unless var
|
188
|
+
|
80
189
|
func = invoke.func
|
81
190
|
args = invoke.args
|
82
191
|
|
83
|
-
|
192
|
+
var =
|
193
|
+
case var
|
194
|
+
when Identifier
|
195
|
+
if (proto_type = var.try_convert_to_proto_type)
|
196
|
+
return evaluate_invoke(invoke, proto_type)
|
197
|
+
end
|
84
198
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
199
|
+
# try stuff like a.b.c
|
200
|
+
return evaluate_identifier(invoke.to_s) if args.nil?
|
201
|
+
|
202
|
+
evaluate_identifier(var)
|
203
|
+
|
204
|
+
when Invoke
|
205
|
+
if args.nil?
|
206
|
+
# try stuff like a.b.c before trying a.b then c
|
207
|
+
val = try_evaluate_lookup(invoke.to_s)
|
208
|
+
|
209
|
+
return val if val
|
210
|
+
end
|
211
|
+
|
212
|
+
evaluate_invoke(var)
|
213
|
+
else
|
214
|
+
call(var)
|
215
|
+
end || var
|
93
216
|
|
94
217
|
case var
|
95
218
|
when String
|
96
219
|
raise EvaluateError, "#{invoke} is not supported" unless String.method_defined?(func, false)
|
97
220
|
|
98
221
|
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)
|
222
|
+
when Map
|
223
|
+
return Macro.__send__(func, var, *args, program: self) if !Module.respond_to?(func) && Macro.respond_to?(func)
|
103
224
|
|
104
|
-
|
105
|
-
|
106
|
-
|
225
|
+
# If e evaluates to a map, then e.f is equivalent to e['f'] (where f is
|
226
|
+
# still being used as a meta-variable, e.g. the expression x.foo is equivalent
|
227
|
+
# to the expression x['foo'] when x evaluates to a map).
|
228
|
+
|
229
|
+
if args
|
230
|
+
var.public_send(func, *args)
|
231
|
+
else
|
232
|
+
begin
|
233
|
+
var.public_send(func)
|
234
|
+
rescue NoMethodError
|
235
|
+
raise NoSuchKeyError.new(var, func)
|
236
|
+
end
|
237
|
+
end
|
238
|
+
when List
|
239
|
+
return Macro.__send__(func, var, *args, program: self) if !Module.respond_to?(func) && Macro.respond_to?(func)
|
107
240
|
|
108
241
|
# If e evaluates to a map, then e.f is equivalent to e['f'] (where f is
|
109
242
|
# still being used as a meta-variable, e.g. the expression x.foo is equivalent
|
110
243
|
# to the expression x['foo'] when x evaluates to a map).
|
111
244
|
|
112
245
|
args ?
|
113
|
-
var.public_send(func, *args) :
|
246
|
+
var.public_send(func, *Array(args).map(&method(:call))) :
|
114
247
|
var.public_send(func)
|
115
248
|
when Timestamp, Duration
|
116
249
|
raise EvaluateError, "#{invoke} is not supported" unless var.class.method_defined?(func, false)
|
117
250
|
|
251
|
+
# eliminate protobuf API from the lookup
|
252
|
+
raise NoMatchingOverloadError.new(var, func) if Protobuf.base_class.instance_methods.include?(func)
|
253
|
+
|
254
|
+
# If e evaluates to a message and f is not declared in this message, the
|
255
|
+
# runtime error no_such_field is raised.
|
256
|
+
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
257
|
+
|
118
258
|
var.public_send(func, *args)
|
259
|
+
when Literal
|
260
|
+
# eliminate ruby API from the lookup
|
261
|
+
raise NoMatchingOverloadError.new(var, func) if Literal.instance_methods.include?(func)
|
262
|
+
|
263
|
+
# If e evaluates to a message and f is not declared in this message, the
|
264
|
+
# runtime error no_such_field is raised.
|
265
|
+
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
266
|
+
|
267
|
+
var.public_send(func)
|
268
|
+
when Protobuf.base_class
|
269
|
+
# eliminate protobuf API from the lookup
|
270
|
+
raise NoMatchingOverloadError.new(var, func) if Protobuf.base_class.instance_methods.include?(func)
|
271
|
+
|
272
|
+
# If e evaluates to a message and f is not declared in this message, the
|
273
|
+
# runtime error no_such_field is raised.
|
274
|
+
raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
|
275
|
+
|
276
|
+
value = Protobuf.lookup(var, func)
|
277
|
+
|
278
|
+
Literal.to_cel_type(value)
|
119
279
|
else
|
280
|
+
if var.is_a?(Module) && var.const_defined?(func)
|
281
|
+
# this block assumes a message based call on a protobuf message, either to a
|
282
|
+
# subclass/namespace (Foo.Bar), or an enum (Foo.BAR)
|
283
|
+
# protobuf accessing enum module
|
284
|
+
enum = var.const_get(func)
|
285
|
+
|
286
|
+
if args.nil?
|
287
|
+
case enum
|
288
|
+
when Integer
|
289
|
+
# enum lookup
|
290
|
+
return Protobuf.convert_to_enum(enum, var)
|
291
|
+
else
|
292
|
+
return enum
|
293
|
+
end
|
294
|
+
else
|
295
|
+
arg = call(args.first)
|
296
|
+
value = case arg
|
297
|
+
when Number
|
298
|
+
Protobuf.convert_to_enum(arg.value, enum)
|
299
|
+
when String
|
300
|
+
resolved_arg = enum.resolve(arg.to_sym)
|
301
|
+
raise EvaluateError, "#{arg} is invalid" unless resolved_arg
|
302
|
+
|
303
|
+
Protobuf.convert_to_enum(resolved_arg, enum)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
return Literal.to_cel_type(value)
|
307
|
+
end
|
308
|
+
|
120
309
|
raise EvaluateError, "#{invoke} is not supported"
|
121
310
|
end
|
122
311
|
end
|
123
312
|
|
124
313
|
def evaluate_condition(condition)
|
125
|
-
|
314
|
+
if_value = call(condition.if)
|
315
|
+
|
316
|
+
raise InvalidArgument, condition.if unless if_value.type == TYPES[:bool]
|
317
|
+
|
318
|
+
if_value.value ? call(condition.then) : call(condition.else)
|
126
319
|
end
|
127
320
|
|
128
321
|
def evaluate_standard_func(funcall)
|
@@ -131,25 +324,39 @@ module Cel
|
|
131
324
|
|
132
325
|
case func
|
133
326
|
when :type
|
134
|
-
|
135
|
-
|
327
|
+
operand = args.first
|
328
|
+
val = call(operand)
|
329
|
+
case val
|
330
|
+
when Protobuf.enum_class
|
331
|
+
val.enum_type
|
332
|
+
else
|
333
|
+
if val.respond_to?(:type)
|
334
|
+
val.type
|
335
|
+
else
|
336
|
+
val.class
|
337
|
+
end
|
338
|
+
end
|
136
339
|
|
137
|
-
val.class
|
138
340
|
# 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
|
341
|
+
when :has, :matches, :size
|
342
|
+
Macro.__send__(func, *args, program: self)
|
343
|
+
when :int, :uint, :string, :double, :bytes, :duration, :timestamp, :bool
|
146
344
|
type = TYPES[func]
|
147
|
-
|
345
|
+
op_value = call(args.first)
|
346
|
+
type.cast(op_value)
|
148
347
|
when :dyn
|
149
348
|
call(args.first)
|
150
349
|
else
|
151
350
|
return evaluate_custom_func(@context.declarations[func], funcall) if @context.declarations.key?(func)
|
152
351
|
|
352
|
+
# enum conversion
|
353
|
+
proto_type = Protobuf.convert_to_proto_type(func.to_s, @environment.package)
|
354
|
+
|
355
|
+
if proto_type && proto_type.respond_to?(:resolve)
|
356
|
+
op_value = call(args.first)
|
357
|
+
return Protobuf.convert_to_enum(op_value.value)
|
358
|
+
end
|
359
|
+
|
153
360
|
raise EvaluateError, "#{funcall} is not supported"
|
154
361
|
end
|
155
362
|
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
|
+
BASE_CLASS
|
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
|