defmodule ExEEx do
@moduledoc """
Documentation for ExEEx.
"""
def adapter() do
Application.get_env(:exeex, :adapter, ExEEx.Adapter.FileStorage)
end
@doc """
Render template file.
## Examples
iex> ExEEx.render("test/templates/hello.txt", val: "world")
"Hello, world!\\n"
iex> ExEEx.render("test/templates/main.txt")
"This is header\\n---\\nThis is body\\n---\\nThis is footer\\n\\n"
iex> ExEEx.render("test/templates/main.txt", [{"foo", 3}])
** (ExEEx.TemplateError) expected keywords as template parameters
"""
def render(filename, params \\ [])
def render(%ExEEx.Template{code: code}, params) when is_list(params) do
if not Keyword.keyword?(params) do
raise ExEEx.TemplateError, message: "expected keywords as template parameters"
end
{result, _binding} = Code.eval_quoted(code, params)
result
end
def render(filename, params) when is_binary(filename) and is_list(params) do
compile(filename)
|> render(params)
end
@doc """
Render template string.
## Examples
iex> ExEEx.render_string("Hello, world!")
"Hello, world!"
iex> ExEEx.render_string("<%= include \\"test/templates/hello.txt\\" %>OK", val: "world")
"Hello, world!
OK"
iex> ExEEx.render_string("<%= block \\"header\\" do %>This is default header<% end %>")
"This is default header"
iex> ExEEx.render_string("<%= block \\"test\\" %>")
""
iex> ExEEx.render_string("<%= block invalid %>")
** (ExEEx.TemplateError) block name should be a string literal: nofile:1
"""
def render_string(template, params \\ []) when is_list(params) do
compile_string(template)
|> render(params)
end
@doc """
Compile template file.
## Examples
iex> ExEEx.compile("test/templates/hello.txt").name
"hello.txt"
"""
def compile(filename, opts \\ []) when is_binary(filename) do
file_path = adapter().expand_path(filename)
adapter().read(file_path)
|> compile_string(Keyword.put(opts, :file, file_path))
end
@doc """
Compile template file.
## Examples
iex> ExEEx.compile_string("Hello, world!").name
:nofile
"""
def compile_string(source, opts \\ []) when is_binary(source) do
{dir, name} =
with nil <- Keyword.get(opts, :file) do
#
# インメモリの場合、現在のディレクトリ
#
{adapter().expand_path("."), :nofile}
else
file ->
# 絶対パスに変換
file_path = adapter().expand_path(file)
#
# ファイルパスが渡されている場合、ディレクトリとベース名に分割
#
ExEEx.Utils.split_path(file_path)
end
file_name = to_string(name)
opts =
opts
|> Keyword.put(:file, file_name)
|> Keyword.put(:dir, dir)
|> Keyword.put(:includes, [])
|> Keyword.put(:engine, ExEEx.Engine)
ExEEx.Engine.BlockStack.init()
{code, _} =
EEx.compile_string(source, opts)
|> ExEEx.Engine.subst_blocks(file_name)
%ExEEx.Template{
code: code,
path: dir,
name: name
}
end
end