Why? 🤷
We found ourselves copy-pasting a few useful "helper" functions across our Elixir projects ... <br /> it wasn't "DRY", 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.13.1"}
]
endFunction 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}
Useful.atomize_map_keys(my_map)
%{name: Alex, id: 1}Works recursively for deeply nested maps:
person = %{"name" => "Alex", id: 1, details: %{"age" => 17, height: 185}}
Useful.atomize_map_keys(person)
%{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)
:a.b()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])
17
iex> Useful.get_in_default(map, [:data, :everything], "Awesome")
"Awesome"
iex> Useful.get_in_default(conn, [:assigns, :person, :id], 0)
0
We needed this for getting conn.assigns.person.id
in our App
without having to write a bunch of boilerplate!
e.g:
person_id =
case Map.has_key?(conn.assigns, :person) do
false -> 0
true -> Map.get(conn.assigns.person, :id)
endis 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: stackoverflow.com/questions/48781427/optional-default-value-for-get-in <br /> All credit to
@PatNowak🙌
The ideal syntax for this would be:
person_id = conn.assigns.person.id || 0
But Elixir "Me no likey" ...
So this is what we have.
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:
get_list_of_items(person_id)
|> 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}}
Useful.stringify_map(map)
"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
typeof
from JavaScript land.
iex> myvar = 42
iex> Useful.typeof(myvar)
"integer"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}Docs 📜
Detailed docs available at: https://hexdocs.pm/useful/Useful.html
Help Us Help You! 🙏
If you need a specific helper function or utility (e.g: something you found useful in a different programming language), please open an issue so that we can all benefit from useful functions.
Thanks!