Created
April 9, 2015 14:22
-
-
Save jschoch/b9c4f9c08fa5be127c67 to your computer and use it in GitHub Desktop.
struct encoding and decoding nested structs with poison
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule MyTime do | |
defstruct stamp: {0,0,0} | |
defimpl Poison.Encoder, for: MyTime do | |
def encode(%MyTime{} = t,options) do | |
list = Tuple.to_list(t.stamp) | |
Poison.Encoder.Map.encode(%MyTime{stamp: list},options) | |
end | |
end | |
defimpl Poison.Decoder, for: MyTime do | |
def decode(s,options) do | |
t = List.to_tuple(s.stamp) | |
%MyTime{stamp: t} | |
end | |
end | |
end | |
defmodule Y do | |
#require Poison.Decoder.MyTime | |
defmacro __using__(_) do | |
quote do | |
require Logger | |
defimpl Poison.Encoder, for: __MODULE__ do | |
def encode(y,options) do | |
Poison.Encoder.Map.encode(y,options) | |
end | |
end | |
defimpl Poison.Decoder, for: __MODULE__ do | |
def decode(map,options) when is_map(map) do | |
map = Enum.reduce(Map.keys(map),map,fn(key,map) -> | |
if (is_map(map[key])) do | |
case Map.has_key?(map[key],:__struct__) do | |
true -> | |
mod_name = map[key][:__struct__] | |
mod_atom = String.to_atom(mod_name) | |
mod_struct = mod_atom.__struct__.__struct__ | |
["Elixir"|short_name] = String.split(mod_name,".") | |
decoder_name = :"Elixir.Poison.Decoder.#{short_name}" | |
case Code.ensure_loaded(decoder_name) do | |
{:module,_} -> | |
decoded = decoder_name.decode(map[key],as: mod_struct) | |
map = Map.put(map,key,decoded) | |
{:error,reason} -> | |
Loggger.warn "couldn't decode #{decoder_name} #{inspect reason}" | |
end | |
false -> | |
Logger.warn "didn't find a :__struct__ for #{key}" | |
end | |
end | |
map | |
end) | |
end | |
end | |
#defoverridable [__struct__: 0] | |
end | |
end | |
end | |
defmodule X do | |
#require MyTime | |
@derive Access | |
defstruct name: :foo, ts: %MyTime{stamp: {2,2,2}}, m: nil, z: nil | |
use Y | |
end | |
defmodule S do | |
defstruct name: :foo | |
use Y | |
end | |
defmodule Z do | |
defstruct name: :baz | |
end |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
defmodule UsingMixinsTest do | |
use ExUnit.Case | |
test "the truth" do | |
item = %MyTime{stamp: {1,1,1}} | |
s = Poison.encode!(item) | |
IO.puts "s: #{inspect s}" | |
de = Poison.decode!(s,as: MyTime) | |
IO.puts "de: #{inspect de}" | |
assert item.stamp == de.stamp | |
end | |
test "embed works" do | |
s = Poison.encode!(%X{name: :bar,m: %{},z: %Z{}}) | |
IO.puts "X: " <> inspect s | |
x = Poison.decode!(s, [keys: :atoms,as: X]) | |
IO.puts "X: " <> inspect x | |
assert %MyTime{} = x.ts | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment