Alembic

Hex.pm License: MIT

A Liquid-compatible template engine for Elixir, with zero runtime dependencies — built entirely on Elixir and OTP standard library functionality.

Quick start

# 1. Add the dependency (the OTP app is :alembic; the Hex package name is
# alembic_template_engine, so the `hex:` key is required)
def deps do
[{:alembic, "~> 0.1.0", hex: "alembic_template_engine"}]
end
# 2. Configure template roots (config/config.exs) — only needed for render_file/3
config :alembic, template_roots: ["priv/templates"]
# 3. Render
Alembic.render_string("Hello, {{ name }}!", %{"name" => "World"})
#=> {:ok, "Hello, World!"}
Alembic.render_file("index.html", %{"title" => "Home"})
#=> {:ok, "<html>...</html>"}

Features

See COMPATIBILITY.md for the full picture of what's supported, what intentionally deviates from upstream Liquid, and what's out of scope for this release.

Configuration

# config/config.exs
config :alembic,
template_roots: ["priv/templates"],
template_extensions: [".html", ".liquid"],
cache: true,
custom_filters: [],
max_inheritance_depth: 10
Key Type Default Description
:template_roots [String.t()] [] Directories searched, in order, by render_file/3
:template_extensions [String.t()] [".html", ".liquid"] Extensions tried when a name has none
:cache boolean() true Enable/disable the compiled-AST cache
:custom_filters [module()] [] Modules implementing Alembic.Filter
:max_inheritance_depth pos_integer() 10 Max {% extends %} chain length

Every key has a per-call override too — see the options table in Alembic's moduledoc.

Custom filters

defmodule MyApp.Filters.Money do
@behaviour Alembic.Filter
@impl true
def name, do: "money"
@impl true
def apply(cents, []) when is_integer(cents) do
{:ok, "$" <> :erlang.float_to_binary(cents / 100, decimals: 2)}
end
end
config :alembic, custom_filters: [MyApp.Filters.Money]
{{ price_cents | money }} {# => "$19.99" #}

Dependency policy

Alembic has zero runtime dependencies. Development tooling (ex_doc, credo, dialyxir, benchee) is runtime: false and never becomes part of the dependency graph of an application that depends on Alembic.

Development

mix deps.get # install dependencies
mix test # run the test suite (unit + integration + doctests)
mix test --cover # with coverage report
mix format --check-formatted
mix credo --strict # static analysis
mix dialyzer # type checking
mix docs # generate documentation
mix run bench/*.exs # run a benchmark script (see BENCHMARKS.md)
mix hex.build # build the Hex package locally

Contributing

Issues and pull requests are welcome. Before opening a PR, please make sure mix test, mix credo --strict, and mix dialyzer all pass.

License

MIT — see LICENSE.