defmodule ExDump do @moduledoc """ Helper utility for dumping variables in EEx templates for easy inspection. """ use Phoenix.HTML @doc """ Dumps a term to html in a easy to read format. """ @spec dump(any(), keyword()) :: {:safe, String.t()} def dump(term, opts \\ []) do theme = Keyword.get(opts, :theme, :default) {:safe, dump_html} = to_html(term) [ ~s(
), dump_html, ~s(
), css(theme) ] |> Enum.join("\n") |> raw() end defp to_html(nil), do: dump_simple_term(:empty, "nil") defp to_html(value) when is_binary(value), do: dump_simple_term(:binary, value) defp to_html(value) when is_boolean(value), do: dump_simple_term(:boolean, value) defp to_html(value) when is_integer(value), do: dump_simple_term(:integer, value) defp to_html(value) when is_tuple(value), do: dump_simple_term(:tuple, inspect(value)) defp to_html(%Decimal{} = value), do: dump_simple_term(:decimal, value) defp to_html(%Date{} = value), do: dump_simple_term("Date", value) defp to_html(%DateTime{} = value), do: dump_simple_term("Datetime", value) defp to_html(value) when is_atom(value), do: dump_simple_term(:atom, inspect(value)) defp to_html(%NaiveDateTime{} = value), do: dump_simple_term("Naive Datetime", value) defp to_html(%{__struct__: struct} = value) do struct_name = inspect(struct) value |> Map.from_struct() |> dump_complex_term("map", ~s[Struct: #{struct_name}]) end defp to_html(value) when is_map(value), do: dump_complex_term(value, "map", "Map") defp to_html(values) when is_list(values) do values |> Enum.with_index() |> Enum.map(fn {value, index} -> {index + 1, value} end) |> dump_complex_term("list", "List") end # catch all defp to_html(values), do: dump_simple_term("uknown", inspect(values)) defp dump_simple_term(type, value) when type in [:atom, :binary, :boolean, :decimal, :integer, :tuple] do """
#{type} #{value}
""" |> raw() end defp dump_simple_term(type, value) do """
#{type}
#{value}
""" |> raw() end defp dump_complex_term(values, name, title) do fingerprint = random_string() rows = values |> Enum.map(fn {key, value} -> {:safe, value_html} = to_html(value) """ #{inspect(key)} #{value_html} """ end) |> Enum.join("\n") toggle_javascript = "var elements = document.getElementsByClassName('#{fingerprint}'); " <> "for(var i = 0; i < elements.length; i++) { " <> "elements[i].style.display = elements[i].style.display == 'none' ? '' : 'none'; }" """ #{rows}
#{title}
""" |> raw() end defp css(:default) do """ """ end defp random_string(length \\ 6) do length |> :crypto.strong_rand_bytes() |> Base.url_encode64() |> binary_part(0, length) end end