cel 0.4.0 → 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.
data/lib/cel/ast/types.rb CHANGED
@@ -2,12 +2,18 @@
2
2
 
3
3
  module Cel
4
4
  class Type
5
+ include CelMethods
6
+
5
7
  def initialize(type)
6
8
  @type = type
7
9
  end
8
10
 
9
- def ==(other)
10
- (other.is_a?(Symbol) && other == @type) || super
11
+ define_cel_method(:==) do |other|
12
+ (other.is_a?(Symbol) && other == @type) || super(other)
13
+ end
14
+
15
+ define_cel_method(:"!=") do |other|
16
+ !cel_send(:==, other)
11
17
  end
12
18
 
13
19
  def to_str
@@ -154,6 +160,29 @@ module Cel
154
160
  raise Error, "unsupported cast operation to #{@type}"
155
161
  end
156
162
  end
163
+
164
+ def convert(primitive_value)
165
+ case @type
166
+ when :int, :uint, :double
167
+ Number.new(@type, primitive_value)
168
+ when :string
169
+ String.new(primitive_value)
170
+ when :bytes
171
+ Bytes.new(primitive_value)
172
+ when :bool
173
+ Bool.new(primitive_value)
174
+ when :null_type
175
+ Null::INSTANCE
176
+ when :timestamp
177
+ Timestamp.new(primitive_value)
178
+ when :duration
179
+ Duration.new(primitive_value)
180
+ when :any
181
+ Literal.to_cel_type(primitive_value)
182
+ else
183
+ raise EvaluateError, "Type conversion error"
184
+ end
185
+ end
157
186
  end
158
187
 
159
188
  class ListType < Type
@@ -176,7 +205,11 @@ module Cel
176
205
  end
177
206
 
178
207
  def cast(value)
179
- value.is_a?(List) ? value : List.new(value)
208
+ value.is_a?(List) ? value : convert(value)
209
+ end
210
+
211
+ def convert(primitive_value)
212
+ List.new(primitive_value)
180
213
  end
181
214
  end
182
215
 
@@ -203,15 +236,27 @@ module Cel
203
236
  end
204
237
 
205
238
  def cast(value)
206
- value.is_a?(Map) ? value : Map.new(value)
239
+ value.is_a?(Map) ? value : convert(value)
240
+ end
241
+
242
+ def convert(primitive_value)
243
+ Map.new(primitive_value)
207
244
  end
208
245
  end
209
246
 
210
247
  class AbstractType < Type
248
+ attr_reader :params
249
+ protected :params
211
250
  def initialize(name, *params)
212
251
  super(name)
213
252
  @params = params
214
253
  end
254
+
255
+ define_cel_method(:==) do |other|
256
+ return super(other) unless other.is_a?(AbstractType)
257
+
258
+ other.type && @type && other.params == @params
259
+ end
215
260
  end
216
261
  # Primitive Cel Types
217
262
 
data/lib/cel/errors.rb CHANGED
@@ -3,6 +3,8 @@
3
3
  module Cel
4
4
  class Error < StandardError; end
5
5
 
6
+ class NoCelMethodError < Error; end
7
+
6
8
  class ParseError < Error; end
7
9
 
8
10
  class MaxRecursionDepthExceededError < ParseError; end
@@ -115,13 +115,13 @@ module Cel
115
115
  end
116
116
 
117
117
  class String
118
- def charAt(idx)
118
+ define_cel_method(:charAt) do |idx|
119
119
  raise EvaluateError, "index out of range: #{idx}" unless idx.between?(0, @value.size)
120
120
 
121
121
  String.new(@value[idx] || "")
122
122
  end
123
123
 
124
- def indexOf(substr, *args)
124
+ define_cel_method(:indexOf) do |substr, *args|
125
125
  idx, = args
126
126
 
127
127
  raise EvaluateError, "index out of range: #{idx}" if idx && !idx.between?(0, @value.size)
@@ -129,7 +129,7 @@ module Cel
129
129
  Number.new(:int, @value.index(substr, *args) || -1)
130
130
  end
131
131
 
132
- def lastIndexOf(substr, *args)
132
+ define_cel_method(:lastIndexOf) do |substr, *args|
133
133
  idx, = args
134
134
 
135
135
  raise EvaluateError, "index out of range: #{idx}" if idx && !idx.between?(0, @value.size)
@@ -137,17 +137,17 @@ module Cel
137
137
  Number.new(:int, @value.rindex(substr, *args) || -1)
138
138
  end
139
139
 
140
- def lowerAscii
140
+ define_cel_method(:lowerAscii) do
141
141
  String.new(@value.downcase(:ascii))
142
142
  end
143
143
 
144
- def upperAscii
144
+ define_cel_method(:upperAscii) do
145
145
  String.new(@value.upcase(:ascii))
146
146
  end
147
147
 
148
148
  UNICODE_WHITESPACE = /[ \t\r\n\u000C\u000D\u0020\u0085\u00A0\u1680\u2000-\u200A\u2028-\u2029\u202F\u205F\u3000]+/
149
149
 
150
- def trim
150
+ define_cel_method(:trim) do
151
151
  # why this? because String#split only takes null, horizontal tab, line feed, vertical tab, form feed,
152
152
  # carriage return, space into account. We need the unicode definition of whitespace.
153
153
  value = @value.gsub(/\A#{UNICODE_WHITESPACE}/o, "")
@@ -156,23 +156,25 @@ module Cel
156
156
  String.new(value.strip)
157
157
  end
158
158
 
159
- def reverse
159
+ define_cel_method(:reverse) do
160
160
  String.new(@value.reverse)
161
161
  end
162
162
 
163
- def split(pattern, *args)
163
+ define_cel_method(:split) do |pattern, *args|
164
164
  raise NoOverloadError unless pattern.is_a?(String) && args.size.between?(0, 1)
165
165
 
166
166
  limit, = args
167
167
 
168
168
  raise NoOverloadError if limit && !limit.is_a?(Number)
169
169
 
170
- return List.new([]) if limit && limit.zero?
171
-
172
- List.new(@value.split(pattern, *args))
170
+ if limit && limit.zero?
171
+ List.new([])
172
+ else
173
+ List.new(@value.split(pattern, *args))
174
+ end
173
175
  end
174
176
 
175
- def substring(*args)
177
+ define_cel_method(:substring) do |*args|
176
178
  raise NoOverloadError unless args.size.between?(1, 2)
177
179
 
178
180
  start_idx, end_idx = *args
@@ -187,7 +189,7 @@ module Cel
187
189
  String.new(@value[start_idx..(end_idx - 1)])
188
190
  end
189
191
 
190
- def replace(pattern, replacement, *args)
192
+ define_cel_method(:replace) do |pattern, replacement, *args|
191
193
  raise NoOverloadError unless args.size.between?(0, 1)
192
194
 
193
195
  limit, = args
@@ -215,14 +217,14 @@ module Cel
215
217
  String.new(value)
216
218
  end
217
219
 
218
- def format(mappings)
220
+ define_cel_method(:format) do |mappings|
219
221
  String.new(format(@value, *mappings))
220
222
  end
221
223
  end
222
224
 
223
225
  class List
224
- def join(*)
225
- String.new(super)
226
+ define_cel_method(:join) do |*args|
227
+ String.new(super(*args))
226
228
  end
227
229
  end
228
230
  end
@@ -1,9 +1,9 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "cel/extensions/math"
4
- require "cel/extensions/string"
5
- require "cel/extensions/bind"
6
- require "cel/extensions/encoders"
3
+ require_relative "extensions/math"
4
+ require_relative "extensions/string"
5
+ require_relative "extensions/bind"
6
+ require_relative "extensions/encoders"
7
7
 
8
8
  module Cel
9
9
  EXTENSIONS = {
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,
data/lib/cel/program.rb CHANGED
@@ -183,12 +183,12 @@ module Cel
183
183
  t.is_a?(Class) && t < Protobuf.base_class ? 1 : 0
184
184
  end
185
185
 
186
- val = lhs.public_send(op, rhs)
186
+ val = lhs.cel_send(op, rhs)
187
187
 
188
188
  Literal.to_cel_type(val)
189
189
  else
190
190
  op_value, *values = operands.map(&method(:call))
191
- val = op_value.public_send(op, *values)
191
+ val = op_value.cel_send(op, *values)
192
192
 
193
193
  Literal.to_cel_type(val)
194
194
  end
@@ -197,7 +197,8 @@ module Cel
197
197
  def evaluate_invoke(invoke, var = invoke.var)
198
198
  return evaluate_standard_func(invoke) unless var
199
199
 
200
- func = invoke.func
200
+ func = call(invoke.func) || invoke.func
201
+
201
202
  args = invoke.args
202
203
 
203
204
  var =
@@ -229,7 +230,7 @@ module Cel
229
230
  when String
230
231
  raise EvaluateError, "#{invoke} is not supported" unless String.method_defined?(func, false)
231
232
 
232
- var.public_send(func, *args.map(&method(:call)))
233
+ var.cel_send(func, *args.map(&method(:call)))
233
234
  when Map
234
235
  return Macro.__send__(func, var, *args, program: self) if !Module.respond_to?(func) && Macro.respond_to?(func)
235
236
 
@@ -238,9 +239,13 @@ module Cel
238
239
  # to the expression x['foo'] when x evaluates to a map).
239
240
 
240
241
  if args
241
- var.public_send(func, *args)
242
+ var.cel_send(func, *args)
242
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
+
243
247
  begin
248
+ # TODO: use explicit lookup method to circumvent the need to method_missing it
244
249
  var.public_send(func)
245
250
  rescue NoMethodError
246
251
  raise NoSuchKeyError.new(var, func)
@@ -254,8 +259,8 @@ module Cel
254
259
  # to the expression x['foo'] when x evaluates to a map).
255
260
 
256
261
  args ?
257
- var.public_send(func, *Array(args).map(&method(:call))) :
258
- var.public_send(func)
262
+ var.cel_send(func, *Array(args).map(&method(:call))) :
263
+ var.cel_send(func)
259
264
  when Timestamp, Duration
260
265
  raise EvaluateError, "#{invoke} is not supported" unless var.class.method_defined?(func, false)
261
266
 
@@ -266,7 +271,7 @@ module Cel
266
271
  # runtime error no_such_field is raised.
267
272
  raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
268
273
 
269
- var.public_send(func, *args)
274
+ var.cel_send(func, *args)
270
275
  when Literal
271
276
  # eliminate ruby API from the lookup
272
277
  raise NoMatchingOverloadError.new(var, func) if Literal.instance_methods.include?(func)
@@ -275,7 +280,7 @@ module Cel
275
280
  # runtime error no_such_field is raised.
276
281
  raise NoSuchFieldError.new(var, func) unless var.respond_to?(func)
277
282
 
278
- var.public_send(func)
283
+ var.cel_send(func)
279
284
  when Protobuf.base_class
280
285
  # eliminate protobuf API from the lookup
281
286
  raise NoMatchingOverloadError.new(var, func) if Protobuf.base_class.instance_methods.include?(func)
@@ -323,6 +328,8 @@ module Cel
323
328
  else
324
329
  raise EvaluateError, "#{invoke} is not supported"
325
330
  end
331
+ rescue NoCelMethodError
332
+ raise EvaluateError, "#{invoke} is not supported"
326
333
  end
327
334
 
328
335
  def evaluate_condition(condition)
data/lib/cel/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cel
4
4
  module Ruby
5
- VERSION = "0.4.0"
5
+ VERSION = "0.4.1"
6
6
  end
7
7
  end
data/lib/cel.rb CHANGED
@@ -1,18 +1,19 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "bigdecimal"
4
- require "cel/version"
5
- require "cel/errors"
6
- require "cel/ast/types"
7
- require "cel/ast/elements"
8
- require "cel/extensions"
9
- require "cel/parser"
10
- require "cel/macro"
11
- require "cel/context"
12
- require "cel/encoder" if RUBY_VERSION >= "3.1.0"
13
- require "cel/checker"
14
- require "cel/program"
15
- require "cel/environment"
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"
16
17
 
17
18
  begin
18
19
  require "tzinfo"
@@ -20,7 +21,7 @@ rescue LoadError # rubocop:disable Lint/SuppressedException
20
21
  end
21
22
 
22
23
  begin
23
- require "cel/ast/elements/protobuf"
24
+ require_relative "cel/ast/elements/protobuf"
24
25
  rescue LoadError => e
25
26
  puts e
26
27
  module Cel
@@ -253,4 +254,17 @@ module Cel
253
254
  /[[:upper:]]/.match?(typ[0]) ? typ : typ.capitalize
254
255
  end.join("::")
255
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
256
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.0
4
+ version: 0.4.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
@@ -79,8 +79,26 @@ files:
79
79
  - LICENSE.txt
80
80
  - README.md
81
81
  - lib/cel.rb
82
+ - lib/cel/ast/cel_methods.rb
82
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
83
99
  - lib/cel/ast/elements/protobuf.rb
100
+ - lib/cel/ast/elements/string.rb
101
+ - lib/cel/ast/elements/timestamp.rb
84
102
  - lib/cel/ast/types.rb
85
103
  - lib/cel/checker.rb
86
104
  - lib/cel/context.rb