Problem

Du hast Datenstrukturen, wie Listen, Structs oder Arrays und möchtest dir diese in deinem Template übersichtlich ausgeben.

Wenn IO.inspect für die Ausgabe in der Konsole gedacht ist, funktioniert die Ausgabe über inspect alleine nicht sonderlich gut - alles wird in einer Zeile ausgegeben.

Lösung

Die Lösung dazu liegt teilweise in HTML und teilweise in Elixir. Als erstes können wir die Ausgabe von inspect wesentlich verbessern.

Dazu nutzen wir folgende Parameter von inspect:

  • pretty: true - Datenstrukturen werden eingerückt.
  • limit: 1000 - Standardmäßig wird die Ausgabe für Collections nach 50 Elementen abgeschnitten. Wir erhöhen diesen Wert auf 1000. :infinity sorgt für eine unbegrenzte Ausgabe.
  • width: 150 - Selbsterklärend - wir brechen erst nach 150 Zeichen um.
  • struct: false - Structs werden nicht formatiert, sondern als Map ausgegeben.

Die Zeilenumbrüche von inspect werden in HTML normalerweise ignoriert. Wir können den Browser aber aber mit <pre> dazu überreden, diese zu beachten.

Um es semantisch korrekt zu machen, wrappen wir die Ausgabe in <pre><code></code></pre>. Die Funktion content_tag aus Phoenix.HTML hilft uns dabei. Folgenden Code kannst du in ein Modul deiner Wahl schreiben:

def debug(input) do
  content_tag :pre do
    content_tag :code do
      inspect(input, pretty: true, limit: 1000, width: 150, struct: false)
    end
  end
end

Als letztes machen wir diese Funktion in allen Views bekannt. Damit könnt ihr eure Variablen über z.B. <%= debug(@users) %> ausgeben.

Die Datei dazu ist nach eurem Projekt benamt und heißt [app_name]_web.ex. In die Sektion der Views importiert ihr euer Modul.

def view do
  quote do
    # ...
    import MyAppWeb.DebugHelper
  end
end

Code

Hier ist der vollständige Code inkl. Tests. In diesem Beispiel heißt meine Applikation platform. Dieser Name wird in deinem Projekt abweichen.

debug_helper.ex

defmodule PlatformWeb.DebugHelper do
  @moduledoc false
  use Phoenix.HTML

  @doc """
  iex> debug(%{test: "yes"}) |> safe_to_string()
  ~s(<pre><code>%{test: &quot;yes&quot;}</code></pre>)

  iex> debug(nil) |> safe_to_string()
  ~s(<pre><code>nil</code></pre>)
  """
  def debug(input) do
    content_tag :pre do
      content_tag :code do
        inspect(input, pretty: true, limit: 1000, width: 150, struct: false)
      end
    end
  end
end

debug_helper_test.exs

defmodule PlatformWeb.DebugHelperTest do
  use ExUnit.Case
  import PlatformWeb.DebugHelper
  import Phoenix.HTML

  doctest PlatformWeb.DebugHelper
end

platform_web.ex

def view do
  quote do
    # ...
    import PlatformWeb.DebugHelper
  end
end