Current section
Files
Jump to
Current section
Files
lib/better_params.ex
defmodule BetterParams do
import Plug.Conn
@moduledoc """
Implementation of the `BetterParams` plug and its core logic.
See the [`README`](https://github.com/sheharyarn/better_params) for
installation and usage instructions.
"""
@doc """
Initializes the Plug.
This plug doesn't take any arguments.
"""
def init(_) do
:ok
end
@doc """
Implementation of the Plug
This implements the `call` callback of the Plug. It calls the
`symbolize_merge/1` method on the `Plug.Conn` params map, so
they are available both with String and Atom keys.
"""
def call(%{params: params} = conn, :ok) do
%{ conn | params: symbolize_merge(params) }
end
@doc """
Core logic of the Plug
Takes a Map with String keys and returns a new map with
all values accessible by both String and Atom keys.
If the map is nested, it symbolizes all sub-maps
as well.
## Example
```
map = %{"a" => 1, "b" => %{"c" => 2, "d" => 3}}
map = BetterParams.symbolize_merge(map)
# => %{:a => 1, :b => %{c: 2, d: 3}, "a" => 1, "b" => %{"c" => 2, "d" => 3}}
map[:a] # => 1
map[:b][:c] # => 2
map.b.d # => 3
```
"""
def symbolize_merge(map) when is_map(map) do
map
|> Map.delete(:__struct__)
|> symbolize_keys
|> Map.merge(map)
end
defp symbolize_keys(map) when is_map(map) do
Enum.reduce map, %{}, fn {k, v}, m ->
v = case is_map(v) do
true -> symbolize_keys(v)
false -> v
end
map_put(m, k, v)
end
end
defp map_put(map, k, v) when is_map(map) do
try do
cond do
is_binary(k) -> Map.put(map, String.to_existing_atom(k), v)
true -> Map.put(map, k, v)
end
rescue
ArgumentError -> map
end
end
end