<div align="center">

# `useful`

A collection of useful functions for building `Elixir` Apps.

![GitHub Workflow Status](
[![ dependency status](](
[![contributions welcome](](



# Why? 🤷

We found ourselves copy-pasting a few useful "helper" functions
across our Elixir projects ... <br />
it wasn't
so we created this library.

# What? 💭

A library of useful functions
that we reach for
when building `Elixir` Apps.

# Who? 👤

This library is used in our various `Elixir` / `Phoenix` apps. <br />
As with everything we do it's Open Source, Tested and Documented
so that _anyone_ can benefit from it.

# How? 💻

## Install ⬇️

Install by adding `useful` to your list of dependencies in `mix.exs`:

def deps do
    {:useful, "~> 1.14.0"}

## Function Reference

### `atomize_map_keys/1`

Converts a `Map` that has strings as keys (or mixed keys)
to have only atom keys. e.g:

# map that has different types of keys:
my_map = %{"name" => "Alex", id: 1}
%{name: Alex, id: 1}

Works recursively for deeply nested maps:

person = %{"name" => "Alex", id: 1, details: %{"age" => 17, height: 185}}
%{name: Alex, id: 1, details: %{age: 17, height: 185}}

### `flatten_map/1`

Flatten a `Map` of any depth/nesting:

iex> map = %{name: "alex", data: %{age: 17, height: 185}}
iex> Useful.flatten_map(map)
%{data__age: 17, data__height: 185, name: "alex"}

**Note**: `flatten_map/1` converts all Map keys to `Atom`
as it's easier to work with atoms as keys
e.g: `map.person__name` instead of `map["person__name"]`.
We use the `__` (_double underscore_)
as the delimiter for the keys of nested maps,
because if we attempt to use `.` (_period character_)
we get an error:

iex(1)> :a.b
** (UndefinedFunctionError) function :a.b/0 is undefined (module :a is not available)

### `get_in_default/1`

Get a deeply nested value from a map.
`get_in_default/3` Proxies `Kernel.get_in/2`
  but allows setting a `default` value as the 3rd argument.

iex> map = %{name: "alex", detail: %{age: 17, height: 185}}
iex> Useful.get_in_default(map, [:data, :age])
iex> Useful.get_in_default(map, [:data, :everything], "Awesome")
iex> Useful.get_in_default(conn, [:assigns, :person, :id], 0)

We needed this for getting ``
in our [`App`](
without having to write a bunch of boilerplate!

person_id =
  case Map.has_key?(conn.assigns, :person) do
    false -> 0
    true -> Map.get(conn.assigns.person, :id)

is just:

person_id = Useful.get_in_default(conn, [:assigns, :person, :id], 0)

_Muuuuuuch cleaner/clearer_! 😍 
If any of the keys in the list is not found
it doesn't _explode_ with errors,
simply returns the `default` value `0` 
and continues!

> **Note**: Code inspired by:
[]( <br />
All credit to [**`@PatNowak`**]( 🙌

The ideal syntax for this would be:
person_id = || 0
But `Elixir` "_Me no likey_" ...
So this is what we have.

### `list_tuple_to_unique_keys/1`

Turns a list of tuples with the _same_ key 
into a list of tuples with _unique_ keys.
Useful when dealing with "multipart" forms 
that upload multiple files. e.g:

parts = [{"file", "pic1.png"}, {"file", "pic2.png"}]
[{"file-1", "pic1.png"}, {"file-2", "pic2.png"}]

### `remove_item_from_list/2`

Remove an `item` from a `list`.

With numbers:

list = [1, 2, 3, 4]
Useful.remove_item_from_list(list, 3)
[1, 2, 4]

With a `List` of `Strings`:

list = ["climate", "change", "is", "not", "real"]
Useful.remove_item_from_list(list, "not")
["climate", "change", "is", "real"]

The `list` is the first argument to the function 
so it's easy to pipe:

|> Useful.remove_item_from_list("item_to_be_removed")
|> etc.

### `stringify_map/1`

Stringify a `Map` e.g. to store it in a DB or log it stdout.

map = %{name: "alex", data: %{age: 17, height: 185}}
"data__age: 17, data__height: 185, name: alex"

### `stringify_tuple/1`

Stringify a tuple of any length; useful in debugging.

iex> tuple = {:ok, :example}
iex> Useful.stringify_tuple(tuple)
"ok: example"

### `typeof/1`

Returns the type of a variable, e.g: "function" or "integer"
Inspired by
from `JavaScript` land.

iex> myvar = 42
iex> Useful.typeof(myvar)

### `empty_dir_contents/1`

Empties the directory
(_deletes all files and any nested directories_)
recursively, but does _not_ delete the actual directory.
This is useful when you want to reset a directory,
e.g. when testing.

iex> dir = "tmp" # contains lots of sub directories and files
iex> Useful.empty_dir_contents(dir)
{:ok, dir}

<br />

# Docs 📜

Detailed docs available at:

<br />

# Help Us Help You! 🙏

If you need a specific helper function or utility
(e.g: something you found useful in a different programming language),
[open an issue](
so that we can all benefit from useful functions.