defmodule Chaperon.Util do
@moduledoc """
Helper functions used throughout `Chaperon`'s codebase.
"""
@spec preserve_vals_merge(map, map) :: map
def preserve_vals_merge(map1, map2) do
new_map =
for {k, v2} <- map2 do
case map1[k] do
nil ->
{k, v2}
v1 when is_list(v1) and is_list(v2) ->
{k, v2 ++ v1}
v1 when is_list(v1) ->
{k, [v2 | v1]}
v1 ->
{k, [v2, v1]}
end
end
|> Enum.into(%{})
map1
|> Map.merge(new_map)
end
@doc """
Converts a map's values to be prefixed (put in a tuple as the first element).
## Examples
iex> Chaperon.Util.map_prefix_value(%{foo: 1, bar: 2}, :wat)
%{foo: {:wat, 1}, bar: {:wat, 2}}
"""
@spec map_prefix_value(map, any) :: map
def map_prefix_value(map, prefix) do
for {k, v} <- map do
{k, {prefix, v}}
end
|> Enum.into(%{})
end
@doc """
Inserts a given key-value pair (`{k2, v2}` under any values within `map` that
are also maps).
## Example
iex> m = %{a: 1, b: %{baz: 3}, c: %{foo: 1, bar: 2}}
iex> Chaperon.Util.map_nested_put(m, :baz, 10)
%{a: 1, b: %{baz: 10}, c: %{foo: 1, bar: 2, baz: 10}}
iex> Chaperon.Util.map_nested_put(m, :foo, "ok")
%{a: 1, b: %{baz: 3, foo: "ok"}, c: %{foo: "ok", bar: 2}}
"""
@spec map_nested_put(map, any, any) :: map
def map_nested_put(map, k2, v2) do
for {k, v} <- map do
case v do
v when is_map(v) ->
{k, Map.put(v, k2, v2)}
v ->
{k, v}
end
end
|> Enum.into(%{})
end
@doc """
Returns last `amount` elements in a given `Enum` as a `List`.
## Example
iex> alias Chaperon.Util
iex> [] |> Util.last(1)
[]
iex> [1] |> Util.last(1)
[1]
iex> [1,2,3,4] |> Util.last(1)
[4]
iex> [1,2,3,4] |> Util.last(2)
[3,4]
iex> [1,2,3,4] |> Util.last(3)
[2,3,4]
iex> [1,2,3,4] |> Util.last(4)
[1,2,3,4]
iex> [1,2,3,4] |> Util.last(5)
[1,2,3,4]
"""
def last(enum, amount) when is_list(enum) do
case Enum.count(enum) - amount do
n when n > 0 ->
enum
|> Enum.drop(n)
_ ->
enum
end
end
@spec shortened_module_name(module | map, non_neg_integer) :: String.t()
def shortened_module_name(mod, max_nesting \\ 2)
def shortened_module_name(%{name: name}, max_nesting) when is_binary(name) do
name
|> String.split(".")
|> last(max_nesting)
|> Enum.join(".")
end
def shortened_module_name(mod, max_nesting) do
mod
|> Module.split()
|> last(max_nesting)
|> Enum.join(".")
end
@spec module_name(module | %{name: String.t()}) :: String.t()
def module_name(%{name: name}) when is_binary(name), do: name
def module_name(mod) when is_atom(mod) do
mod
|> Module.split()
|> Enum.join(".")
end
@spec local_pid?(pid) :: boolean
def local_pid?(pid) do
case inspect(pid) do
"#PID<0." <> _ ->
true
_ ->
false
end
end
def percentile_name(percentile) do
p =
percentile
|> to_string
|> String.replace(".", "_")
:"percentile_#{p}"
end
def symbolize_keys(map) do
map
|> Map.new(fn {k, v} ->
k = String.to_atom(k)
v =
case v do
nested_map when is_map(nested_map) ->
symbolize_keys(nested_map)
_ ->
v
end
{k, v}
end)
end
end