cel 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
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.