remove stream mode from jsx_terms and streamline options handling in jsx_terms to simplify migration to new api

This commit is contained in:
alisdair sullivan 2011-08-10 23:31:14 -07:00
parent 3186223fd1
commit 01a8154ac4
2 changed files with 69 additions and 49 deletions

View file

@ -125,7 +125,6 @@
-type decoder_opts() :: [decoder_opt()]. -type decoder_opts() :: [decoder_opt()].
-type decoder_opt() :: {strict, true | false} -type decoder_opt() :: {strict, true | false}
| {stream, true | false}
| {encoding, supported_utf()}. | {encoding, supported_utf()}.

View file

@ -28,12 +28,19 @@
-include("jsx_common.hrl"). -include("jsx_common.hrl").
-spec json_to_term(JSON::binary(), Opts::decoder_opts()) -> -record(decoder_opts, {
strict = false,
encoding = auto
}).
-spec json_to_term(JSON::binary(), OptsList::decoder_opts()) ->
jsx_term() | {jsx, incomplete, fun()}. jsx_term() | {jsx, incomplete, fun()}.
json_to_term(JSON, Opts) -> json_to_term(JSON, OptsList) ->
P = jsx:decoder([iterate] ++ extract_parser_opts(Opts)), Opts = parse_opts(OptsList, #decoder_opts{}),
case proplists:get_value(strict, Opts, false) of P = jsx:decoder([iterate, {encoding, Opts#decoder_opts.encoding}]),
case Opts#decoder_opts.strict of
true -> collect_strict(P(JSON), [[]], Opts) true -> collect_strict(P(JSON), [[]], Opts)
; false -> collect(P(JSON), [[]], Opts) ; false -> collect(P(JSON), [[]], Opts)
end. end.
@ -42,32 +49,72 @@ json_to_term(JSON, Opts) ->
%% the jsx formatter (pretty printer) can do most of the heavy lifting in %% the jsx formatter (pretty printer) can do most of the heavy lifting in
%% converting erlang terms to json strings %% converting erlang terms to json strings
-spec term_to_json(JSON::jsx_term(), Opts::encoder_opts()) -> -record(encoder_opts, {
strict = false,
encoding = auto,
formatter_opts = []
}).
-spec term_to_json(JSON::jsx_term(), OptsList::encoder_opts()) ->
binary() | {jsx, incomplete, fun()}. binary() | {jsx, incomplete, fun()}.
term_to_json(List, Opts) -> term_to_json(List, OptsList) ->
case proplists:get_value(strict, Opts, false) of Opts = parse_opts(OptsList, #encoder_opts{}),
case Opts#encoder_opts.strict of
true when is_list(List) -> continue true when is_list(List) -> continue
; true -> erlang:error(badarg) ; true -> erlang:error(badarg)
; false -> continue ; false -> continue
end, end,
Encoding = proplists:get_value(encoding, Opts, utf8),
FOpts = [{output_encoding, Encoding}] ++ Opts,
case term_to_events(List) of case term_to_events(List) of
L when is_tuple(L) -> jsx:format(L, FOpts) L when is_tuple(L) ->
; L when is_list(L) -> jsx:format(lists:reverse(L), FOpts) jsx:format(L, Opts#encoder_opts.formatter_opts)
; L when is_list(L) ->
jsx:format(lists:reverse(L), Opts#encoder_opts.formatter_opts)
end. end.
extract_parser_opts(Opts) -> parse_opts([{strict, Val}|Rest], Opts = #decoder_opts{})
extract_parser_opts(Opts, []). when Val =:= true; Val =:= false ->
parse_opts(Rest, Opts#decoder_opts{strict = Val});
extract_parser_opts([], Acc) -> Acc; parse_opts([strict|Rest], Opts = #decoder_opts{}) ->
extract_parser_opts([{K,V}|Rest], Acc) -> parse_opts(Rest, Opts#decoder_opts{strict = true});
case lists:member(K, [encoding]) of parse_opts([{strict, Val}|Rest], Opts = #encoder_opts{})
true -> [{K,V}] ++ Acc when Val =:= true; Val =:= false ->
; false -> extract_parser_opts(Rest, Acc) parse_opts(Rest, Opts#encoder_opts{strict = Val});
end. parse_opts([strict|Rest], Opts = #encoder_opts{}) ->
parse_opts(Rest, Opts#encoder_opts{strict = true});
parse_opts([{encoding, Val}|Rest], Opts = #decoder_opts{})
when Val =:= auto; Val =:= utf8;
Val =:= utf16; Val =:= {utf16,little};
Val =:= utf32; Val =:= {utf32,little} ->
parse_opts(Rest, Opts#decoder_opts{encoding = Val});
parse_opts([encoding|Rest], Opts = #decoder_opts{}) ->
parse_opts(Rest, Opts#decoder_opts{encoding = auto});
parse_opts([{encoding, Val}|Rest], Opts = #encoder_opts{})
when Val =:= auto; Val =:= utf8;
Val =:= utf16; Val =:= {utf16,little};
Val =:= utf32; Val =:= {utf32,little} ->
parse_opts(Rest, Opts#encoder_opts{encoding = Val});
parse_opts([encoding|Rest], Opts = #encoder_opts{}) ->
parse_opts(Rest, Opts#encoder_opts{encoding = auto});
parse_opts([{indent, Val}|Rest], Opts = #encoder_opts{formatter_opts = F})
when is_integer(Val) ->
parse_opts(Rest, Opts#encoder_opts{formatter_opts = [{indent, Val}] ++ F});
parse_opts([indent|Rest], Opts = #encoder_opts{formatter_opts = F}) ->
parse_opts(Rest, Opts#encoder_opts{formatter_opts = [{indent, 1}] ++ F});
parse_opts([{space, Val}|Rest], Opts = #encoder_opts{formatter_opts = F})
when is_integer(Val) ->
parse_opts(Rest, Opts#encoder_opts{formatter_opts = [{space, Val}] ++ F});
parse_opts([space|Rest], Opts = #encoder_opts{formatter_opts = F}) ->
parse_opts(Rest, Opts#encoder_opts{formatter_opts = [{space, 1}] ++ F});
parse_opts([{output_encoding, Val}|Rest], Opts = #encoder_opts{formatter_opts = F})
when Val =:= utf8;
Val =:= utf16; Val =:= {utf16,little};
Val =:= utf32; Val =:= {utf32,little} ->
parse_opts(Rest, Opts#encoder_opts{formatter_opts = [{output_encoding, Val}] ++ F});
parse_opts([], Opts) ->
Opts.
%% ensure the first jsx event we get is start_object or start_array when running %% ensure the first jsx event we get is start_object or start_array when running
@ -75,13 +122,6 @@ extract_parser_opts([{K,V}|Rest], Acc) ->
collect_strict({jsx, Start, Next}, Acc, Opts) collect_strict({jsx, Start, Next}, Acc, Opts)
when Start =:= start_object; Start =:= start_array -> when Start =:= start_object; Start =:= start_array ->
collect(Next(), [[]|Acc], Opts); collect(Next(), [[]|Acc], Opts);
collect_strict({jsx, incomplete, More}, Acc, Opts) ->
case proplists:get_value(stream, Opts, false) of
true -> {jsx, incomplete, fun(JSON) ->
collect_strict(More(JSON), Acc, Opts)
end}
; false -> erlang:error(badarg)
end;
collect_strict(_, _, _) -> erlang:error(badarg). collect_strict(_, _, _) -> erlang:error(badarg).
@ -116,17 +156,10 @@ collect({jsx, {key, _} = PreKey, Next}, Acc, Opts) ->
collect(Next(), [Key] ++ Acc, Opts); collect(Next(), [Key] ++ Acc, Opts);
%% if our returned event is {jsx, incomplete, ...} try to force end and return %% if our returned event is {jsx, incomplete, ...} try to force end and return
%% the Event if one is returned %% the Event if one is returned
collect({jsx, incomplete, More}, Acc, Opts) -> collect({jsx, incomplete, More}, _Acc, Opts) ->
case More(end_stream) of case More(end_stream) of
{jsx, Event, _Next} -> event(Event, Opts) {jsx, Event, _Next} -> event(Event, Opts)
; _ -> ; _ -> erlang:error(badarg)
case proplists:get_value(stream, Opts, false) of
true ->
{jsx, incomplete,
fun(JSON) -> collect(More(JSON), Acc, Opts) end
}
; false -> erlang:error(badarg)
end
end; end;
%% check acc to see if we're inside an object or an array. because inside an %% check acc to see if we're inside an object or an array. because inside an
%% object context the events that fall this far are always preceded by a key %% object context the events that fall this far are always preceded by a key
@ -437,16 +470,4 @@ escape_test_() ->
} }
]. ].
stream_test_() ->
[
{"streaming mode",
?_assert(begin
{jsx, incomplete, F} = json_to_term(<<"{">>,
[{stream, true}]
),
F(<<"}">>)
end =:= [{}])
}
].
-endif. -endif.