Current section
Files
Jump to
Current section
Files
lib/slime/parser/attributes_keyword.ex
defmodule Slime.Parser.AttributesKeyword do
@moduledoc "
Utilities for handling element attributes.
"
@doc """
Merges multiply attributes values for keys specified in merge_rules.
Attribute value may be given by string, list, or {:eex, args} node
`merge_rules` should me an `%{attribute_name: joining_character}` map
## Examples
iex> Slime.Parser.AttributesKeyword.merge(
...> [class: "a", class: ["b", "c"], class: "d"],
...> %{class: " "}
...> )
[class: "a b c d"]
iex> Slime.Parser.AttributesKeyword.merge(
...> [class: "a", class: ["b", "c"], class: {:eex, "d"}],
...> %{class: " "}
...> )
[class: {:eex, ~S("a b c \#{d}")}]
"""
def merge(keyword_list, merge_rules) do
Enum.reduce(merge_rules, keyword_list, fn {attr, join}, result ->
values =
result
|> Enum.filter(fn {key, _value} -> key == attr end)
|> Enum.map(fn {_key, value} -> value end)
if values == [] do
result
else
values = merge_attribute_values(values, join)
result = Enum.filter(result, fn {key, _value} -> key != attr end)
[{attr, values} | result]
end
end)
end
defp merge_attribute_values(values, join_by) do
result = join_attribute_values(values, join_by)
if Enum.any?(values, &dynamic_value?/1) do
{:eex, ~s("#{result}")}
else
result
end
end
defp dynamic_value?({:eex, _}), do: true
defp dynamic_value?(_), do: false
defp join_attribute_values(values, join_by) do
values |> Enum.map(&attribute_val(&1, join_by)) |> List.flatten() |> Enum.join(join_by)
end
defp attribute_val({:eex, content}, join_by) do
case Code.string_to_quoted!(content) do
list when is_list(list) ->
list |> List.flatten() |> Enum.join(join_by)
_ ->
"\#{" <> content <> "}"
end
end
defp attribute_val(value, _), do: value
end