Current section
Files
Jump to
Current section
Files
lib/puck/prompt/solid.ex
if Code.ensure_loaded?(Solid) do
defmodule Puck.Prompt.Solid do
@moduledoc """
Solid (Liquid) template engine for prompts.
## Example
alias Puck.Prompt.Solid
{:ok, template} = Solid.parse("Hello {{ name }}!")
{:ok, "Hello World!"} = Solid.render(template, %{name: "World"})
# Or in one step
{:ok, "Hello World!"} = Solid.evaluate("Hello {{ name }}!", %{name: "World"})
See [Solid documentation](https://hexdocs.pm/solid) for template syntax.
"""
@behaviour Puck.Prompt
@impl true
def parse(template) when is_binary(template) do
Solid.parse(template)
end
@impl true
def parse!(template) when is_binary(template) do
case parse(template) do
{:ok, parsed} ->
parsed
{:error, error} ->
raise ArgumentError, "Failed to parse template: #{inspect(error)}"
end
end
@impl true
def render(template, context) when is_struct(template, Solid.Template) do
string_context = normalize_context(context)
case Solid.render(template, string_context) do
{:ok, iodata} ->
{:ok, IO.iodata_to_binary(iodata)}
{:error, errors, _partial} ->
{:error, errors}
end
end
@impl true
def render!(template, context) when is_struct(template, Solid.Template) do
case render(template, context) do
{:ok, rendered} ->
rendered
{:error, errors} ->
raise ArgumentError, "Failed to render template: #{inspect(errors)}"
end
end
@impl true
def evaluate(template, context) when is_binary(template) do
with {:ok, parsed} <- parse(template) do
render(parsed, context)
end
end
@impl true
def evaluate!(template, context) when is_binary(template) do
case evaluate(template, context) do
{:ok, rendered} -> rendered
{:error, errors} -> raise ArgumentError, "Failed to evaluate template: #{inspect(errors)}"
end
end
defp normalize_context(context) when is_map(context) do
Map.new(context, fn {k, v} -> {to_string(k), v} end)
end
end
end