Packages
Elixir library for various strategies/experiments for avoiding string access to conn params
Retired package: Bad docs, whoops!
Current section
Files
Jump to
Current section
Files
lib/indifferent_access.ex
defmodule IndifferentAccess do
@moduledoc """
Transforms a map into a struct or map supporting indifferent access.
Primary intended usage is via `IndifferentAccess.Plug`, see docs there.
"""
alias IndifferentAccess.Params
@doc """
Returns a struct or map accessible by Atom keys with several configuration optons determining behavior. See examples below.
## Examples
iex> IndifferentAccess.indifferentize(%{"schedulers" => "4"})
%IndifferentAccess.Params{params: %{"schedulers" => "4"}, opts: [as: :struct, strategy: :replace]}
iex> IndifferentAccess.indifferentize(%{"schedulers" => "4"}, as: :struct, strategy: :replace)[:schedulers]
"4"
iex> IndifferentAccess.indifferentize(%{"schedulers" => %{"tls" => "3"}}, as: :struct, strategy: :replace)[:schedulers][:tls]
"3"
iex> IndifferentAccess.indifferentize(%{"schedulers" => %{"tls" => "3"}}, as: :struct, strategy: :static)[:schedulers][:tls]
nil
iex> IndifferentAccess.indifferentize(%{"schedulers" => %{"tls" => "3"}}, as: :map, strategy: :replace)[:schedulers][:tls]
"3"
iex> IndifferentAccess.indifferentize(%{"schedulers" => %{"tls" => "3", "random_string" => "2"}}, as: :map, strategy: :replace)[:schedulers]
%{:tls => "3", "random_string" => "2"}
"""
def indifferentize(params, opts \\ [as: :struct, strategy: :replace]) when is_map(params) do
case opts[:as] do
:map -> indifferentize_map(params, opts)
:struct -> Params.new(params, opts)
end
end
@doc """
Returns a map with String keys replaced or supplemented by Atom keys where equivalent atoms exist.
## Examples
iex> IndifferentAccess.indifferentize_map(%{"schedulers" => "4"}, strategy: :replace)
%{schedulers: "4"}
iex> IndifferentAccess.indifferentize_map(%{"schedulers" => "4"}, strategy: :augment)
%{:schedulers => "4", "schedulers" => "4"}
iex> IndifferentAccess.indifferentize_map(%{"schedulers" => %{"tls" => "3", "others" => "2"}}, strategy: :replace)
%{schedulers: %{"others" => "2", :tls => "3"}}
iex> IndifferentAccess.indifferentize_map(%{"schedulers" => %{"tls" => "3", "others" => "2"}}, strategy: :static)
** (RuntimeError) `strategy: :static` is only valid within IndifferentAccess.Params struct, not when using `as: :map` option in plug or indifferentize_map directly
"""
def indifferentize_map(map, opts \\ [])
def indifferentize_map(map, opts) when is_map(map) do
if Map.get(map, :__struct__) do
map
else
map_keys = Map.keys(map)
Enum.reduce(map, %{}, fn
{key, value}, accum when is_binary(key) ->
indifferent_value = indifferentize_map(value, opts)
case opts[:strategy] do
:augment ->
if existing_atom(key),
do:
accum
|> Map.put_new(existing_atom(key), indifferent_value)
|> Map.put(key, indifferent_value),
else: Map.put(accum, key, indifferent_value)
:replace ->
if existing_atom(key) && existing_atom(key) not in map_keys,
do:
accum
|> Map.put_new(existing_atom(key), indifferent_value)
|> Map.delete(key),
else: Map.put(accum, key, indifferent_value)
:static ->
raise "`strategy: :static` is only valid within IndifferentAccess.Params struct," <>
" not when using `as: :map` option in plug or indifferentize_map directly"
end
{key, value}, accum ->
indifferent_value = indifferentize_map(value, opts)
Map.put(accum, key, indifferent_value)
end)
end
end
def indifferentize_map(list, opts) when is_list(list),
do: Enum.map(list, &indifferentize_map(&1, opts))
def indifferentize_map(other, _opts), do: other
defp existing_atom(key) do
String.to_existing_atom(key)
rescue
ArgumentError -> nil
end
end