From ec295a888b312ed0c131bae38ebe5e6a841bd0cc Mon Sep 17 00:00:00 2001 From: alisdair sullivan Date: Sun, 4 Mar 2012 18:40:00 -0800 Subject: [PATCH] new is_term function that mirrors is_json for erlang terms --- README.markdown | 18 ++++++++++++++---- src/jsx.erl | 16 ++++++++++++---- src/jsx_to_json.erl | 17 +++++++++-------- src/jsx_to_term.erl | 2 +- src/jsx_utils.erl | 19 +++++++++++++++++-- src/jsx_verify.erl | 19 +++++++++++-------- 6 files changed, 64 insertions(+), 27 deletions(-) diff --git a/README.markdown b/README.markdown index 6e00fc9..e343057 100644 --- a/README.markdown +++ b/README.markdown @@ -105,7 +105,7 @@ see the note below about streaming mode for details of `explicit_end` **verifying json texts** -returns true if input is a valid JSON text or erlang term that represents a JSON text, false if not. note that if you want to recognize naked (unwrapped) terms, you must specify a parser to use +returns true if input is a valid JSON text, false if not `is_json(MaybeJSON)` -> `Term` @@ -117,12 +117,22 @@ types: * `Term` = `true` | `false` | `{incomplete, Fun}` * `Opts` = `[]` | `[Opt]` * `Opt` = - - `{parser, Parser}` - * `Parser` = `jsx:decoder()` | `jsx:encoder()` - `loose_unicode` - `explicit_end` -see `json_to_term` and `term_to_json` for details of options +see `json_to_term` for details of options + + +**verifying json texts** + +returns true if input is a valid erlang term that represents a JSON text, false if not + +`is_term(MaybeJSON)` -> `Term` + +types: + +* `MaybeJSON` = `any()` +* `Term` = `true` | `false` **streaming mode** diff --git a/src/jsx.erl b/src/jsx.erl index baa6f66..0c6caee 100644 --- a/src/jsx.erl +++ b/src/jsx.erl @@ -25,7 +25,7 @@ -export([to_json/1, to_json/2]). -export([to_term/1, to_term/2]). --export([is_json/1, is_json/2]). +-export([is_json/1, is_json/2, is_term/1, is_term/2]). -export([format/1, format/2]). -export([encoder/3, decoder/3]). %% old api @@ -56,7 +56,7 @@ term_to_json(Source, Opts) -> to_json(Source, Opts). format(Source) -> format(Source, []). -format(Source, Opts) -> jsx_to_json:to_json(Source, Opts). +format(Source, Opts) -> jsx_to_json:format(Source, Opts). -spec to_term(Source::binary()) -> any(). @@ -72,14 +72,22 @@ json_to_term(Source) -> to_term(Source, []). json_to_term(Source, Opts) -> to_term(Source, Opts). --spec is_json(Source::binary() | list()) -> true | false. --spec is_json(Source::binary() | list(), Opts::jsx_verify:opts()) -> true | false. +-spec is_json(Source::binary()) -> true | false. +-spec is_json(Source::binary(), Opts::jsx_verify:opts()) -> true | false. is_json(Source) -> is_json(Source, []). is_json(Source, Opts) -> jsx_verify:is_json(Source, Opts). +-spec is_term(Source::any()) -> true | false. +-spec is_term(Source::any(), Opts::jsx_verify:opts()) -> true | false. + +is_term(Source) -> is_term(Source, []). + +is_term(Source, Opts) -> jsx_verify:is_term(Source, Opts). + + -spec decoder(Handler::module(), State::any(), Opts::list()) -> fun(). decoder(Handler, State, Opts) -> jsx_decoder:decoder(Handler, State, Opts). diff --git a/src/jsx_to_json.erl b/src/jsx_to_json.erl index e5a80fc..3e994bb 100644 --- a/src/jsx_to_json.erl +++ b/src/jsx_to_json.erl @@ -23,7 +23,7 @@ -module(jsx_to_json). --export([to_json/2]). +-export([to_json/2, format/2]). -export([init/1, handle_event/2]). @@ -36,14 +36,17 @@ -type opts() :: list(). --spec to_json(Source::(binary() | list()), Opts::opts()) -> binary(). +-spec to_json(Source::any(), Opts::opts()) -> binary(). -to_json(Source, Opts) when is_list(Source) andalso is_list(Opts) -> - (jsx:encoder(?MODULE, init(Opts), Opts))(Source); -to_json(Source, Opts) when is_binary(Source) andalso is_list(Opts) -> - (jsx:decoder(?MODULE, init(Opts), Opts))(Source). +to_json(Source, Opts) when is_list(Opts) -> + (jsx:encoder(?MODULE, init(Opts), jsx_utils:extract_opts(Opts)))(Source). +-spec format(Source::binary(), Opts::opts()) -> binary(). + +format(Source, Opts) when is_binary(Source) andalso is_list(Opts) -> + (jsx:decoder(?MODULE, init(Opts), jsx_utils:extract_opts(Opts)))(Source). + parse_opts(Opts) -> parse_opts(Opts, #opts{}). @@ -173,8 +176,6 @@ indent_or_space(Opts) -> -ifdef(TEST). -include_lib("eunit/include/eunit.hrl"). -format(Source, Opts) -> to_json(Source, Opts). - basic_test_() -> [ {"empty object", ?_assert(format(<<"{}">>, []) =:= <<"{}">>)}, diff --git a/src/jsx_to_term.erl b/src/jsx_to_term.erl index e5f434f..06908f3 100644 --- a/src/jsx_to_term.erl +++ b/src/jsx_to_term.erl @@ -37,7 +37,7 @@ -spec to_term(Source::(binary() | list()), Opts::opts()) -> binary(). to_term(Source, Opts) when is_list(Opts) -> - (jsx:decoder(?MODULE, init(Opts), Opts))(Source). + (jsx:decoder(?MODULE, init(Opts), jsx_utils:extract_opts(Opts)))(Source). diff --git a/src/jsx_utils.erl b/src/jsx_utils.erl index b26ff6c..5de1598 100644 --- a/src/jsx_utils.erl +++ b/src/jsx_utils.erl @@ -24,6 +24,7 @@ -module(jsx_utils). -export([parse_opts/1]). +-export([extract_opts/1]). -export([json_escape/2]). -include("../include/jsx_opts.hrl"). @@ -42,12 +43,26 @@ 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]) 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. + + %% json string escaping, for utf8 binaries. escape the json control sequences to %% their json equivalent, escape other control characters to \uXXXX sequences, %% everything else should be a legal json string component diff --git a/src/jsx_verify.erl b/src/jsx_verify.erl index ec18371..f087184 100644 --- a/src/jsx_verify.erl +++ b/src/jsx_verify.erl @@ -23,7 +23,7 @@ -module(jsx_verify). --export([is_json/2]). +-export([is_json/2, is_term/2]). -export([init/1, handle_event/2]). @@ -34,18 +34,21 @@ -type opts() :: []. --spec is_json(Source::(binary() | list()), Opts::opts()) -> binary(). +-spec is_json(Source::binary(), Opts::opts()) -> true | false. -is_json(Source, Opts) when is_list(Source) andalso is_list(Opts) -> - try (jsx:encoder(?MODULE, init(Opts), Opts))(Source) - catch error:badarg -> false - end; -is_json(Source, Opts) when is_binary(Source) andalso is_list(Opts) -> - try (jsx:decoder(?MODULE, init(Opts), Opts))(Source) +is_json(Source, Opts) when is_list(Opts) -> + try (jsx:decoder(?MODULE, init(Opts), jsx_utils:extract_opts(Opts)))(Source) catch error:badarg -> false end. +-spec is_term(Source::any(), Opts::opts()) -> true | false. + +is_term(Source, Opts) when is_list(Opts) -> + try (jsx:encoder(?MODULE, init(Opts), jsx_utils:extract_opts(Opts)))(Source) + catch error:badarg -> false + end. + parse_opts(Opts) -> parse_opts(Opts, #opts{}).