Skip to content

Commit

Permalink
add mochijson2:decode/2 with [{format, eep18 | proplist | struct}] op…
Browse files Browse the repository at this point in the history
…tion
  • Loading branch information
etrepum committed Aug 30, 2011
1 parent cfc3af6 commit 497f1fc
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 10 deletions.
60 changes: 51 additions & 9 deletions src/mochijson2.erl
Expand Up @@ -40,9 +40,9 @@
-module(mochijson2). -module(mochijson2).
-author('bob@mochimedia.com'). -author('bob@mochimedia.com').
-export([encoder/1, encode/1]). -export([encoder/1, encode/1]).
-export([decoder/1, decode/1]). -export([decoder/1, decode/1, decode/2]).


% This is a macro to placate syntax highlighters.. %% This is a macro to placate syntax highlighters..
-define(Q, $\"). -define(Q, $\").
-define(ADV_COL(S, N), S#decoder{offset=N+S#decoder.offset, -define(ADV_COL(S, N), S#decoder{offset=N+S#decoder.offset,
column=N+S#decoder.column}). column=N+S#decoder.column}).
Expand Down Expand Up @@ -70,9 +70,10 @@
%% @type json_number() = integer() | float() %% @type json_number() = integer() | float()
%% @type json_array() = [json_term()] %% @type json_array() = [json_term()]
%% @type json_object() = {struct, [{json_string(), json_term()}]} %% @type json_object() = {struct, [{json_string(), json_term()}]}
%% @type json_eep18_object() = {[{json_string(), json_term()}]}
%% @type json_iolist() = {json, iolist()} %% @type json_iolist() = {json, iolist()}
%% @type json_term() = json_string() | json_number() | json_array() | %% @type json_term() = json_string() | json_number() | json_array() |
%% json_object() | json_iolist() %% json_object() | json_eep18_object() | json_iolist()


-record(encoder, {handler=null, -record(encoder, {handler=null,
utf8=false}). utf8=false}).
Expand Down Expand Up @@ -102,6 +103,14 @@ decoder(Options) ->
State = parse_decoder_options(Options, #decoder{}), State = parse_decoder_options(Options, #decoder{}),
fun (O) -> json_decode(O, State) end. fun (O) -> json_decode(O, State) end.


%% @spec decode(iolist(), [{format, proplist | eep18 | struct}]) -> json_term()
%% @doc Decode the given iolist to Erlang terms using the given object format
%% for decoding, where proplist returns JSON objects as [{binary(), json_term()}]
%% proplists, eep18 returns JSON objects as {[binary(), json_term()]}, and struct
%% returns them as-is.
decode(S, Options) ->
json_decode(S, parse_decoder_options(Options, #decoder{})).

%% @spec decode(iolist()) -> json_term() %% @spec decode(iolist()) -> json_term()
%% @doc Decode the given iolist to Erlang terms. %% @doc Decode the given iolist to Erlang terms.
decode(S) -> decode(S) ->
Expand All @@ -119,7 +128,10 @@ parse_encoder_options([{utf8, Switch} | Rest], State) ->
parse_decoder_options([], State) -> parse_decoder_options([], State) ->
State; State;
parse_decoder_options([{object_hook, Hook} | Rest], State) -> parse_decoder_options([{object_hook, Hook} | Rest], State) ->
parse_decoder_options(Rest, State#decoder{object_hook=Hook}). parse_decoder_options(Rest, State#decoder{object_hook=Hook});
parse_decoder_options([{format, Format} | Rest], State)
when Format =:= struct orelse Format =:= eep18 orelse Format =:= proplist ->
parse_decoder_options(Rest, State#decoder{object_hook=Format}).


json_encode(true, _State) -> json_encode(true, _State) ->
<<"true">>; <<"true">>;
Expand All @@ -139,6 +151,10 @@ json_encode([{K, _}|_] = Props, State) when (K =/= struct andalso
json_encode_proplist(Props, State); json_encode_proplist(Props, State);
json_encode({struct, Props}, State) when is_list(Props) -> json_encode({struct, Props}, State) when is_list(Props) ->
json_encode_proplist(Props, State); json_encode_proplist(Props, State);
json_encode({Props}, State) when is_list(Props) ->
json_encode_proplist(Props, State);
json_encode({}, State) ->
json_encode_proplist([], State);
json_encode(Array, State) when is_list(Array) -> json_encode(Array, State) when is_list(Array) ->
json_encode_array(Array, State); json_encode_array(Array, State);
json_encode({array, Array}, State) when is_list(Array) -> json_encode({array, Array}, State) when is_list(Array) ->
Expand Down Expand Up @@ -318,8 +334,12 @@ decode1(B, S=#decoder{state=null}) ->
decode_object(B, S1) decode_object(B, S1)
end. end.


make_object(V, #decoder{object_hook=null}) -> make_object(V, #decoder{object_hook=N}) when N =:= null orelse N =:= struct ->
V; V;
make_object({struct, P}, #decoder{object_hook=eep18}) ->
{P};
make_object({struct, P}, #decoder{object_hook=proplist}) ->
P;
make_object(V, #decoder{object_hook=Hook}) -> make_object(V, #decoder{object_hook=Hook}) ->
Hook(V). Hook(V).


Expand Down Expand Up @@ -838,12 +858,34 @@ float_test() ->


handler_test() -> handler_test() ->
?assertEqual( ?assertEqual(
{'EXIT',{json_encode,{bad_term,{}}}}, {'EXIT',{json_encode,{bad_term,{x,y}}}},
catch encode({})), catch encode({x,y})),
F = fun ({}) -> [] end, F = fun ({x,y}) -> [] end,
?assertEqual( ?assertEqual(
<<"[]">>, <<"[]">>,
iolist_to_binary((encoder([{handler, F}]))({}))), iolist_to_binary((encoder([{handler, F}]))({x, y}))),
ok. ok.


encode_empty_test_() ->
[{A, ?_assertEqual(<<"{}">>, iolist_to_binary(encode(B)))}
|| {A, B} <- [{"eep18 {}", {}},
{"eep18 {[]}", {[]}},
{"{struct, []}", {struct, []}}]].

encode_test_() ->
P = [{<<"k">>, <<"v">>}],
JSON = iolist_to_binary(encode({struct, P})),
[{atom_to_list(F),
?_assertEqual(JSON, iolist_to_binary(encode(decode(JSON, [{format, F}]))))}
|| F <- [struct, eep18, proplist]].

format_test_() ->
P = [{<<"k">>, <<"v">>}],
JSON = iolist_to_binary(encode({struct, P})),
[{atom_to_list(F),
?_assertEqual(A, decode(JSON, [{format, F}]))}
|| {F, A} <- [{struct, {struct, P}},
{eep18, {P}},
{proplist, P}]].

-endif. -endif.
2 changes: 1 addition & 1 deletion src/mochiweb.app.src
@@ -1,7 +1,7 @@
%% This is generated from src/mochiweb.app.src %% This is generated from src/mochiweb.app.src
{application, mochiweb, {application, mochiweb,
[{description, "MochiMedia Web Server"}, [{description, "MochiMedia Web Server"},
{vsn, "2.0.0"}, {vsn, "2.1.0"},
{modules, []}, {modules, []},
{registered, []}, {registered, []},
{env, []}, {env, []},
Expand Down

0 comments on commit 497f1fc

Please sign in to comment.