Permalink
Browse files

Add a precoder option

Optionally have a function that can mutate the input EJSON structure
that will modify the input before its passed to the NIF code. Can be
used to encode custom types.
  • Loading branch information...
1 parent ad1d4c5 commit 6650215e1044d94c92cfaacf1d33c8bc0124450c @davisp committed Apr 11, 2012
Showing with 85 additions and 4 deletions.
  1. +12 −0 README.md
  2. +31 −3 src/jiffy.erl
  3. +35 −0 test/009-precode.t
  4. +7 −1 test/util.erl
View
@@ -48,6 +48,18 @@ Data Format
{[{foo, bar}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]}
{[{<<"foo">>, <<"bar">>}]} -> {"foo": "bar"} -> {[{<<"foo">>, <<"bar">>}]}
+
+Encoder Options
+---------------
+
+The encoder takes a few options that will affect the JSON output. Most of
+these are fairly simple.
+
+ * `uencode` - Encode all UTF-8 data as `\uXXXX` sequences.
+ * `pretty` - Pretty print the JSON with two-space indents.
+ * `{precoder, Function}` - Pass a function that will convert any unknown
+ Erlang terms into the appropriate format before encoding.
+
Improvements over EEP0018
-------------------------
View
@@ -24,7 +24,8 @@ encode(Data) ->
encode(Data, []).
-encode(Data, Options) ->
+encode(Data0, Options0) ->
+ {Data, Options} = maybe_precode(Data0, Options0),
case nif_encode(Data, Options) of
{error, _} = Error ->
throw(Error);
@@ -67,6 +68,33 @@ finish_decode_arr([V | Vals], Acc) ->
finish_decode_arr(Vals, [finish_decode(V) | Acc]).
+maybe_precode(Data, Opts) ->
+ case proplists:get_value(precoder, Opts) of
+ Pre when is_function(Pre, 1) ->
+ {precode(Data, Pre), lists:keydelete(precoder, 1, Opts)};
+ _ ->
+ {Data, Opts}
+ end.
+
+
+precode({Props}, Pre) ->
+ precode_obj(Props, [], Pre);
+precode(Vals, Pre) when is_list(Vals) ->
+ precode_arr(Vals, [], Pre);
+precode(Val, Pre) ->
+ Pre(Val).
+
+precode_obj([], Acc, _Pre) ->
+ {lists:reverse(Acc)};
+precode_obj([{K, V} | Rest], Acc, Pre) ->
+ precode_obj(Rest, [precode({K, precode(V, Pre)}, Pre) | Acc], Pre).
+
+precode_arr([], Acc, _Pre) ->
+ lists:reverse(Acc);
+precode_arr([Val | Rest], Acc, Pre) ->
+ precode_arr(Rest, [precode(Val, Pre) | Acc], Pre).
+
+
finish_encode([], Acc) ->
%% No reverse! The NIF returned us
%% the pieces in reverse order.
@@ -76,8 +104,8 @@ finish_encode([<<_/binary>>=B | Rest], Acc) ->
finish_encode([Val | Rest], Acc) when is_integer(Val) ->
Bin = list_to_binary(integer_to_list(Val)),
finish_encode(Rest, [Bin | Acc]);
-finish_encode(_, _) ->
- throw({error, invalid_ejson}).
+finish_encode(V, _) ->
+ throw({error, {invalid_ejson, V}}).
init() ->
View
@@ -0,0 +1,35 @@
+#! /usr/bin/env escript
+% This file is part of Jiffy released under the MIT license.
+% See the LICENSE file for more information.
+
+main([]) ->
+ code:add_pathz("ebin"),
+ code:add_pathz("test"),
+
+ etap:plan(3),
+ util:test_enc_ok(good(), [{precoder, fun(V) -> precoder(V) end}]),
+ %util:test_errors(errors()),
+ etap:end_tests().
+
+precoder({Y, M, D}) when is_integer(Y); is_integer(M); is_integer(D) ->
+ Fmt = "~4.10.0B-~2.10.0B-~2.10.0B",
+ list_to_binary(io_lib:format(Fmt, [Y, M, D]));
+precoder(O) ->
+ O.
+
+good() ->
+ [
+ {{2012, 4, 11}, <<"\"2012-04-11\"">>},
+ {[{2012, 4, 11}], <<"[\"2012-04-11\"]">>},
+ {
+ {[{<<"foo">>, {2012, 4, 11}}]},
+ <<"{\"foo\":\"2012-04-11\"}">>
+ }
+ ].
+
+errors() ->
+ [
+ {foo},
+ {[{<<"foo">>, {bang}}]},
+ [{bong}]
+ ].
View
@@ -1,5 +1,5 @@
-module(util).
--export([test_good/1, test_good/2, test_errors/1]).
+-compile(export_all).
test_good(Cases) ->
test_good(Cases, []).
@@ -10,6 +10,9 @@ test_good(Cases, Options) ->
test_errors(Cases) ->
lists:foreach(fun(Case) -> check_error(Case) end, Cases).
+test_enc_ok(Cases, Options) ->
+ lists:foreach(fun(Case) -> check_enc_ok(Case, Options) end, Cases).
+
ok_dec(J, _E) ->
lists:flatten(io_lib:format("Decoded ~p.", [J])).
@@ -42,3 +45,6 @@ check_error(J) ->
error_mesg(J)
).
+check_enc_ok({E, J}, Options) ->
+ etap:is(do_encode(E, Options), J, ok_enc(E, J)).
+

0 comments on commit 6650215

Please sign in to comment.