use end_json to end streaming when in streaming mode in addition

to `end_stream`
This commit is contained in:
alisdair sullivan 2014-08-13 23:00:35 -07:00
parent b14714aef9
commit c25bb49902
5 changed files with 38 additions and 7 deletions

View file

@ -1,3 +1,7 @@
v2.1
* force the end of streams with `end_json` in addition to `end_stream`
v2.0.4 v2.0.4
* more typespec adjustments * more typespec adjustments

View file

@ -264,16 +264,16 @@ memory
however, it is important to recognize that **jsx** is conservative by default. **jsx** will however, it is important to recognize that **jsx** is conservative by default. **jsx** will
not consider the parsing complete even when input is exhausted and the json text is not consider the parsing complete even when input is exhausted and the json text is
unambiguously incomplete. to end parsing call the `incomplete` function with the unambiguously incomplete. to end parsing call the `incomplete` function with the
argument `end_stream` like: argument `end_stream` (or `end_json`) like:
```erlang ```erlang
1> {incomplete, F} = jsx:decode(<<"[">>, [stream]). 1> {incomplete, F} = jsx:decode(<<"[">>, [stream]).
{incomplete,#Fun<jsx_decoder.1.122947756>} {incomplete,#Fun<jsx_decoder.1.122947756>}
2> F(end_stream). 2> F(end_stream). % can also be `F(end_json)`
** exception error: bad argument ** exception error: bad argument
3> {incomplete, G} = F(<<"]">>). 3> {incomplete, G} = F(<<"]">>).
{incomplete,#Fun<jsx_decoder.1.122947756>} {incomplete,#Fun<jsx_decoder.1.122947756>}
4> G(end_stream). 4> G(end_stream). % can also be `G(end_json)`
[] []
``` ```

View file

@ -107,14 +107,14 @@ is_term(Source) -> is_term(Source, []).
is_term(Source, Config) -> jsx_verify:is_term(Source, Config). is_term(Source, Config) -> jsx_verify:is_term(Source, Config).
-type decoder() :: fun((json_text() | end_stream) -> any()). -type decoder() :: fun((json_text() | end_stream | end_json) -> any()).
-spec decoder(Handler::module(), State::any(), Config::list()) -> decoder(). -spec decoder(Handler::module(), State::any(), Config::list()) -> decoder().
decoder(Handler, State, Config) -> jsx_decoder:decoder(Handler, State, Config). decoder(Handler, State, Config) -> jsx_decoder:decoder(Handler, State, Config).
-type encoder() :: fun((json_term() | end_stream) -> any()). -type encoder() :: fun((json_term() | end_stream | end_json) -> any()).
-spec encoder(Handler::module(), State::any(), Config::list()) -> encoder(). -spec encoder(Handler::module(), State::any(), Config::list()) -> encoder().
@ -464,5 +464,32 @@ encode_test_() ->
} || {Title, _, Term, Events} <- Data } || {Title, _, Term, Events} <- Data
]. ].
end_stream_test_() ->
Tokens = [start_object, end_object, end_json],
[
{"encoder end_stream", ?_assertEqual(
Tokens,
begin
{incomplete, F} = (jsx:parser(jsx, [], [stream]))([start_object, end_object]),
F(end_stream)
end
)},
{"encoder end_json", ?_assertEqual(
Tokens,
begin
{incomplete, F} = (jsx:parser(jsx, [], [stream]))([start_object, end_object]),
F(end_json)
end
)},
{"decoder end_stream", ?_assertEqual(
Tokens,
begin {incomplete, F} = (jsx:decoder(jsx, [], [stream]))(<<"{}">>), F(end_stream) end
)},
{"decoder end_json", ?_assertEqual(
Tokens,
begin {incomplete, F} = (jsx:decoder(jsx, [], [stream]))(<<"{}">>), F(end_json) end
)}
].
-endif. -endif.

View file

@ -150,7 +150,7 @@ incomplete(State, Rest, Handler, Acc, Stack, Config = #config{stream=false}) ->
incomplete(State, Rest, Handler, Acc, Stack, Config = #config{incomplete_handler=false}) -> incomplete(State, Rest, Handler, Acc, Stack, Config = #config{incomplete_handler=false}) ->
{incomplete, fun(Stream) when is_binary(Stream) -> {incomplete, fun(Stream) when is_binary(Stream) ->
resume(<<Rest/binary, Stream/binary>>, State, Handler, Acc, Stack, Config); resume(<<Rest/binary, Stream/binary>>, State, Handler, Acc, Stack, Config);
(end_stream) -> (End) when End == end_stream; End == end_json ->
case resume(<<Rest/binary, ?space/utf8>>, State, Handler, Acc, Stack, Config#config{stream=false}) of case resume(<<Rest/binary, ?space/utf8>>, State, Handler, Acc, Stack, Config#config{stream=false}) of
{incomplete, _} -> ?error(State, Rest, Handler, Acc, Stack, Config); {incomplete, _} -> ?error(State, Rest, Handler, Acc, Stack, Config);
Else -> Else Else -> Else

View file

@ -71,7 +71,7 @@ resume(Rest, State, Handler, Stack, Config) ->
incomplete(State, Handler, Stack, Config=#config{stream=false}) -> incomplete(State, Handler, Stack, Config=#config{stream=false}) ->
?error(State, [], Handler, Stack, Config); ?error(State, [], Handler, Stack, Config);
incomplete(State, Handler, Stack, Config=#config{incomplete_handler=false}) -> incomplete(State, Handler, Stack, Config=#config{incomplete_handler=false}) ->
{incomplete, fun(end_stream) -> {incomplete, fun(End) when End == end_stream; End == end_json ->
case resume([end_json], State, Handler, Stack, Config) of case resume([end_json], State, Handler, Stack, Config) of
{incomplete, _} -> ?error(State, [], Handler, Stack, Config); {incomplete, _} -> ?error(State, [], Handler, Stack, Config);
Else -> Else Else -> Else