Current section
Files
Jump to
Current section
Files
lib/atomic_map.ex
defmodule AtomicMap.Opts do
@moduledoc ~S"""
Set any value to `false` to disable checking for that kind of key.
"""
defstruct safe: true,
underscore: true
end
defmodule AtomicMap do
def convert(v, opts \\ %{})
def convert(struct=%{__struct__: type}, opts=%AtomicMap.Opts{}) do
struct
|> Map.from_struct
|> convert(opts)
|> Map.put(:__struct__, type)
end
def convert(map, opts=%AtomicMap.Opts{}) when is_map(map) do
map |> Enum.reduce(%{}, fn({k,v}, acc)->
k = k |> convert_key(opts)
v = v |> convert(opts)
acc |> Map.put(k, v)
end)
end
def convert(list, opts=%AtomicMap.Opts{}) when is_list(list) do
list |> Enum.map(fn(x)-> convert(x, opts) end)
end
def convert(tuple, opts=%AtomicMap.Opts{}) when is_tuple(tuple) do
tuple |> Tuple.to_list |> convert(opts) |> List.to_tuple
end
def convert(v, _opts=%AtomicMap.Opts{}), do: v
# if you pass a plain map or keyword list as opts, those will match and convert it to struct
def convert(v, opts=%{}), do: convert(v, struct(AtomicMap.Opts, opts))
def convert(v, opts) when is_list(opts), do: convert(v, Enum.into(opts, %{}))
defp convert_key(k, opts) do
k
|> as_underscore(opts.underscore)
|> as_atom(opts.safe)
end
defp as_atom(s, true) when is_binary(s), do: s |> String.to_existing_atom
defp as_atom(s, false) when is_binary(s), do: s |> String.to_atom
defp as_atom(s, _), do: s
def as_underscore(s, true) when is_binary(s), do: s |> Macro.underscore
def as_underscore(s, true) when is_atom(s), do: s |> Atom.to_string |> as_underscore(true)
def as_underscore(s, false), do: s
end