defmodule X.Template do @moduledoc """ Extends module with `~X` sigil to compile templates. use X.Template """ defmacro __using__(_) do quote do import unquote(__MODULE__) end end @doc ~S""" Handles sigil `~X` for the X templates. It returns Elixir AST which can be injected into the function body: iex> defmodule Example do ...> use X.Template ...> ...> def render(assigns) do ...> ~X(
{{ assigns.message }}
) ...> end ...> end ...> Example.render(%{message: "test"}) ["
", "test", "
"] By default `~X` sigil returns `iodata` AST. The `s` modifier is used to return string: iex> use X.Template ...> message = "Test" ...> ~X(
{{ message }}
)s "
Test
" """ defmacro sigil_X(expr, 's') do quote do IO.iodata_to_binary(unquote(handle_sigil(expr, __CALLER__))) end end defmacro sigil_X(expr, _) do handle_sigil(expr, __CALLER__) end @spec handle_sigil(Macro.t(), Macro.Env.t()) :: Macro.t() defp handle_sigil({:<<>>, _, [expr]}, env) do X.compile_string!(expr, env, line: env.line) end defp handle_sigil(expr, env) when is_bitstring(expr) do X.compile_string!(expr, env, line: env.line) end end