cel 0.2.0 → 0.2.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 868e7e643aad1444aa54da0dab45e583a49abf2e6af0dcbbd1512b88af209e88
4
- data.tar.gz: 2f174f88813b63181f1c16e701d1baf961eda0d9ef18c575b29b5afdc53d450c
3
+ metadata.gz: 54879dbe064eebebe6597acd098c6b10b8376f7b2333d2f822ca02c24a0815bb
4
+ data.tar.gz: 95e2fed808711b64aedc8ed6aff2f8bc8eb9e5f9562907c0d794df186a35f035
5
5
  SHA512:
6
- metadata.gz: 26c83e074c1729c00f5b8c3ca271865bb009f562326c6b6ddca3d5c127cf7c7f33ab93b3c964d4db0eafbe442e07dc1413abf2dc5b5ac487950da2d02fc8cd69
7
- data.tar.gz: 3aa55062c1693eb5c3d3ad45bb09d95028c5115a9428d8bf2fdd3189b5c8869c4b6d92c6aa3e864b515f555fe78d3015fbeaf03799d64f0ef9f8365ce95a87d0
6
+ metadata.gz: 59349c9633015f0a63c297573e30e33d459de63f1af8ff032f808b045c069716c19142e2208f653864bd4a2363009dd7cb54c8feed3160e6c792c260853cc79f
7
+ data.tar.gz: 2070807c5f7a01217117d96373372e111697727069b915a665acfc6fd2a58c6ff4adfb4fd747522585d7b03733cfb77ee2b7b726b6c36edb3f6d828a93ffed10
data/CHANGELOG.md CHANGED
@@ -1,5 +1,38 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [0.2.1] - 2023-07-26
4
+
5
+
6
+ ### Improvements
7
+
8
+ Collection type declarations are now better supported, i.e. declaring "an array of strings" is now possible:
9
+
10
+ ```ruby
11
+ Cel::Types[:list, :string] # array of strings
12
+ Cel::Environment.new(
13
+ names: Cel::Types[:list, :string],
14
+ owned_by: Cel::Types[:map, :string] # hash map of string keys
15
+ )
16
+ ```
17
+
18
+ ### Bugfixes
19
+
20
+ Collections passed as variables of an expression are now correctly cast to Cel types:
21
+
22
+ ```ruby
23
+ env.evaluate("a", { a: [1, 2, 3] }) #=> now returns a Cel::List
24
+ ```
25
+
26
+ Conversely, custom functions now expose ruby types in the blocks, instead of its Cel counterparts:
27
+
28
+ ```ruby
29
+ func = Cel::Function(:list, :list, return_type: :list) do |a, b|
30
+ # a is now a ruby array, b as well
31
+ a & b
32
+ # function returns a ruby array, will be converted to a Cel::List for use in the expression
33
+ end
34
+ ```
35
+
3
36
  ## [0.2.0] - 2023-01-17
4
37
 
5
38
  ### Features
data/README.md CHANGED
@@ -1,8 +1,8 @@
1
1
  # Cel::Ruby
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/cel.svg)](http://rubygems.org/gems/cel)
4
- [![pipeline status](https://gitlab.com/honeyryderchuck/cel-ruby/badges/master/pipeline.svg)](https://gitlab.com/honeyryderchuck/cel-ruby/pipelines?page=1&scope=all&ref=master)
5
- [![coverage report](https://gitlab.com/honeyryderchuck/cel-ruby/badges/master/coverage.svg?job=coverage)](https://honeyryderchuck.gitlab.io/cel-ruby/coverage/#_AllFiles)
4
+ [![pipeline status](https://gitlab.com/os85/cel-ruby/badges/master/pipeline.svg)](https://gitlab.com/os85/cel-ruby/pipelines?page=1&scope=all&ref=master)
5
+ [![coverage report](https://gitlab.com/os85/cel-ruby/badges/master/coverage.svg?job=coverage)](https://os85.gitlab.io/cel-ruby/coverage/#_AllFiles)
6
6
 
7
7
  Pure Ruby implementation of Google Common Expression Language, https://opensource.google/projects/cel.
8
8
 
@@ -45,19 +45,20 @@ end
45
45
  prg = env.program(ast)
46
46
  # 1.3 evaluate
47
47
  return_value = prg.evaluate(name: Cel::String.new("/groups/acme.co/documents/secret-stuff"),
48
- group: Cel::String.new("acme.co")))
48
+ group: Cel::String.new("acme.co"))
49
49
 
50
50
  # 2.1 parse and check
51
51
  prg = env.program('name.startsWith("/groups/" + group)')
52
52
  # 2.2 then evaluate
53
53
  return_value = prg.evaluate(name: Cel::String.new("/groups/acme.co/documents/secret-stuff"),
54
- group: Cel::String.new("acme.co")))
54
+ group: Cel::String.new("acme.co"))
55
55
 
56
56
  # 3. or parse, check and evaluate
57
57
  begin
58
58
  return_value = env.evaluate(ast,
59
59
  name: Cel::String.new("/groups/acme.co/documents/secret-stuff"),
60
- group: Cel::String.new("acme.co"))
60
+ group: Cel::String.new("acme.co")
61
+ )
61
62
  rescue Cel::Error => e
62
63
  STDERR.puts("evaluation error: #{e.message}")
63
64
  raise e
@@ -66,6 +67,20 @@ end
66
67
  puts return_value #=> true
67
68
  ```
68
69
 
70
+ ### types
71
+
72
+ `cel-ruby` supports declaring the types of variables in the environment, which allows for expression checking:
73
+
74
+ ```ruby
75
+ env = Cel::Environment.new(
76
+ first_name: :string, # shortcut for Cel::Types[:string]
77
+ middle_names: Cel::Types[:list, :string], # list of strings
78
+ last_name: :string
79
+ )
80
+
81
+ # you can use Cel::Types to access any type of primitive type, i.e. Cel::Types[:bytes]
82
+ ```
83
+
69
84
  ### protobuf
70
85
 
71
86
  If `google/protobuf` is available in the environment, `cel-ruby` will also be able to integrate with protobuf declarations in CEL expressions.
@@ -176,6 +176,10 @@ module Cel
176
176
  end
177
177
  end
178
178
 
179
+ def to_ruby_type
180
+ @value
181
+ end
182
+
179
183
  private
180
184
 
181
185
  def check; end
@@ -296,6 +300,10 @@ module Cel
296
300
  def to_ary
297
301
  [self]
298
302
  end
303
+
304
+ def to_ruby_type
305
+ value.map(&:to_ruby_type)
306
+ end
299
307
  end
300
308
 
301
309
  class Map < Literal
@@ -318,6 +326,10 @@ module Cel
318
326
  [self]
319
327
  end
320
328
 
329
+ def to_ruby_type
330
+ value.to_h { |*args| args.map(&:to_ruby_type) }
331
+ end
332
+
321
333
  def respond_to_missing?(meth, *args)
322
334
  super || (@value && @value.keys.any? { |k| k.to_s == meth.to_s })
323
335
  end
data/lib/cel/ast/types.rb CHANGED
@@ -58,6 +58,14 @@ module Cel
58
58
  def get(idx)
59
59
  @type_list[idx]
60
60
  end
61
+
62
+ def ==(other)
63
+ other == :list || super
64
+ end
65
+
66
+ def cast(value)
67
+ List.new(value)
68
+ end
61
69
  end
62
70
 
63
71
  class MapType < Type
@@ -73,12 +81,45 @@ module Cel
73
81
  _, value = @type_map.find { |k, _| k == attrib.to_s }
74
82
  value
75
83
  end
84
+
85
+ def ==(other)
86
+ other == :map || super
87
+ end
88
+
89
+ def cast(value)
90
+ Map.new(value)
91
+ end
76
92
  end
77
93
 
78
94
  # Primitive Cel Types
79
95
 
80
96
  PRIMITIVE_TYPES = %i[int uint double bool string bytes list map timestamp duration null_type type].freeze
81
- TYPES = PRIMITIVE_TYPES.to_h { |typ| [typ, Type.new(typ)] }
97
+ COLTYPES = %i[list map].freeze
98
+ TYPES = (PRIMITIVE_TYPES - COLTYPES).to_h { |typ| [typ, Type.new(typ)] }
82
99
  TYPES[:type] = Type.new(:type)
83
100
  TYPES[:any] = Type.new(:any)
101
+
102
+ module CollectionTypeFetch
103
+ def [](*args)
104
+ col_type, elem_type = args
105
+
106
+ return super unless COLTYPES.include?(col_type)
107
+
108
+ return super if args.size > 2
109
+
110
+ elem_type ||= :any
111
+
112
+ type = case col_type
113
+ when :list
114
+ ListType.new([])
115
+ when :map
116
+ MapType.new({})
117
+ end
118
+
119
+ type.element_type = super(*elem_type)
120
+ type
121
+ end
122
+ end
123
+
124
+ TYPES.singleton_class.prepend(CollectionTypeFetch)
84
125
  end
data/lib/cel/checker.rb CHANGED
@@ -148,7 +148,7 @@ module Cel
148
148
  case func
149
149
  when :[]
150
150
  attribute = var_type.get(args)
151
- unsupported_operation(funcall) unless attribute
151
+ return TYPES[:any] unless attribute
152
152
  when :all, :exists, :exists_one
153
153
  check_arity(funcall, args, 2)
154
154
  identifier, predicate = args
@@ -162,7 +162,7 @@ module Cel
162
162
  return TYPES[:bool]
163
163
  else
164
164
  attribute = var_type.get(func)
165
- unsupported_operation(funcall) unless attribute
165
+ return TYPES[:any] unless attribute
166
166
  end
167
167
 
168
168
  call(attribute)
@@ -381,7 +381,7 @@ module Cel
381
381
  end
382
382
  end
383
383
 
384
- TYPES[type]
384
+ type && types.is_a?(Type) ? types : TYPES[type]
385
385
  end
386
386
 
387
387
  def check_arity(func, args, arity)
data/lib/cel/program.rb CHANGED
@@ -93,7 +93,7 @@ module Cel
93
93
  when String
94
94
  raise EvaluateError, "#{invoke} is not supported" unless String.method_defined?(func, false)
95
95
 
96
- var.public_send(func, *args)
96
+ var.public_send(func, *args.map(&method(:call)))
97
97
  when Message
98
98
  # If e evaluates to a message and f is not declared in this message, the
99
99
  # runtime error no_such_field is raised.
@@ -134,10 +134,12 @@ module Cel
134
134
 
135
135
  val.class
136
136
  # MACROS
137
- when :has, :size
138
- Macro.__send__(func, *args)
137
+ when :has
138
+ Bool.new(Macro.__send__(func, *args))
139
+ when :size
140
+ Cel::Number.new(:int, Macro.__send__(func, *args))
139
141
  when :matches
140
- Macro.__send__(func, *args.map(&method(:call)))
142
+ Bool.new(Macro.__send__(func, *args.map(&method(:call))))
141
143
  when :int, :uint, :string, :double, :bytes, :duration, :timestamp
142
144
  type = TYPES[func]
143
145
  type.cast(call(args.first))
@@ -153,7 +155,7 @@ module Cel
153
155
  def evaluate_custom_func(func, funcall)
154
156
  args = funcall.args
155
157
 
156
- func.call(*args.map(&method(:call)))
158
+ func.call(*args.map(&method(:call)).map(&:to_ruby_type))
157
159
  end
158
160
  end
159
161
  end
data/lib/cel/version.rb CHANGED
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Cel
4
4
  module Ruby
5
- VERSION = "0.2.0"
5
+ VERSION = "0.2.1"
6
6
  end
7
7
  end
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.2.0
4
+ version: 0.2.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tiago Cardoso
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-01-17 00:00:00.000000000 Z
11
+ date: 2023-07-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: minitest
@@ -88,7 +88,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
88
88
  - !ruby/object:Gem::Version
89
89
  version: '0'
90
90
  requirements: []
91
- rubygems_version: 3.3.7
91
+ rubygems_version: 3.4.10
92
92
  signing_key:
93
93
  specification_version: 4
94
94
  summary: Pure Ruby implementation of Google Common Expression Language, https://opensource.google/projects/cel.