Current section
Files
Jump to
Current section
Files
lib/toolbelt.ex
defmodule Toolbox.Keyword do
@moduledoc """
Functions closely related to `Keyword` that didn't make it or didn't yet make it to the standard library.
"""
@doc """
Check if the given value is a keyword list.
This function is **slow** because it iterates over every element in the list
to assert that it is indeed a key-value tuple.
"""
def is_keyword_list(val) do
is_list(val) and Toolbox.Enum.andmap(val, fn(el) -> is_tuple(el) and tuple_size(el) == 2 end)
end
end
defmodule Toolbox.Enum do
@moduledoc """
Functions closely related to `Enum` that didn't make it or didn't yet make it to the standard library.
"""
@doc """
Performs a classical ormap on the given enumerable.
"""
def andmap(enum, callback) do
cond do
length(enum) == 0 -> true
not callback.(Enum.first(enum)) -> false
true -> andmap(Enum.rest(enum),callback)
end
end
@doc """
Performs a classical ormap on the given enumerable.
"""
def ormap(enum, callback) do
cond do
length(enum) == 0 -> false
callback.(Enum.first(enum)) -> true
true -> ormap(Enum.rest(enum),callback)
end
end
@doc """
Transforms the keys of the map-like structure according to the given
procedure in the second argument.
"""
def map_keys(maplike, callback) do
Enum.map(maplike, fn({key,value}) -> {callback.(key),value} end)
end
@doc """
Transforms the values of the map-like structure according to the given
procedure in the second argument.
"""
def map_values(maplike, callback) do
Enum.map(maplike, fn({key,value}) -> {key,callback.(value)} end)
end
@doc """
Iterates over all own keys and nested keys and transforms them according to
the given procedure.
"""
def map_keys_deep(maplike, callback) do
Enum.map(maplike, fn({key,val}) ->
if is_map(val) do
{callback.(key), val |> map_keys_deep(callback)}
else
{callback.(key), val}
end
end)
end
@doc """
Iterates over all own values and nested values and transforms them according
to the given procedure.
"""
def map_values_deep(maplike, callback) do
Enum.map(maplike, fn({key,val}) ->
if is_map(val) do
{key, val |> map_values_deep(callback)}
else
{key,callback.(val)}
end
end)
end
@doc """
Deeply merges two maplike structures into one.
As a matter of convenience, the second argument may be nil, which will cause
the function to return the first argument unmodified.
"""
def merge_deep(a, b) do
if is_nil(b) do
a
else
Enum.reduce(b, a, fn({key,val},maplike) -> cond do
is_map(val) -> {key,merge_deep(val,a[key])}
Toolbox.Keyword.is_keyword_list(val) -> {key,merge_deep(val,a[key])}
end
end)
end
end
end