# ex_aequo
<!--
DO NOT EDIT THIS FILE
It has been generated from the template `README.md.eex` by Extractly (https://github.com/RobertDober/extractly.git)
and any changes you make in this file will most likely be lost
-->
[![CI](https://github.com/RobertDober/ex_aequo/actions/workflows/ci.yml/badge.svg)](https://github.com/RobertDober/ex_aequo/actions/workflows/ci.yml)
[![Coverage Status](https://coveralls.io/repos/github/RobertDober/ex_aequo/badge.svg?branch=master)](https://coveralls.io/github/RobertDober/ex_aequo?branch=master)
[![Hex.pm](https://img.shields.io/hexpm/v/ex_aequo.svg)](https://hex.pm/packages/ex_aequo)
[![Hex.pm](https://img.shields.io/hexpm/dw/ex_aequo.svg)](https://hex.pm/packages/ex_aequo)
[![Hex.pm](https://img.shields.io/hexpm/dt/ex_aequo.svg)](https://hex.pm/packages/ex_aequo)
# ExAequo Elixir Tools
### Installation:
```elxir
{ :ex_aequo, ">= 0.2.2" }
```
Meaning of the name. All nice latin expressions starting with _Ex_ are consumed at an alarming rate, so, all things
being equal, I choose this one.
## ExAequo.Enum offers some extension functions for Elixir's Enum module
### Grouped Accumulation
Groupes accumulated values of an Enum according to a function that
indicates if two consequent items are of the same kind and if so
how to accumulate their two values.
The `grouped_reduce` function returns the groupes in reverse order, as,
during traversal of lists quite often reversing the result of the
classical "take first and push a function of it to the result" pattern
cancels out.
An optional, `reverse: true` keyword option can be provided to reverse
the final result for convenience.
iex(0)> add_same = fn {x, a}, {y, b} ->
...(0)> cond do
...(0)> x == y -> {:cont, {x, a + b}}
...(0)> true -> {:stop, nil} end end
...(0)> E.grouped_reduce(
...(0)> [{:a, 1}, {:a, 2}, {:b, 3}, {:b, 4}], add_same)
[{:b, 7}, {:a, 3}]
The `grouped_inject` function behaves almost identically to `grouped_reduce`,
however an initial value is provided.
iex(1)> sub_same = fn {x, a}, {y, b} ->
...(1)> cond do
...(1)> x == y -> {:cont, {x, a - b}}
...(1)> true -> {:stop, nil}
...(1)> end
...(1)> end
...(1)> E.grouped_inject(
...(1)> [{:a, 1}, {:b, 2}, {:b, 2}, {:c, 2}, {:c, 1}, {:c, 1}],
...(1)> {:a, 43}, sub_same, reverse: true)
[a: 42, b: 0, c: 0]
## Tools to facilitate dispatching on keyword parameters, used in contexts like the following
@defaults [a: 1, b: false] # Keyword or Map
def some_fun(..., options \ []) # options again can be a Keyword or Map
{a, b} = tuple_from_params(@defaults, options, [:a, :b])
### Merging defaults and actual parameters
Its most useful feature is that you will get a map whatever the mixtures of maps and keywords the
input was
```elixir
iex(0)> merge_params([])
%{}
iex(1)> merge_params([a: 1], %{b: 2})
%{a: 1, b: 2}
iex(2)> merge_params(%{a: 1}, [a: 2, b: 2])
%{a: 2, b: 2}
```
#### Strict merging
_Not implemented yet_
### Extracting params from the merged defaults and actuals
iex(3)> defaults = [foo: false, depth: 3]
...(3)> tuple_from_params(defaults, %{foo: true}, [:foo, :depth])
{true, 3}
As defaults are required a missing parameter will raise an Error
iex(4)> try do
...(4)> tuple_from_params([], [foo: 1], [:bar])
...(4)> rescue
...(4)> KeyError -> :caught
...(4)> end
:caught
Alternatively on can extract a map
iex(5)> map_from_params([], [hello: "world"], [:hello])
%{hello: "world"}
This is the 2 param form which is identical to an empty default map
iex(6)> map_from_params(%{a: 1, b: 2}, [:a])
%{a: 1}
This is the 2 param form which is identical to an empty default map
iex(7)> tuple_from_params(%{a: 1, b: 2}, [:b, :a])
{2, 1}
```elxir
iex(0)> base_name_without_ext("a/b/c.txt")
"c"
iex(1)> base_name_without_ext("a/b/c.txt.eex")
"c.txt"
iex(2)> base_name_without_ext("a/b/c")
"c"
```
```elxir
iex(3)> full_name_without_ext("a/b/c.txt")
"a/b/c"
iex(4)> full_name_without_ext("a/b/c.txt.eex")
"a/b/c.txt"
iex(5)> full_name_without_ext("a/b/c")
"a/b/c"
iex(6)> full_name_without_ext("/c")
"/c"
```
SPDX-License-Identifier: Apache-2.0