From cb1f26a8b3ca7efd4c79437b803cd8021c57d204 Mon Sep 17 00:00:00 2001 From: isaac-rstor Date: Wed, 14 Nov 2018 11:29:58 -0800 Subject: [PATCH] allows for encoding keyword lists (#62) added a method to do encodings directly through keyword lists --- lib/encode.ex | 49 +++++++++++++++++++++++++++++--------------- test/encode_test.exs | 19 +++++++++++++++++ 2 files changed, 52 insertions(+), 16 deletions(-) diff --git a/lib/encode.ex b/lib/encode.ex index 23848b6..7a7f1ee 100644 --- a/lib/encode.ex +++ b/lib/encode.ex @@ -150,19 +150,30 @@ defmodule Jason.Encode do | list_loop(tail, escape, encode_map)] end + @spec keyword(keyword, opts) :: iodata + def keyword(list, {escape, encode_map}) do + encode_map.(list, escape, encode_map) + end + @spec map(map, opts) :: iodata def map(value, {escape, encode_map}) do encode_map.(value, escape, encode_map) end + defp map_naive([], _escape, _encode_map) do + "{}" + end + + defp map_naive([{key, value} | tail], escape, encode_map) do + ["{\"", key(key, escape), "\":", + value(value, escape, encode_map) + | map_naive_loop(tail, escape, encode_map)] + end + defp map_naive(value, escape, encode_map) do - case Map.to_list(value) do - [] -> "{}" - [{key, value} | tail] -> - ["{\"", key(key, escape), "\":", - value(value, escape, encode_map) - | map_naive_loop(tail, escape, encode_map)] - end + value + |> Map.to_list + |> map_naive(escape, encode_map) end defp map_naive_loop([], _escape, _encode_map) do @@ -175,16 +186,22 @@ defmodule Jason.Encode do | map_naive_loop(tail, escape, encode_map)] end + defp map_strict([], _escape, _encode_map) do + "{}" + end + + defp map_strict([{key, value} | tail], escape, encode_map) do + key = IO.iodata_to_binary(key(key, escape)) + visited = %{key => []} + ["{\"", key, "\":", + value(value, escape, encode_map) + | map_strict_loop(tail, escape, encode_map, visited)] + end + defp map_strict(value, escape, encode_map) do - case Map.to_list(value) do - [] -> "{}" - [{key, value} | tail] -> - key = IO.iodata_to_binary(key(key, escape)) - visited = %{key => []} - ["{\"", key, "\":", - value(value, escape, encode_map) - | map_strict_loop(tail, escape, encode_map, visited)] - end + value + |> Map.to_list + |> map_strict(escape, encode_map) end defp map_strict_loop([], _encode_map, _escape, _visited) do diff --git a/test/encode_test.exs b/test/encode_test.exs index 805085e..e4a0a74 100644 --- a/test/encode_test.exs +++ b/test/encode_test.exs @@ -133,6 +133,24 @@ defmodule Jason.EncoderTest do assert to_json(derived_using_except) == ~s({"size":10}) end + defmodule KeywordTester do + defstruct [:baz, :foo, :quux] + end + + defimpl Jason.Encoder, for: [KeywordTester] do + def encode(struct, opts) do + struct + |> Map.from_struct + |> Enum.map(&(&1)) + |> Jason.Encode.keyword(opts) + end + end + + test "using keyword list encoding" do + t = %KeywordTester{baz: :bar, foo: "bag", quux: 42} + assert to_json(t) == ~s({"baz":"bar","foo":"bag","quux":42}) + end + test "EncodeError" do assert_raise Protocol.UndefinedError, fn -> to_json(self()) @@ -162,4 +180,5 @@ defmodule Jason.EncoderTest do defp to_json(value, opts \\ []) do Jason.encode!(value, opts) end + end