# `MapSorter.Compare`
[🔗](https://github.com/RaymondLoranger/map_sorter/blob/main/lib/map_sorter/compare.ex#L1)

A compare function and a heredoc to become a compare function.

# `comp_fun`

```elixir
@type comp_fun() :: (Access.container(), Access.container() -&gt; boolean())
```

Compare function

# `fun`

```elixir
@spec fun(MapSorter.SortSpecs.t()) :: comp_fun()
```

Generates an `Enum.sort/2` compare function from a list of sort specs.

## Examples

    # To run multiple doctests sequentially, remove empty lines between them.
    iex> alias MapSorter.{Compare, Log}
    iex> Log.debug(:doctest_id, {:compare_id_1, __ENV__})
    iex> sort_specs = [:dob, desc: :likes]
    iex> fun = Compare.fun(sort_specs)
    iex> map1 = %{name: "John", dob: "2000-01-01", likes: "ski"}
    iex> map2 = %{name: "Jane", dob: "2000-01-01", likes: "hike"}
    iex> is_function(fun, 2) and fun.(map1, map2)
    true
    # Compare function always true => no reordering...
    iex> alias MapSorter.{Compare, Log}
    iex> Log.debug(:doctest_id, {:compare_id_2, __ENV__})
    iex> sort_specs = {:dob, desc: :likes}
    iex> fun = Compare.fun(sort_specs)
    iex> is_function(fun, 2) and fun.(1, 2) and fun.(2, 1)
    true
    iex> alias MapSorter.{Compare, Log}
    iex> Log.debug(:doctest_id, {:compare_id_3, __ENV__})
    iex> sort_specs = fn -> [:dob, desc: :likes] end
    iex> fun = Compare.fun(sort_specs.())
    iex> map1 = %{name: "John", dob: "2000-01-01", likes: "ski"}
    iex> map2 = %{name: "Jane", dob: "2000-01-01", likes: "hike"}
    iex> is_function(fun, 2) and fun.(map1, map2)
    true
    iex> alias MapSorter.{Compare, Log}
    iex> Log.debug(:doctest_id, {:compare_id_4, __ENV__})
    iex> sort_specs = Tuple.to_list({:dob, {:desc, :likes}})
    iex> fun = Compare.fun(sort_specs)
    iex> map1 = %{name: "John", dob: "2000-01-01", likes: "ski"}
    iex> map2 = %{name: "Jane", dob: "2000-01-01", likes: "hike"}
    iex> is_function(fun, 2) and fun.(map1, map2)
    true

# `heredoc`

```elixir
@spec heredoc(MapSorter.SortSpecs.t()) :: String.t()
```

Generates a `cond/1` expression as a heredoc to become a compare function.

The heredoc may be converted into its quoted form at compile time or else
have its contents evaluated at runtime.

This function cannot be named `cond` as it is among the `Kernel.SpecialForms`.

## Examples

    iex> alias MapSorter.Compare
    iex> Compare.heredoc([])
    """
    & cond do
    true -> true or &1 > &2
    end
    """

    iex> alias MapSorter.Compare
    iex> sort_specs = [:name, {:desc, :dob}]
    iex> Compare.heredoc(sort_specs)
    """
    & cond do
    &1[:name] < &2[:name] -> true
    &1[:name] > &2[:name] -> false
    &1[:dob] > &2[:dob] -> true
    &1[:dob] < &2[:dob] -> false
    true -> true or &1 > &2
    end
    """

    iex> alias MapSorter.Compare
    iex> sort_specs = [:name, {:desc, {:dob, Date}}]
    iex> Compare.heredoc(sort_specs)
    """
    & cond do
    &1[:name] < &2[:name] -> true
    &1[:name] > &2[:name] -> false
    &1[:dob] != nil and Date.compare(&1[:dob], &2[:dob]) == :gt -> true
    &1[:dob] != nil and Date.compare(&1[:dob], &2[:dob]) == :lt -> false
    true -> true or &1 > &2
    end
    """

    iex> alias MapSorter.Compare
    iex> sort_specs = [:name, {:desc, {:account, Path}}]
    iex> Compare.heredoc(sort_specs)
    """
    & cond do
    &1[:name] < &2[:name] -> true
    &1[:name] > &2[:name] -> false
    &1[{:account, Path}] > &2[{:account, Path}] -> true
    &1[{:account, Path}] < &2[{:account, Path}] -> false
    true -> true or &1 > &2
    end
    """

---

*Consult [api-reference.md](api-reference.md) for complete listing*
