Current section
Files
Jump to
Current section
Files
lib/jazz/decoder.ex
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# Version 2, December 2004
#
# DO WHAT THE FUCK YOU WANT TO PUBLIC LICENSE
# TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
#
# 0. You just DO WHAT THE FUCK YOU WANT TO.
defmodule Jazz.Decode do
@spec it(String.t) :: { :ok, term } | { :error, term }
@spec it(String.t, Keyword.t) :: { :ok, term } | { :error, term }
def it(string, options \\ []) when string |> is_binary do
case Jazz.Parser.parse(string) do
{ :ok, parsed } ->
{ :ok, transform(parsed, options) }
error ->
error
end
end
@spec it!(String.t) :: term | no_return
@spec it!(String.t, Keyword.t) :: term | no_return
def it!(string, options \\ []) when string |> is_binary do
Jazz.Parser.parse!(string) |> transform(options)
end
@spec transform(term) :: term
@spec transform(term, Keyword.t) :: term
def transform(parsed, options \\ [])
def transform(parsed, []) do
parsed
end
def transform(parsed, [keys: :atoms]) when parsed |> is_map do
for { key, value } <- parsed, into: %{} do
if value |> is_list or value |> is_map do
value = transform(value, keys: :atoms)
end
{ String.to_atom(key), value }
end
end
def transform(parsed, [keys: :atoms]) when parsed |> is_list do
for value <- parsed do
if value |> is_list or value |> is_map do
value = transform(value, keys: :atoms)
end
value
end
end
def transform(parsed, [keys: :atoms!]) when parsed |> is_map do
for { key, value } <- parsed, into: %{} do
if value |> is_list or value |> is_map do
value = transform(value, keys: :atoms!)
end
{ String.to_existing_atom(key), value }
end
end
def transform(parsed, [keys: :atoms!]) when parsed |> is_list do
for value <- parsed do
if value |> is_list or value |> is_map do
value = transform(value, keys: :atoms)
end
value
end
end
def transform(parsed, options) do
keys = options[:keys]
case options[:as] do
as when as |> is_atom ->
Jazz.Decoder.decode(as.__struct__, parsed, options)
[as] when as |> is_atom ->
for parsed <- parsed do
Jazz.Decoder.decode(as.__struct__, parsed, options)
end
as when as |> is_list ->
as = for { name, value } <- as do
{ to_string(name), value }
end
for { name, value } <- parsed, into: %{} do
value = cond do
spec = as |> List.keyfind(name, 0) ->
{ _name, spec } = spec
transform(value, Keyword.put(options, :as, spec))
keys && value |> is_list ->
transform(value, keys: keys)
true ->
value
end
if keys do
name = case keys do
:atoms -> String.to_atom(name)
:atoms! -> String.to_existing_atom(name)
end
end
{ name, value }
end
end
end
end
defprotocol Jazz.Decoder do
@fallback_to_any true
def decode(new, parsed, options)
end
defimpl Jazz.Decoder, for: Any do
def decode(%{__struct__: module} = new, parsed, _options) do
for { name, old } <- Map.delete(new, :__struct__), into: %{} do
if value = parsed[name |> to_string] do
{ name, value }
else
{ name, old }
end
end |> Map.put(:__struct__, module)
end
end