Current section
Files
Jump to
Current section
Files
lib/map_rewire.ex
defmodule MapRewire do
@debug Application.get_env(:map_rewire, :debug?)
@transform_to "=>"
@moduledoc """
Syntactic sugar to simply bulk rekey maps. MapRewire takes two arguments, data (map) and transformation (list of transformations / string of transformations separated by whitespace).
1. Main Syntax: `left<~>right` (`content<~>transformation`). Left value is the map that holds the data and keys you would like to update, Right value is an Elixir List that contains a string for each of the keys that you would like to update.
2. Transformation Syntax: `left=>right` (`from=>to`). Left is the original key, right is the new key.
3. Return Syntax: `[left, right]` (`[ original, rekeyed ]`). `left` is the original map. `right` is the new, rekeyed, map.
"""
require Logger
defmacro __using__(_) do
quote do
import MapRewire
end
end
@doc """
Macro syntax sugar to enable calling `rewire` in an elixir like way.
**Input params:**
1. `data` is passed as `content`
2. `transforms` is passed as `list` or `binary`.
**Output:**
`[left, right]` (`[ original, rekeyed ]`). `left` is the original map. `right` is the new, rekeyed, map.
"""
defmacro data <~> transforms do
quote do
rewire(unquote(data), unquote(transforms))
end
end
@doc """
Maps over the Enum `content` and replaces the key if it matches with an item in `list`.
**Example 1:**
```MapRewire.rewrite(%{"id"=>"234923409", "title"=>"asdf"}, ~w(title=>name id=>shopify_id))```
**Example 2:**
```MapRewire.rewrite(%{"id"=>"234923409"}, ['id=>shopify_id'])```
"""
def rewire(content, list) when is_map(content) and is_list(list) do
if(@debug) do
Logger.info("[MapRewire:arg1]rewire#content: #{inspect(content)}")
Logger.info("[MapRewire:arg2]rewire#list: #{inspect(list)}")
end
rewire_do(content, list)
end
def rewire(content, binary) when is_map(content) and is_binary(binary) do
if(@debug) do
Logger.info("[MapRewire:arg1]rewire#content: #{inspect(content)}")
Logger.info("[MapRewire:arg2]rewire#binary: #{inspect(binary)}")
end
list = String.split("#{binary}", " ")
rewire_do(content, list)
end
#
# Rewire raise statements
#
def rewire(arg1, arg2)
when is_map(arg1) == false and (is_list(arg2) == false or is_binary(arg2) == false),
do:
raise(
ArgumentError,
"[MapRewire:arg1<~>arg2] bad arguments. Arg1 should be a map, Arg2 should be a list or string." <>
" Arg1: `#{inspect(arg1)}`, Arg2: `#{inspect(arg2)}`"
)
def rewire(arg1, _arg2) when is_map(arg1) == false,
do:
raise(
ArgumentError,
"[MapRewire:arg1<~>arg2] bad argument. Expected Arg1 to be a map, got `#{inspect(arg1)}`"
)
def rewire(_arg1, arg2) when is_list(arg2) == false and is_binary(arg2) == false,
do:
raise(
ArgumentError,
"[MapRewire:arg1<~>arg2] bad argument. Expected Arg2 to be a list or string, got `#{
inspect(arg2)
}`"
)
def rewire(arg1, arg2),
do:
raise(
ArgumentError,
"[MapRewire:arg1<~>arg2] bad arguments. Error reason not known. Please check inspections: " <>
" Arg1: `#{inspect(arg1)}`, Arg2: `#{inspect(arg2)}`"
)
# logic for rewire
defp rewire_do(content, list) do
if(@debug) do
Logger.info("[MapRewire:arg1]rewire_do#content: #{inspect(content)}")
Logger.info("[MapRewire:arg2]rewire_do#list: #{inspect(list)}")
end
transform_list = rewire_do_create_transform_list(list)
[
content,
recursion(transform_list, content)
]
end
defp rewire_do_create_transform_list(input) do
if(@debug) do
Logger.info("[MapRewire]rewire_do_create_transform_list#input: #{inspect(input)}")
end
Enum.map(input, &transform_key_to_list/1)
end
defp transform_key_to_list(item) do
if(@debug) do
Logger.info("[MapRewire]transform_key_to_list#item: #{inspect(item)}")
end
String.split("#{item}", "#{@transform_to}")
end
defp recursion([key1, key2], map) when is_binary(key1) and is_binary(key2),
do: replace_key([key1, key2], map)
defp recursion([], map), do: map
defp recursion([head | tail], map) when is_list(head) and is_list(tail) do
new_map = replace_key(head, map)
recursion(tail, new_map)
end
# Takes `map`, removes key & value for `key1`, adds `key2` with the value of `key1`
# `MapRewire.replace_key([:title, :name], map)`
defp replace_key([key1, key2], map) do
if(@debug) do
Logger.info("[MapRewire]replace_key#key1: #{inspect(key1)}")
Logger.info("[MapRewire]replace_key#key2: #{inspect(key2)}")
Logger.info("[MapRewire]replace_key#map: #{inspect(map)}")
end
case Map.has_key?(map, key1) do
true ->
if(@debug) do
Logger.info(
"[MapRewire]replace_key: #{inspect(key1)} is present, moving it to a new map with the new key #{
inspect(key2)
}"
)
end
{value, new_map} = Map.pop(map, key1)
Map.put_new(new_map, key2, value)
false ->
if(@debug) do
Logger.info("[MapRewire]replace_key: #{inspect(key1)} is not present, skipping...")
end
map
end
end
end