kip

kip

ex_cldr Core Team

A little while ago someone asked about how to get a full list of function clauses when there is a function clause error. I have some code that generates a lot of function clauses so I had a similar need. I couldn’t find my code at the time but I have now and post it here so I can find it again :slight_smile:

Example

iex> FunctionClause.match MyApp.Cldr.Number.Formatter.Decimal, :to_string, ["123", "#", []]
    def to_string(number, format, options) when is_binary(format) and is_list(options)
    def to_string(number, "#,##0%", options) when is_map(options)
    def to_string(number, "#,##0.###", options) when is_map(options)
    def to_string(number, "#,##0.00 ¤", options) when is_map(options)
    def to_string(number, "#,##0.00 ¤;(#,##0.00 ¤)", options) when is_map(options)
    def to_string(number, "#,##0 %", options) when is_map(options)
    def to_string(number, "#E0", options) when is_map(options)
    def to_string(number, "0", options) when is_map(options)
    def to_string(number, "0 Billion", options) when is_map(options)
    def to_string(number, "0 Billionen", options) when is_map(options)
    def to_string(number, "0 Milliarde", options) when is_map(options)
    def to_string(number, "0 Milliarden", options) when is_map(options)
    .... and a lot more :-)

Code

defmodule FunctionClause do
  @moduledoc """
  Format function clauses using Exception.blame/3
  """

  @doc """
  Given a `module`, `function`, and `args` see
  that function clause would match or not match.

  This is useful for helping diagnose function
  clause errors when many clauses are generated
  at compile time.

  """
  @spec match(module(), atom(), list(any)) :: :ok | no_return()
  def match(module, function, args) do
    case Exception.blame_mfa(module, function, args) do
      {:ok, kind, clauses} ->
        formatted_clauses(function, kind, clauses, &blame_match/2)

      :error ->
        raise ArgumentError,
              "Function #{inspect(module)}.#{function}/#{length(args)} " <>
                "is not known."
    end
  end

  defp formatted_clauses(function, kind, clauses, ast_fun) do
    format_clause_fun = fn {args, guards} ->
      code = Enum.reduce(guards, {function, [], args}, &{:when, [], [&2, &1]})
      "    #{kind} " <> Macro.to_string(code, ast_fun) <> "\n"
    end

    clauses
    |> Enum.map(format_clause_fun)
    |> Enum.join()
    |> IO.puts()
  end

  defp blame_match(%{match?: true, node: node}, _),
    do: Macro.to_string(node)

  defp blame_match(%{match?: false, node: node}, _),
    do: IO.ANSI.red() <> Macro.to_string(node) <> IO.ANSI.reset()

  defp blame_match(_, string), do: string
end

Where Next? Top

Trending in Guides/Tuts Top

c4lliope
# ~/src/livebook/.iex.exs System.cmd("xdg-open", [ LivebookWeb.Endpoint.access_url() ] ) Because Livebook requires a unique passcode on ...
New
krasenyp
You probably already know that &lt;span&gt;{nil}&lt;/span&gt; in a HEEX template produces &lt;span&gt; &lt;/span&gt; when rendered. I fin...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
garrison
Hobbes is a low-level distributed database for the Elixir programming language. Hobbes provides a simple, safe, and scalable storage lay...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
Damirados
Hello everyone. After busy few months I am happy to announce v0.1.0 of Emerge &amp; Solve. They are GUI (Emerge) and State management (S...
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews