cel-rs-rb
Ruby bindings for the Rust cel crate, implemented with Magnus.
Goals
- Ruby-first API over the Rust CEL engine
- Close semantic compatibility with Rust
cel::Program+cel::Context - Ruby variable and function interop
- Thread-safe concurrent execution
- GVL released while CEL evaluation runs
Installation
gem "cel-rs-rb"
Usage
require "cel"
context = CEL::Context.build(user: {"name" => "Ada"}, scores: [10, 20, 30]) do |ctx|
ctx.define_function("sum") { |*args| args.sum }
end
program = CEL.compile("sum(scores[0], scores[1], scores[2])")
program.execute(context)
# => 60
API mapping
CEL.compile(source)->CEL::ProgramCEL::Program.compile(source)->CEL::ProgramCEL::Program#execute(context = nil)-> Ruby valueCEL::Program#references->{ "variables" => [...], "functions" => [...] }CEL::Context.new(empty = false)-> context with builtins (false) or empty (true)CEL::Context#add_variable(name, value)CEL::Context#define_function(name) { |*args| ... }CEL::Duration.new(seconds)-> duration value for context variables and duration results
Type support
Ruby -> CEL
nil->nulltrue/false->boolInteger->intFloat->doubleString/Symbol->string- binary
String(ASCII-8BIT, e.g."abc".b) ->bytes Time->timestampCEL::Duration->durationArray->listHashwith keysString|Symbol|Integer|Boolean->map
CEL -> Ruby
null->nil- scalar primitives map naturally
bytes-> binary RubyStringtimestamp->Timeduration->CEL::Durationlist->Arraymap->Hash
Error classes
CEL::ErrorCEL::ParseErrorCEL::ExecutionErrorCEL::TypeError
Thread safety and concurrency
- Context data is mutex-protected and immutable during execution snapshots.
- CEL execution is run with the Ruby GVL released so other Ruby threads can run.
- Ruby callbacks from CEL functions temporarily re-acquire the GVL.
Development
Tooling
Uses mise for versions:
[tools]
ruby = "4.0"
rust = "1.96.0"
Test + lint
bundle exec rake
This runs:
standard(format/lint)- native extension compile
rspec
CI also runs the test suite on Ruby 3.3, Ruby 3.4, and Ruby 4.0 through Buildkite.
Compatibility notes
- Some CEL value variants (e.g. opaque custom Rust types) cannot be fully marshaled to Ruby and raise
CEL::TypeError. - This project targets broad CEL compatibility, but parity for every Rust-only extension point is still evolving.