ex_aequo

CI Coverage Status Hex.pm Hex.pm Hex.pm

ExAequo Elixir Tools

Installation:

{ :ex_aequo, ">= 0.5.0" }

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.File

expands wc and zips each matching file into a list of {String.t, File.Stat.t}

read a file into lines

iex(0)> readlines(Path.join(~W[test fixtures a_simple_file.txt]))
["Line 1", "Line two", " Una terza linea"]

expands wc and zips each matching file into a list of {String.t, File.Stat.t}, then filters only the files from today

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]

Support for the 256 ANSI and full RGB colors

N.B. Does, of course, respect the usage of the $NO_COLOR variable

The most basic approach is to use the generated escape sequences directly in your code, e.g.

IO.puts(ExAequo.Color.rgb(250, 148, 13) <> "Brownish Orange" <> ExAequo.Color.reset)

rgb

The generated escape codes would be:

iex(1)> rgb(250, 148, 13)
"\e[38;2;250;148;13m"
iex(2)> reset()
"\e[0m"

format

But like IO.ANSI a convenience function called format is available

iex(3)> format(["Hello", "World"])
["Hello", "World"]

As one can see it is tailor made for IO.puts and may be converted into a string by means of IO.chardata_to_string, this conversion can also be done by format itself

iex(4)> format(["Hello", "World"], to_string: true)
"HelloWorld"

RGB

In order to get colors into the mix we can use, atoms (for named colors or instructions like reset) or triples for RGB colors

iex(5)> format([{100, 20, 150}, "Deep Purple (pun intended)", :reset])
["\e[38;2;100;20;150m", "Deep Purple (pun intended)", "\e[0m"]

8 Color Space

And here are some nice names, which shall work on all terminals

iex(6)> format([:red, "red", :blue, "blue"])
["\e[31m", "red", "\e[34m", "blue"]

Oftentimes you will pass a variable to format and not a literal array, then the usage of the reset: true option might come in handy

iex(7)> some_values = [:azure1, "The sky?"]
...(7)> format(some_values, reset: true, to_string: true)
"\e[38;2;240;255;255mThe sky?\e[0m"

256 Colors

iex(8)> format([:color242, :color142, :color42])
["\e[38;5;242m", "\e[38;5;142m", "\e[38;5;42m"]

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

iex(0)> merge_params([])
%{}
```elixir
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
```elixir
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}
iex(0)> basename_without_ext("a/b/c.txt")
"c"
iex(1)> basename_without_ext("a/b/c.txt.eex")
"c.txt"
iex(2)> basename_without_ext("a/b/c")
"c"
iex(3)> fullname_without_ext("a/b/c.txt")
"a/b/c"
iex(4)> fullname_without_ext("a/b/c.txt.eex")
"a/b/c.txt"
iex(5)> fullname_without_ext("a/b/c")
"a/b/c"
iex(6)> fullname_without_ext("/c")
"/c"