add `get_value/1' function for retrieving the current (final?) value
of the internal representations from `jsx_to_json' and `jsx_to_term' add all internal representation functions to `jsx' module and export them
This commit is contained in:
parent
00469ba9c6
commit
c81e2108dd
3 changed files with 116 additions and 5 deletions
99
src/jsx.erl
99
src/jsx.erl
|
@ -28,9 +28,12 @@
|
||||||
-export([format/1, format/2, minify/1, prettify/1]).
|
-export([format/1, format/2, minify/1, prettify/1]).
|
||||||
-export([encoder/3, decoder/3, parser/3]).
|
-export([encoder/3, decoder/3, parser/3]).
|
||||||
-export([resume/3]).
|
-export([resume/3]).
|
||||||
|
-export([start_json/0, start_json/1, start_term/0, start_term/1]).
|
||||||
|
-export([start_object/1, start_array/1, finish/1, insert/2, insert/3, get_key/1, get_value/1]).
|
||||||
|
|
||||||
-export_type([json_term/0, json_text/0, token/0]).
|
-export_type([json_term/0, json_text/0, token/0]).
|
||||||
-export_type([encoder/0, decoder/0, parser/0, internal_state/0]).
|
-export_type([encoder/0, decoder/0, parser/0, internal_state/0]).
|
||||||
|
-export_type([internal_json/0, internal_term/0, internal_thing/0]).
|
||||||
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
-ifdef(TEST).
|
||||||
|
@ -150,12 +153,108 @@ resume(Term, {parser, State, Handler, Stack}, Config) ->
|
||||||
jsx_parser:resume(Term, State, Handler, Stack, jsx_config:parse_config(Config)).
|
jsx_parser:resume(Term, State, Handler, Stack, jsx_config:parse_config(Config)).
|
||||||
|
|
||||||
|
|
||||||
|
-opaque internal_json() :: tuple().
|
||||||
|
|
||||||
|
-spec start_json() -> internal_json().
|
||||||
|
-spec start_json(Config::list()) -> internal_json().
|
||||||
|
|
||||||
|
start_json() -> {jsx_to_json, jsx_to_json:start_json()}.
|
||||||
|
start_json(Config) -> {jsx_to_json, jsx_to_json:start_json(Config)}.
|
||||||
|
|
||||||
|
|
||||||
|
-opaque internal_term() :: tuple().
|
||||||
|
|
||||||
|
-spec start_term() -> internal_term().
|
||||||
|
-spec start_term(Config::list()) -> internal_term().
|
||||||
|
|
||||||
|
start_term() -> {jsx_to_term, jsx_to_term:start_term()}.
|
||||||
|
start_term(Config) -> {jsx_to_term, jsx_to_term:start_term(Config)}.
|
||||||
|
|
||||||
|
|
||||||
|
% naming things is hard
|
||||||
|
-opaque internal_thing() :: internal_term() | internal_json().
|
||||||
|
|
||||||
|
|
||||||
|
-spec start_object(internal_thing()) -> internal_thing().
|
||||||
|
|
||||||
|
start_object({Handler, Internals}) -> {Handler, Handler:start_object(Internals)}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec start_array(internal_thing()) -> internal_thing().
|
||||||
|
|
||||||
|
start_array({Handler, Internals}) -> {Handler, Handler:start_array(Internals)}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec finish(internal_thing()) -> internal_thing().
|
||||||
|
|
||||||
|
finish({Handler, Internals}) -> {Handler, Handler:finish(Internals)}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec insert(Value::any(), internal_thing()) -> internal_thing().
|
||||||
|
|
||||||
|
insert(Value, {Handler, Internals}) -> {Handler, Handler:insert(Value, Internals)}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec insert(Key::any(), Value::any(), internal_thing()) -> internal_thing().
|
||||||
|
|
||||||
|
insert(Key, Value, {Handler, Internals}) -> {Handler, Handler:insert(Key, Value, Internals)}.
|
||||||
|
|
||||||
|
|
||||||
|
-spec get_key(internal_thing()) -> atom() | binary().
|
||||||
|
|
||||||
|
get_key({Handler, Internals}) -> Handler:get_key(Internals).
|
||||||
|
|
||||||
|
|
||||||
|
-spec get_value(internal_thing()) -> any().
|
||||||
|
|
||||||
|
get_value({Handler, Internals}) -> Handler:get_value(Internals).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
-ifdef(TEST).
|
||||||
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
-include_lib("eunit/include/eunit.hrl").
|
||||||
|
|
||||||
|
|
||||||
|
%% sanity checks for internal format handlers
|
||||||
|
|
||||||
|
internal_format_sanity_test_() ->
|
||||||
|
[
|
||||||
|
{"jsx term sanity check", ?_assertEqual(
|
||||||
|
[{key, [1, true, <<"hallo world">>]}],
|
||||||
|
begin
|
||||||
|
NewTerm = start_term(),
|
||||||
|
ObjectAllocated = start_object(NewTerm),
|
||||||
|
KeyInserted = insert(key, ObjectAllocated),
|
||||||
|
ArrayAllocated = start_array(KeyInserted),
|
||||||
|
OneInserted = insert(1, ArrayAllocated),
|
||||||
|
TrueInserted = insert(true, OneInserted),
|
||||||
|
HalloWorldInserted = insert(<<"hallo world">>, TrueInserted),
|
||||||
|
ArrayClosed = finish(HalloWorldInserted),
|
||||||
|
ObjectClosed = finish(ArrayClosed),
|
||||||
|
TermClosed = get_value(ObjectClosed),
|
||||||
|
TermClosed
|
||||||
|
end
|
||||||
|
)},
|
||||||
|
{"jsx json sanity check", ?_assertEqual(
|
||||||
|
<<"{\"key\":[1,true,\"hallo world\"]}">>,
|
||||||
|
begin
|
||||||
|
NewTerm = start_json(),
|
||||||
|
ObjectAllocated = start_object(NewTerm),
|
||||||
|
KeyInserted = insert(<<"\"key\"">>, ObjectAllocated),
|
||||||
|
ArrayAllocated = start_array(KeyInserted),
|
||||||
|
OneInserted = insert(<<"1">>, ArrayAllocated),
|
||||||
|
TrueInserted = insert(<<"true">>, OneInserted),
|
||||||
|
HalloWorldInserted = insert(<<"\"hallo world\"">>, TrueInserted),
|
||||||
|
ArrayClosed = finish(HalloWorldInserted),
|
||||||
|
ObjectClosed = finish(ArrayClosed),
|
||||||
|
TermClosed = get_value(ObjectClosed),
|
||||||
|
TermClosed
|
||||||
|
end
|
||||||
|
)}
|
||||||
|
].
|
||||||
|
|
||||||
|
|
||||||
%% test handler
|
%% test handler
|
||||||
init([]) -> [].
|
init([]) -> [].
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
-export([to_json/2, format/2]).
|
-export([to_json/2, format/2]).
|
||||||
-export([init/1, handle_event/2]).
|
-export([init/1, handle_event/2]).
|
||||||
-export([start_json/0, start_json/1]).
|
-export([start_json/0, start_json/1]).
|
||||||
-export([start_object/1, start_array/1, finish/1, insert/2, insert/3, get_key/1]).
|
-export([start_object/1, start_array/1, finish/1, insert/2, insert/3, get_key/1, get_value/1]).
|
||||||
|
|
||||||
|
|
||||||
-record(config, {
|
-record(config, {
|
||||||
|
@ -95,7 +95,7 @@ init(Config) -> {[], parse_config(Config)}.
|
||||||
|
|
||||||
-spec handle_event(Event::any(), State::state()) -> state().
|
-spec handle_event(Event::any(), State::state()) -> state().
|
||||||
|
|
||||||
handle_event(end_json, {Term, _Config}) -> Term;
|
handle_event(end_json, State) -> get_value(State);
|
||||||
|
|
||||||
handle_event(start_object, State) -> start_object(State);
|
handle_event(start_object, State) -> start_object(State);
|
||||||
handle_event(end_object, State) -> finish(State);
|
handle_event(end_object, State) -> finish(State);
|
||||||
|
@ -243,6 +243,14 @@ get_key({[{object, Key, _}|_], _}) -> Key;
|
||||||
get_key(_) -> erlang:error(badarg).
|
get_key(_) -> erlang:error(badarg).
|
||||||
|
|
||||||
|
|
||||||
|
get_value({Value, Config}) ->
|
||||||
|
case Value of
|
||||||
|
Value when is_binary(Value) -> Value;
|
||||||
|
_ -> erlang:error(badarg)
|
||||||
|
end;
|
||||||
|
get_value(_) -> erlang:error(badarg).
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
%% eunit tests
|
%% eunit tests
|
||||||
|
|
||||||
|
|
|
@ -26,7 +26,7 @@
|
||||||
-export([to_term/2]).
|
-export([to_term/2]).
|
||||||
-export([init/1, handle_event/2]).
|
-export([init/1, handle_event/2]).
|
||||||
-export([start_term/0, start_term/1]).
|
-export([start_term/0, start_term/1]).
|
||||||
-export([start_object/1, start_array/1, finish/1, insert/2, insert/3, get_key/1]).
|
-export([start_object/1, start_array/1, finish/1, insert/2, insert/3, get_key/1, get_value/1]).
|
||||||
|
|
||||||
|
|
||||||
-record(config, {
|
-record(config, {
|
||||||
|
@ -80,7 +80,7 @@ init(Config) -> {[], parse_config(Config)}.
|
||||||
|
|
||||||
-spec handle_event(Event::any(), State::state()) -> state().
|
-spec handle_event(Event::any(), State::state()) -> state().
|
||||||
|
|
||||||
handle_event(end_json, {Term, _Config}) -> Term;
|
handle_event(end_json, State) -> get_value(State);
|
||||||
|
|
||||||
handle_event(start_object, State) -> start_object(State);
|
handle_event(start_object, State) -> start_object(State);
|
||||||
handle_event(end_object, State) -> finish(State);
|
handle_event(end_object, State) -> finish(State);
|
||||||
|
@ -128,7 +128,8 @@ start_object({Stack, Config}) -> {[{object, []}] ++ Stack, Config}.
|
||||||
%% allocate a new array on top of the stack
|
%% allocate a new array on top of the stack
|
||||||
start_array({Stack, Config}) -> {[{array, []}] ++ Stack, Config}.
|
start_array({Stack, Config}) -> {[{array, []}] ++ Stack, Config}.
|
||||||
|
|
||||||
%% finish an object or array and insert it into the parent object if it exists
|
%% finish an object or array and insert it into the parent object if it exists or
|
||||||
|
%% return it if it is the root object
|
||||||
finish({[{object, []}], Config}) -> {[{}], Config};
|
finish({[{object, []}], Config}) -> {[{}], Config};
|
||||||
finish({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config});
|
finish({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config});
|
||||||
finish({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config};
|
finish({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config};
|
||||||
|
@ -158,6 +159,9 @@ get_key({[{object, Key, _}|_], _}) -> Key;
|
||||||
get_key(_) -> erlang:error(badarg).
|
get_key(_) -> erlang:error(badarg).
|
||||||
|
|
||||||
|
|
||||||
|
get_value({Value, _Config}) -> Value;
|
||||||
|
get_value(_) -> erlang:error(badarg).
|
||||||
|
|
||||||
|
|
||||||
%% eunit tests
|
%% eunit tests
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue