From 6dacf64620d369f7997edc2d0fc27c71911eb5a3 Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Tue, 29 Nov 2011 19:39:01 -0800 Subject: [PATCH] refactors out extraction of parser opts, generalizes use of specific parsers by processors --- include/jsx_opts.hrl | 3 ++- src/gen_json.erl | 12 ++++++++++-- src/jsx.erl | 37 ++++++++++++++----------------------- src/jsx_to_json.erl | 25 ++++++------------------- src/jsx_to_term.erl | 20 +++----------------- src/jsx_utils.erl | 20 +++++++++++++++++++- src/jsx_verify.erl | 20 +++----------------- 7 files changed, 57 insertions(+), 80 deletions(-) diff --git a/include/jsx_opts.hrl b/include/jsx_opts.hrl index a572170..d49254b 100644 --- a/include/jsx_opts.hrl +++ b/include/jsx_opts.hrl @@ -1,5 +1,6 @@ -record(opts, { loose_unicode = false, escape_forward_slash = false, - explicit_end = false + explicit_end = false, + parser = auto }). \ No newline at end of file diff --git a/src/gen_json.erl b/src/gen_json.erl index f860b3a..e508f09 100644 --- a/src/gen_json.erl +++ b/src/gen_json.erl @@ -33,6 +33,14 @@ behaviour_info(_) -> undefined. parser(Mod, Args) -> parser(Mod, Args, []). -parser(Mod, Args, Opts) -> fun(Input) when is_list(Input) -> (jsx:encoder(Mod, Args, Opts))(Input) - ; (Input) when is_binary(Input) -> (jsx:decoder(Mod, Args, Opts))(Input) +parser(Mod, Args, Opts) when is_atom(Mod), is_list(Opts) -> + case proplists:get_value(parser, Opts, auto) of + auto -> + fun(Input) when is_list(Input) -> (jsx:encoder(Mod, Args, Opts))(Input) + ; (Input) when is_binary(Input) -> (jsx:decoder(Mod, Args, Opts))(Input) + end + ; encoder -> + fun(Input) -> (jsx:encoder(Mod, Args, Opts))(Input) end + ; decoder -> + fun(Input) -> (jsx:decoder(Mod, Args, Opts))(Input) end end. \ No newline at end of file diff --git a/src/jsx.erl b/src/jsx.erl index 63bcfbf..30adc3c 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -23,7 +23,7 @@ -module(jsx). --export([encoder/0, encoder/1]). +-export([encoder/2, encoder/3]). -export([decoder/2, decoder/3]). %% shims for jsx_to_json, jsx_to_term, jsx_verify -export([to_json/1, to_json/2]). @@ -56,7 +56,10 @@ -include("../include/jsx_opts.hrl"). -type opts() :: [opt()]. --type opt() :: loose_unicode | escape_forward_slashes | explicit_end. +-type opt() :: loose_unicode + | escape_forward_slashes + | explicit_end + | {parser, auto} | {parser, encoder} | {parser, decoder} | {parser, function()}. @@ -65,20 +68,22 @@ -spec decoder(Mod::module(), Args::any()) -> decoder(). -spec decoder(Mod::module(), Args::any(), OptsList::opts()) -> decoder(). -decoder(Mod, Args) -> decoder(Mod, Args, []). +decoder(Mod, Args) when is_atom(Mod) -> decoder(Mod, Args, []). -decoder(Mod, Args, OptsList) when is_list(OptsList) -> jsx_decoder:decoder(Mod, Args, OptsList). +decoder(Mod, Args, OptsList) when is_atom(Mod), is_list(OptsList) -> + jsx_decoder:decoder(Mod, Args, OptsList). -type encoder() :: fun((list()) -> {ok, events()} | {incomplete, decoder()}). --spec encoder() -> encoder(). --spec encoder(OptsList::opts()) -> encoder(). +-spec encoder(Mod::module(), Args::any()) -> encoder(). +-spec encoder(Mod::module(), Args::any(), OptsList::opts()) -> encoder(). -encoder() -> encoder([]). +encoder(Mod, Args) when is_atom(Mod) -> encoder(Mod, Args, []). -encoder(OptsList) when is_list(OptsList) -> jsx_encoder:encoder(OptsList). +encoder(Mod, Args, OptsList) when is_atom(Mod), is_list(OptsList) -> + jsx_encoder:encoder(Mod, Args, OptsList). @@ -120,21 +125,7 @@ encoder_decoder_equiv_test_() -> {"encoder/decoder equivalency", ?_assert((jsx:decoder(?MODULE, []))( <<"[\"a\", 17, 3.14, true, {\"k\":false}, []]">> - ) =:= (jsx:encoder())( - [start_array, - {string, <<"a">>}, - {integer, 17}, - {float, 3.14}, - {literal, true}, - start_object, - {key, <<"k">>}, - {literal, false}, - end_object, - start_array, - end_array, - end_array, - end_json] - ) + ) =:= (jsx:encoder(?MODULE, []))([<<"a">>, 17, 3.14, true, [{<<"k">>, false}], []]) ) } ]. diff --git a/src/jsx_to_json.erl b/src/jsx_to_json.erl index b76bbb5..3924bb6 100644 --- a/src/jsx_to_json.erl +++ b/src/jsx_to_json.erl @@ -40,13 +40,10 @@ to_json(Source, Opts) when (is_binary(Source) andalso is_list(Opts)) orelse (is_list(Source) andalso is_list(Opts)) -> - (gen_json:parser(?MODULE, Opts, extract_opts(Opts)))(Source). + (gen_json:parser(?MODULE, Opts, jsx_utils:extract_opts(Opts)))(Source). -init(Opts) -> {start, [], parse_opts(Opts)}. - - parse_opts(Opts) -> parse_opts(Opts, #opts{}). parse_opts([{space, Val}|Rest], Opts) when is_integer(Val), Val > 0 -> @@ -63,21 +60,6 @@ parse_opts([], Opts) -> Opts. -extract_opts(Opts) -> - extract_parser_opts(Opts, []). - -extract_parser_opts([], Acc) -> Acc; -extract_parser_opts([{K,V}|Rest], Acc) -> - case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of - true -> extract_parser_opts(Rest, [{K,V}] ++ Acc) - ; false -> extract_parser_opts(Rest, Acc) - end; -extract_parser_opts([K|Rest], Acc) -> - case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of - true -> extract_parser_opts(Rest, [K] ++ Acc) - ; false -> extract_parser_opts(Rest, Acc) - end. - -define(start_object, <<"{">>). -define(start_array, <<"[">>). @@ -90,6 +72,11 @@ extract_parser_opts([K|Rest], Acc) -> -define(newline, <<"\n">>). + +init(Opts) -> {start, [], parse_opts(Opts)}. + + + handle_event(Event, {start, Acc, Opts}) -> case Event of {Type, Value} -> {[], [Acc, encode(Type, Value)], Opts} diff --git a/src/jsx_to_term.erl b/src/jsx_to_term.erl index 5c4cb2f..c43df50 100644 --- a/src/jsx_to_term.erl +++ b/src/jsx_to_term.erl @@ -38,13 +38,10 @@ to_term(Source, Opts) when (is_binary(Source) andalso is_list(Opts)) orelse (is_list(Source) andalso is_list(Opts)) -> - (gen_json:parser(?MODULE, Opts, extract_opts(Opts)))(Source). + (gen_json:parser(?MODULE, Opts, jsx_utils:extract_opts(Opts)))(Source). -init(Opts) -> {[[]], parse_opts(Opts)}. - - parse_opts(Opts) -> parse_opts(Opts, #opts{}). parse_opts([{labels, Val}|Rest], Opts) @@ -58,20 +55,9 @@ parse_opts([], Opts) -> Opts. -extract_opts(Opts) -> - extract_parser_opts(Opts, []). -extract_parser_opts([], Acc) -> Acc; -extract_parser_opts([{K,V}|Rest], Acc) -> - case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of - true -> extract_parser_opts(Rest, [{K,V}] ++ Acc) - ; false -> extract_parser_opts(Rest, Acc) - end; -extract_parser_opts([K|Rest], Acc) -> - case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of - true -> extract_parser_opts(Rest, [K] ++ Acc) - ; false -> extract_parser_opts(Rest, Acc) - end. +init(Opts) -> {[[]], parse_opts(Opts)}. + handle_event(end_json, {[[Terms]], _Opts}) -> Terms; diff --git a/src/jsx_utils.erl b/src/jsx_utils.erl index a8160f8..842ba8a 100644 --- a/src/jsx_utils.erl +++ b/src/jsx_utils.erl @@ -23,7 +23,7 @@ -module(jsx_utils). --export([parse_opts/1, nice_decimal/1, json_escape/2]). +-export([parse_opts/1, extract_opts/1, nice_decimal/1, json_escape/2]). -include("../include/jsx_opts.hrl"). @@ -41,10 +41,28 @@ parse_opts([escape_forward_slash|Rest], Opts) -> parse_opts(Rest, Opts#opts{escape_forward_slash=true}); parse_opts([explicit_end|Rest], Opts) -> parse_opts(Rest, Opts#opts{explicit_end=true}); +parse_opts([{parser, Mode}|Rest], Opts) -> + parse_opts(Rest, Opts#opts{parser=Mode}); parse_opts(_, _) -> {error, badarg}. +extract_opts(Opts) -> + extract_parser_opts(Opts, []). + +extract_parser_opts([], Acc) -> Acc; +extract_parser_opts([{K,V}|Rest], Acc) -> + case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end, parser]) of + true -> extract_parser_opts(Rest, [{K,V}] ++ Acc) + ; false -> extract_parser_opts(Rest, Acc) + end; +extract_parser_opts([K|Rest], Acc) -> + case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of + true -> extract_parser_opts(Rest, [K] ++ Acc) + ; false -> extract_parser_opts(Rest, Acc) + end. + + %% conversion of floats to 'nice' decimal output. erlang's float implementation %% is almost but not quite ieee 754. it converts negative zero to plain zero %% silently, and throws exceptions for any operations that would produce NaN diff --git a/src/jsx_verify.erl b/src/jsx_verify.erl index 6b311c5..c8f66bb 100644 --- a/src/jsx_verify.erl +++ b/src/jsx_verify.erl @@ -38,7 +38,7 @@ is_json(Source, Opts) when (is_binary(Source) andalso is_list(Opts)) orelse (is_list(Source) andalso is_list(Opts)) -> - try case (gen_json:parser(?MODULE, Opts, extract_opts(Opts)))(Source) of + try case (gen_json:parser(?MODULE, Opts, jsx_utils:extract_opts(Opts)))(Source) of {incomplete, _} -> false ; true -> true end @@ -47,9 +47,6 @@ is_json(Source, Opts) when (is_binary(Source) andalso is_list(Opts)) -init(Opts) -> {parse_opts(Opts), []}. - - parse_opts(Opts) -> parse_opts(Opts, #opts{}). parse_opts([{repeated_keys, Val}|Rest], Opts) when Val == true; Val == false -> @@ -62,20 +59,9 @@ parse_opts([], Opts) -> Opts. -extract_opts(Opts) -> - extract_parser_opts(Opts, []). -extract_parser_opts([], Acc) -> Acc; -extract_parser_opts([{K,V}|Rest], Acc) -> - case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of - true -> extract_parser_opts(Rest, [{K,V}] ++ Acc) - ; false -> extract_parser_opts(Rest, Acc) - end; -extract_parser_opts([K|Rest], Acc) -> - case lists:member(K, [loose_unicode, escape_forward_slash, explicit_end]) of - true -> extract_parser_opts(Rest, [K] ++ Acc) - ; false -> extract_parser_opts(Rest, Acc) - end. +init(Opts) -> {parse_opts(Opts), []}. + handle_event(end_json, _) -> true;