Skip to content

Instantly share code, notes, and snippets.

@astery
Last active June 11, 2020 15:35
Show Gist options
  • Save astery/2fdddc2fdc7597856a5ce83289f3c276 to your computer and use it in GitHub Desktop.
Save astery/2fdddc2fdc7597856a5ce83289f3c276 to your computer and use it in GitHub Desktop.
Indifferent access in elixir
defmodule Access do
def indifferent_key(key) do
fn
:get, data, next ->
get_atom_or_string_key!(data, key)
|> case do
nil -> next.(nil)
key -> next.(Map.get(data, key))
end
:get_and_update, data, next ->
{key, value} =
get_atom_or_string_key!(data, key)
|> case do
nil -> {key, nil}
key -> {key, Map.get(data, key)}
end
case next.(value) do
{get, update} -> {get, Map.put(data, key, update)}
:pop -> {value, Map.delete(data, key)}
end
end
end
defp map_indifferent_get(data, key) do
get_atom_or_string_key!(data, key)
|> case do
nil -> nil
key -> Map.get(data, key)
end
end
defp get_atom_or_string_key!(data, key) do
{atom_key, string_key} =
cond do
is_atom(key) -> {key, to_string(key)}
is_binary(key) -> {String.to_existing_atom(key), key}
true -> raise "Indifferent key must be an atom or string"
end
{Map.has_key?(data, atom_key), Map.has_key?(data, string_key)}
|> case do
{true, true} -> raise "Map contains both string and atom key: #{string_key}"
{false, false} -> nil
{true, false} -> atom_key
{false, true} -> string_key
end
end
end
update_in(attrs, [City.Access.indifferent_key(field)], fn value ->
...
end)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment