View Source Alembic (alembic v0.1.0)

Alembic — a Liquid-compatible template engine for Elixir, with zero runtime dependencies.

Quick start

iex> {:ok, ast} = Alembic.compile("Hello {{ name }}!")
iex> Alembic.render(ast, %{"name" => "World"})
{:ok, "Hello World!"}

iex> Alembic.render_string("Hi {{ user }}", %{"user" => "Alice"})
{:ok, "Hi Alice"}

The pipeline

render_file(path, assigns, opts)
    
     Loader.resolve_path(path, opts)        {:ok, resolved_path}
    
     Cache.get(resolved_path)                {:hit, ast}  
                                                                   
     :miss                                                       
                                                                  
         File.read(resolved_path)            {:ok, source}     
         compile(source)                      {:ok, ast}       
         Cache.put(resolved_path, ast)                           
        
                
                 Inheritance.preprocess(ast, loader_fn)  {:ok, resolved_ast}
                
                 Evaluator.eval(resolved_ast, Context.new(assigns))  {:ok, html}

compile/2 and render/3 are kept separate so a caller (e.g. Grimoire) can compile once and render many times — the same reason render_file/3 bothers with a cache at all.

Options

OptionTypeDefaultDescription
:roots[String.t()]Alembic.Config.template_roots/0Override template root dirs
:extensions[String.t()][".html", ".liquid"]File extensions tried when a name has none
:cacheboolean()trueEnable/disable the compiled-AST cache for this call
:strictboolean()falseError on undefined variables instead of rendering ""
:custom_filters[module()][]Additional filter modules for this call only (see below)

Custom filters can be registered globally via config :alembic, custom_filters: [MyApp.Filters.Money], per call via the :custom_filters option above, or both — per-call modules are tried first and take precedence over globally-registered ones on a name collision. See Alembic.Filter.

Errors

Every non-bang function returns {:ok, value} | {:error, reason}. Bang (!) variants raise Alembic.TemplateError — see that module and Alembic.CompileError / Alembic.RenderError below.

Summary

Functions

Compiles a template source string into an AST.

Compiles a template source string into an AST, raising on error.

Renders a pre-compiled AST against an assigns map.

Renders a pre-compiled AST against an assigns map, raising on error.

Loads, compiles (using the cache when enabled), and renders a template file resolved by name across the configured template roots.

Loads, compiles, and renders a template file, raising on error.

Compiles and renders a template string in one step.

Compiles and renders a template string in one step, raising on error.

Types

@type compile_error() ::
  {:lexer, Alembic.Lexer.reason()} | {:parser, Alembic.Parser.reason()}
@type render_error() ::
  {:inheritance, Alembic.Inheritance.reason()}
  | {:evaluator, Alembic.Evaluator.reason()}
  | {:loader, Alembic.Loader.reason() | File.posix()}

Functions

Link to this function

compile(source, opts \\ [])

View Source
@spec compile(
  String.t(),
  keyword()
) :: {:ok, Alembic.AST.t()} | {:error, compile_error()}

Compiles a template source string into an AST.

Examples

iex> {:ok, ast} = Alembic.compile("Hello {{ name }}!")
iex> ast
[{:text, "Hello "}, {:output, ["name"], []}, {:text, "!"}]

iex> Alembic.compile("{{ }}")
{:error, {:lexer, {:empty_output_tag, %{line: 1, col: 1}}}}
Link to this function

compile!(source, opts \\ [])

View Source
@spec compile!(
  String.t(),
  keyword()
) :: Alembic.AST.t()

Compiles a template source string into an AST, raising on error.

Examples

iex> Alembic.compile!("Hello {{ name }}!")
[{:text, "Hello "}, {:output, ["name"], []}, {:text, "!"}]
Link to this function

render(ast, assigns \\ %{}, opts \\ [])

View Source
@spec render(Alembic.AST.t(), map(), keyword()) ::
  {:ok, String.t()} | {:error, render_error()}

Renders a pre-compiled AST against an assigns map.

Examples

iex> {:ok, ast} = Alembic.compile("Hello {{ name }}!")
iex> Alembic.render(ast, %{"name" => "World"})
{:ok, "Hello World!"}

iex> {:ok, ast} = Alembic.compile("{{ missing }}")
iex> Alembic.render(ast, %{}, strict: true)
{:error, {:evaluator, {:undefined_variable, ["missing"]}}}

iex> {:ok, ast} = Alembic.compile("{{ name | shout }}")
iex> Alembic.render(ast, %{"name" => "world"}, custom_filters: [Alembic.DocTest.Shout])
{:ok, "WORLD!"}
Link to this function

render!(ast, assigns \\ %{}, opts \\ [])

View Source
@spec render!(Alembic.AST.t(), map(), keyword()) :: String.t()

Renders a pre-compiled AST against an assigns map, raising on error.

Link to this function

render_file(name, assigns \\ %{}, opts \\ [])

View Source
@spec render_file(String.t(), map(), keyword()) ::
  {:ok, String.t()}
  | {:error,
     {:loader, Alembic.Loader.reason()} | compile_error() | render_error()}

Loads, compiles (using the cache when enabled), and renders a template file resolved by name across the configured template roots.

Link to this function

render_file!(name, assigns \\ %{}, opts \\ [])

View Source
@spec render_file!(String.t(), map(), keyword()) :: String.t()

Loads, compiles, and renders a template file, raising on error.

Link to this function

render_string(source, assigns \\ %{}, opts \\ [])

View Source
@spec render_string(String.t(), map(), keyword()) ::
  {:ok, String.t()} | {:error, compile_error() | render_error()}

Compiles and renders a template string in one step.

Examples

iex> Alembic.render_string("Hi {{ user }}", %{"user" => "Alice"})
{:ok, "Hi Alice"}
Link to this function

render_string!(source, assigns \\ %{}, opts \\ [])

View Source
@spec render_string!(String.t(), map(), keyword()) :: String.t()

Compiles and renders a template string in one step, raising on error.

Examples

iex> Alembic.render_string!("Hi {{ user }}", %{"user" => "Alice"})
"Hi Alice"