Current section
Files
Jump to
Current section
Files
lib/exmatch.ex
defmodule ExMatch do
@moduledoc """
Assertions for data equivalence.
"""
alias ExMatch.BindingProtocol
@doc """
Raises if the values don't match and displays what exactly was different.
iex> ExMatch.match([1, a, 3], [1, 2, 3])
iex> 2 = a
"""
defmacro match(left, right) do
{bindings, left} = parse_ast(left)
quote do
unquote(bindings) =
case BindingProtocol.diff(unquote(left), unquote(right), %{}) do
{diff_left, diff_right} = diff ->
raise ExUnit.AssertionError,
left: diff_left,
right: diff_right,
message: "match failed",
context: {:match, []}
bindings when is_list(bindings) ->
bindings
end
end
end
defp parse_ast(left) when is_number(left) or is_bitstring(left) or is_atom(left) do
self =
quote do
unquote(left)
end
{[], self}
end
defp parse_ast({var, _, context} = binding) when is_atom(var) and is_atom(context) do
ExMatch.Var.parse(binding)
end
defp parse_ast(left) when is_list(left) do
ExMatch.List.parse(left, &parse_ast/1)
end
defp parse_ast({_, _} = left) do
ExMatch.Tuple.parse(left, &parse_ast/1)
end
defp parse_ast({:{}, _, _} = left) do
ExMatch.Tuple.parse(left, &parse_ast/1)
end
defp parse_ast({:%{}, _, _} = left) do
ExMatch.Map.parse(left, &parse_ast/1)
end
defp parse_ast({:%, _, _} = left) do
ExMatch.Struct.parse(left, &parse_ast/1)
end
defp parse_ast(left) do
ExMatch.Expr.parse(left)
end
end