Celixir.Environment (Celixir v0.3.0)

Copy Markdown View Source

Execution environment for CEL expressions. Holds variable bindings, custom function definitions, and an optional type adapter.

Building an environment

env = Celixir.Environment.new(%{x: 10, name: "alice"})

Registering custom functions

Use put_function/3 to register Elixir functions callable from CEL. Functions receive plain Elixir values (unwrapped from CEL internal types) and should return plain Elixir values.

env = Celixir.Environment.new()
      |> Celixir.Environment.put_function("double", fn x -> x * 2 end)
      |> Celixir.Environment.put_function("math.clamp", fn v, lo, hi ->
        v |> max(lo) |> min(hi)
      end)

You can also pass module function captures:

env = Celixir.Environment.new()
      |> Celixir.Environment.put_function("slugify", &MyApp.Helpers.slugify/1)

Building reusable libraries

Group related functions into a module that configures an environment:

defmodule MyApp.CelLibrary do
  alias Celixir.Environment

  def register(env \\ Environment.new()) do
    env
    |> Environment.put_function("format.currency", &format_currency/2)
    |> Environment.put_function("format.percent", &format_percent/1)
  end

  defp format_currency(amount, cur), do: "#{cur} #{amount}"
  defp format_percent(ratio), do: "#{round(ratio * 100)}%"
end

env = MyApp.CelLibrary.register()
      |> Celixir.Environment.put_variable("price", 29.9)

Celixir.eval!("format.currency(price, 'USD')", env)

Summary

Functions

Deletes a private value from the environment.

Looks up a function.

Retrieves a private value from the environment.

Retrieves a private value, raising if the key doesn't exist.

Looks up a variable with proper resolution order

Checks if a variable name is locally bound (e.g., comprehension iter var).

Creates a new empty environment.

Creates an environment with the given variable bindings.

Registers a custom function.

Adds a local variable binding that shadows container-resolved and outer names.

Adds multiple local variable bindings at once (single struct copy instead of N copies).

Stores a private value in the environment.

Adds a variable binding.

Sets the container (namespace) for identifier resolution.

Sets a custom type adapter module.

Types

t()

@type t() :: %Celixir.Environment{
  container: String.t() | nil,
  container_prefixes: [String.t()],
  functions: %{required(String.t()) => function()},
  locals: %{required(atom()) => any()},
  private: %{required(any()) => any()},
  type_adapter: module() | nil,
  variables: %{required(atom()) => any()}
}

Functions

delete_private(env, key)

Deletes a private value from the environment.

get_function(env, name)

Looks up a function.

get_private(env, key)

Retrieves a private value from the environment.

Returns {:ok, value} or :error.

get_private!(env, key)

Retrieves a private value, raising if the key doesn't exist.

get_variable(env, name)

Looks up a variable with proper resolution order:

  • Absolute names (.y) bypass locals and container, look up in outer variables only
  • Local names check locals first (comprehension iter vars, cel.bind), then container-resolved outer vars

local?(env, name)

Checks if a variable name is locally bound (e.g., comprehension iter var).

new()

Creates a new empty environment.

new(variables)

Creates an environment with the given variable bindings.

put_function(env, name, func)

Registers a custom function.

put_local(env, name, value)

Adds a local variable binding that shadows container-resolved and outer names.

put_locals_bulk(env, new_locals)

Adds multiple local variable bindings at once (single struct copy instead of N copies).

put_private(env, key, value)

Stores a private value in the environment.

Private values are not visible to CEL expressions — they are only accessible from custom Elixir functions that receive the environment.

Examples

env = Celixir.Environment.new()
      |> Celixir.Environment.put_private(:repo, MyApp.Repo)

put_variable(env, name, value)

Adds a variable binding.

set_container(env, container)

Sets the container (namespace) for identifier resolution.

set_type_adapter(env, adapter)

Sets a custom type adapter module.