Current section
Files
Jump to
Current section
Files
lib/liquid/variable.ex
defmodule Liquid.Variable do
@moduledoc """
Module to create and lookup for Variables
"""
defstruct name: nil, literal: nil, filters: [], parts: []
alias Liquid.{Appointer, Filters, Variable, Context}
@doc """
resolves data from `Liquid.Variable.parse/1` and creates a variable struct
"""
def create(markup) when is_binary(markup) do
[name | filters] = markup |> parse
name = String.trim(name)
variable = %Liquid.Variable{name: name, filters: filters}
parsed = Liquid.Appointer.parse_name(name)
if String.contains?(name, "%") do
raise Liquid.SyntaxError, message: "Invalid variable name"
end
Map.merge(variable, parsed)
end
@doc """
Assigns context to variable and than applies all filters
"""
@spec lookup(%Variable{}, %Context{}) :: {String.t(), %Context{}}
def lookup(%Variable{} = v, %Context{} = context) do
{ret, filters} = Appointer.assign(v, context)
result =
try do
{:ok, filters |> Filters.filter(ret) |> apply_global_filter(context)}
rescue
e in UndefinedFunctionError -> {e, e.reason}
e in ArgumentError -> {e, e.message}
e in ArithmeticError -> {e, "Liquid error: #{e.message}"}
end
case result do
{:ok, text} -> {text, context}
{error, message} -> process_error(context, error, message)
end
end
defp process_error(%Context{template: template} = context, error, message) do
error_mode = Application.get_env(:liquid, :error_mode, :lax)
case error_mode do
:lax ->
{message, context}
:strict ->
context = %{context | template: %{template | errors: template.errors ++ [error]}}
{nil, context}
end
end
defp apply_global_filter(input, %Context{global_filter: nil}), do: input
defp apply_global_filter(input, %Context{global_filter: global_filter}),
do: global_filter.(input)
@doc """
Parses the markup to a list of filters
"""
def parse(markup) when is_binary(markup) do
parsed_variable =
if markup != "" do
Liquid.filter_parser()
|> Regex.scan(markup)
|> List.flatten()
|> Enum.map(&String.trim/1)
else
[""]
end
if hd(parsed_variable) == "|" or hd(Enum.reverse(parsed_variable)) == "|" do
raise Liquid.SyntaxError, message: "You cannot use an empty filter"
end
[name | filters] = Enum.filter(parsed_variable, &(&1 != "|"))
filters = parse_filters(filters)
[name | filters]
end
defp parse_filters(filters) do
for markup <- filters do
[_, filter] = ~r/\s*(\w+)/ |> Regex.scan(markup) |> hd()
args =
Liquid.filter_arguments()
|> Regex.scan(markup)
|> List.flatten()
|> Liquid.List.even_elements()
[String.to_atom(filter), args]
end
end
end