From 82815646e66d9379730d7a4fd269aa876b528720 Mon Sep 17 00:00:00 2001 From: Michael Uvarov Date: Tue, 4 Aug 2015 15:33:21 +0200 Subject: [PATCH] Add return_tail option --- src/jsx_config.erl | 5 +++++ src/jsx_config.hrl | 1 + src/jsx_decoder.erl | 36 ++++++++++++++++++++++++++++++++++++ 3 files changed, 42 insertions(+) diff --git a/src/jsx_config.erl b/src/jsx_config.erl index a7cf3de..92a958b 100644 --- a/src/jsx_config.erl +++ b/src/jsx_config.erl @@ -65,6 +65,8 @@ parse_config([dirty_strings|Rest], Config) -> parse_config(Rest, Config#config{dirty_strings=true}); parse_config([multi_term|Rest], Config) -> parse_config(Rest, Config#config{multi_term=true}); +parse_config([return_tail|Rest], Config) -> + parse_config(Rest, Config#config{return_tail=true}); %% retained for backwards compat, now does nothing however parse_config([repeat_keys|Rest], Config) -> parse_config(Rest, Config); @@ -155,6 +157,7 @@ valid_flags() -> unescaped_jsonp, dirty_strings, multi_term, + return_tail, repeat_keys, strict, stream, @@ -196,6 +199,7 @@ config_test_() -> unescaped_jsonp = true, dirty_strings = true, multi_term = true, + return_tail = true, strict_comments = true, strict_commas = true, strict_utf8 = true, @@ -209,6 +213,7 @@ config_test_() -> escaped_strings, unescaped_jsonp, multi_term, + return_tail, repeat_keys, strict, stream, diff --git a/src/jsx_config.hrl b/src/jsx_config.hrl index 9b5e025..be619c0 100644 --- a/src/jsx_config.hrl +++ b/src/jsx_config.hrl @@ -9,6 +9,7 @@ strict_single_quotes = false :: boolean(), strict_escapes = false :: boolean(), stream = false :: boolean(), + return_tail = false :: boolean(), uescape = false :: boolean(), unescaped_jsonp = false :: boolean(), error_handler = false :: false | jsx_config:handler(), diff --git a/src/jsx_decoder.erl b/src/jsx_decoder.erl index 0f03975..07dce72 100644 --- a/src/jsx_decoder.erl +++ b/src/jsx_decoder.erl @@ -1129,6 +1129,8 @@ done(<>, Handler, Stack, Config) -> comment(Rest, Handler, done, [multicomment|Stack], Config); done(<>, Handler, Stack, Config) -> incomplete(done, <>, Handler, Stack, Config); +done(Bin, {_Handler, State}, _Stack, #config{return_tail=true}) -> + {with_tail,State, Bin}; done(<<>>, {Handler, State}, [], Config=#config{stream=true}) -> incomplete(done, <<>>, {Handler, State}, [], Config); done(<<>>, {_Handler, State}, [], _Config) -> State; @@ -1938,4 +1940,38 @@ custom_incomplete_handler_test_() -> ]. +return_tail_test_() -> + [ + {"return_tail with tail", ?_assertEqual( + {with_tail,[{}],<<"3">>}, + jsx:decode(<<"{} 3">>, [return_tail]) + )}, + {"return_tail without tail", ?_assertEqual( + {with_tail,[{}],<<"">>}, + jsx:decode(<<"{}">>, [return_tail]) + )}, + {"return_tail with trimmed whitespace", ?_assertEqual( + {with_tail,[{}],<<"">>}, + jsx:decode(<<"{} ">>, [return_tail]) + )}, + {"return_tail and streaming", ?_assertEqual( + {with_tail,[{}],<<"3">>}, + begin + {incomplete, F} = jsx:decode(<<"{">>, [return_tail, stream]), + F(<<"} 3">>) + end + )}, + {"return_tail and streaming", ?_assertEqual( + {with_tail,[{}],<<"">>}, + begin + %% In case of infinite stream of objects a user does not know + %% when to call F(end_stream). + %% So, return_tail overwrites conservative stream end. + %% This means that we don't need to call end_stream explicitly. + {incomplete, F} = jsx:decode(<<"{">>, [return_tail, stream]), + F(<<"}">>) + end + )} + ]. + -endif.