Skip to content

warhammerkid/cel-ruby

Repository files navigation

Cel::Ruby

Gem Version pipeline status coverage report

Pure Ruby implementation of Google Common Expression Language, https://opensource.google/projects/cel.

The Common Expression Language (CEL) implements common semantics for expression evaluation, enabling different applications to more easily interoperate.

Installation

Add this line to your application's Gemfile:

gem 'cel'

And then execute:

$ bundle install

Or install it yourself as:

$ gem install cel

Usage

The usage pattern follows the pattern defined by cel-go, i.e. define an environment, which then can be used to parse, compile and evaluate a CEL program.

require "cel"

# set the environment
env = Cel::Environment.new(name: :string, group: :string)

# 1.1 parse
ast = env.parse('name.startsWith("/groups/" + group)') #=> Cel::AST::Expr
# 1.2 check
env.check(ast)
# 1.3 evaluate
prg = env.program(ast)
return_value = prg.evaluate(name: Cel::String.new("/groups/acme.co/documents/secret-stuff"),
    group: Cel::String.new("acme.co"))

# 2.1 parse and check
ast = env.compile('name.startsWith("/groups/" + group)')
# 2.2 then evaluate
prg = env.program(ast)
return_value = prg.evaluate(name: Cel::String.new("/groups/acme.co/documents/secret-stuff"),
    group: Cel::String.new("acme.co"))

# 3. or parse, check and evaluate
begin
  return_value = env.evaluate(
    'name.startsWith("/groups/" + group)',
    name: Cel::String.new("/groups/acme.co/documents/secret-stuff"),
    group: Cel::String.new("acme.co")
  )
rescue Cel::Error => e
  STDERR.puts("evaluation error: #{e.message}")
  raise e
end

puts return_value #=> true

types

cel-ruby supports declaring the types of variables in the environment, which allows for expression checking:

env = Cel::Environment.new(
  first_name: :string, # shortcut for Cel::TYPES[:string]
  middle_names: Cel::ListType[:string], # list of strings
  last_name: :string
)

# you can use Cel::TYPES to access any type of primitive type, i.e. Cel::TYPES[:bytes]

protobuf

If google/protobuf is available in the environment, cel-ruby will also be able to integrate with protobuf declarations in CEL expressions.

require "google/protobuf"
require "cel"

env = Cel::Environment.new

env.evaluate("google.protobuf.Duration{seconds: 123}.seconds == 123") #=> true

Custom functions

cel-ruby allows you to define custom functions to be used inside CEL expressions. The recommended way to do this is to create a module with all your custom functions.

module MyCustomFunctions
  class << self
    extend Cel::FunctionBindings

    cel_func { global_function("foo", [:int, :int], :int) }
    def foo(a, b)
      Cel::Number.new(:int, a.value + b.value)
    end
  end
end

env = Cel::Environment.new
env.extend_functions(MyCustomFunctions)
env.evaluate("foo(2, 2)") #=> 4

You can also pass in function declarations alongside variable declarations when creating the environment. While we strongly recommend usage of Cel::Function for defining them (due to the ability of them being used for checking), the only requirement is that the function object responds to .call. Some functionality is not available when defining functions this way:

env = environment(foo: Cel::Function(:int, :int, return_type: :int) { |a, b|  a + b})
env.evaluate("foo(2, 2)") #=> 4

# this is also possible, just not as type-safe
env2 = environment(foo: -> (a, b) { a + b})
env2.evaluate("foo(2, 2)") #=> 4

Supported Rubies

All Rubies greater or equal to 2.7, and always latest JRuby and Truffleruby.

Development

Clone the repo in your local machine, where you have ruby installed. Then you can:

# install dev dependencies
> bundle install
# run tests
> bundle exec rake test

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and the created tag, and push the .gem file to rubygems.org.

CEL parser

The parser is based on the grammar defined in cel-spec, and developed using racc, a LALR(1) parser generator, which is part of ruby's standard library.

Changes in the parser are therefore accomplished by modifying the parser.ry file and running:

> bundle exec racc -o lib/cel/parser.rb lib/cel/parser.ry

Contributing

Bug reports and pull requests are welcome on Gitlab at https://gitlab.com/os85/cel-ruby.

About

Pure Ruby implementation of Google Common Expression Language

Resources

License

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors