Skip to content

If and Unless Sections from flat maps throw exceptions #29

@drewknab

Description

@drewknab

Given a sectioned template and a flat map structure, Mustache.ex throws an exception.

Example from the opening of the spec:

A typical Mustache template:

Hello {{name}}
You have just won {{value}} dollars!
{{#in_ca}}
Well, {{taxed_value}} dollars, after taxes.
{{/in_ca}}
Given the following hash:

{
"name": "Chris",
"value": 10000,
"taxed_value": 10000 - (10000 * 0.4),
"in_ca": true
}
Will produce the following:

Hello Chris
You have just won 10000 dollars!
Well, 6000.0 dollars, after taxes.

Currently, this throws an exception:

     The following arguments were given to Access.get/3:
     
         # 1
         true
     
         # 2
         "taxed_value"
     
         # 3
         nil
     
     Attempted function clauses (showing 6 out of 6):
     

         def get(%module{} = container, key, default)
         def get(map, key, default) when is_map(map)
         def get(list, key, default) when is_list(list) and is_atom(key)
         def get(list, key, _default) when is_list(list) and is_integer(key)
         def get(list, key, _default) when is_list(list)
         def get(nil, _key, default)

In investigating this, it looks like if the val is true in process_if or false in process_unless then the above exception occurs.

  defp process_if(template, val) do
    case val do
      nil -> ""
      false -> ""
      [] -> ""
      [_ | _] -> val
                 |> Stream.map(&(render(template, &1)))
                 |> Enum.join()
      val -> render(template, val)
    end
  end

  defp process_unless(template, val) do
    case val do
      nil -> render(template, val)
      false -> render(template, val)
      [] -> render(template, val)
      _val -> ""
    end
  end

The solution I came up with looks something like this that seems to continue to allow the rendering a list or a nested map while also supporting a flat structure.

  defp process_if(template, val, data \\ %{}) do
    case val do
      nil -> ""
      false -> ""
      [] -> ""
      [_ | _] -> val
                 |> Stream.map(&(render(template, &1)))
                 |> Enum.join()
      true -> render(template, data)
      val -> render(template, val)
    end
  end

  defp process_unless(template, val, data \\ %{}) do
    case val do
      nil -> render(template, val)
      false -> render(template, data)
      [] -> render(template, val)
      _val -> ""
    end
  end

This allows a nested template to render successfully from a flat map.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions