add a return_maps option that returns maps instead of proplists

This commit is contained in:
alisdair sullivan 2014-11-24 17:21:37 -08:00
parent 55eaa7b524
commit 989609b250

View file

@ -30,7 +30,8 @@
-record(config, { -record(config, {
labels = binary labels = binary,
return_maps = false
}). }).
-type config() :: list(). -type config() :: list().
@ -60,6 +61,11 @@ parse_config([{labels, Val}|Rest], Config)
parse_config(Rest, Config#config{labels = Val}); parse_config(Rest, Config#config{labels = Val});
parse_config([labels|Rest], Config) -> parse_config([labels|Rest], Config) ->
parse_config(Rest, Config#config{labels = binary}); parse_config(Rest, Config#config{labels = binary});
parse_config([{return_maps, Val}|Rest], Config)
when Val == true; Val == false ->
parse_config(Rest, Config#config{return_maps = true});
parse_config([return_maps|Rest], Config) ->
parse_config(Rest, Config#config{return_maps = true});
parse_config([{K, _}|Rest] = Options, Config) -> parse_config([{K, _}|Rest] = Options, Config) ->
case lists:member(K, jsx_config:valid_flags()) of case lists:member(K, jsx_config:valid_flags()) of
true -> parse_config(Rest, Config) true -> parse_config(Rest, Config)
@ -128,15 +134,31 @@ 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}.
-ifndef(maps_support).
finish(Any) -> finish0(Any).
-endif.
-ifdef(maps_support).
finish({[{object, []}], Config=#config{return_maps=true}}) ->
{#{}, Config};
finish({[{object, []}|Rest], Config=#config{return_maps=true}}) ->
insert(#{}, {Rest, Config});
finish({[{object, Pairs}], Config=#config{return_maps=true}}) ->
{maps:from_list(Pairs), Config};
finish({[{object, Pairs}|Rest], Config=#config{return_maps=true}}) ->
insert(maps:from_list(Pairs), {Rest, Config});
finish(Else) -> finish0(Else).
-endif.
%% finish an object or array and insert it into the parent object if it exists or %% finish an object or array and insert it into the parent object if it exists or
%% return it if it is the root object %% return it if it is the root object
finish({[{object, []}], Config}) -> {[{}], Config}; finish0({[{object, []}], Config}) -> {[{}], Config};
finish({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config}); finish0({[{object, []}|Rest], Config}) -> insert([{}], {Rest, Config});
finish({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config}; finish0({[{object, Pairs}], Config}) -> {lists:reverse(Pairs), Config};
finish({[{object, Pairs}|Rest], Config}) -> insert(lists:reverse(Pairs), {Rest, Config}); finish0({[{object, Pairs}|Rest], Config}) -> insert(lists:reverse(Pairs), {Rest, Config});
finish({[{array, Values}], Config}) -> {lists:reverse(Values), Config}; finish0({[{array, Values}], Config}) -> {lists:reverse(Values), Config};
finish({[{array, Values}|Rest], Config}) -> insert(lists:reverse(Values), {Rest, Config}); finish0({[{array, Values}|Rest], Config}) -> insert(lists:reverse(Values), {Rest, Config});
finish(_) -> erlang:error(badarg). finish0(_) -> erlang:error(badarg).
%% insert a value when there's no parent object or array %% insert a value when there's no parent object or array
insert(Value, {[], Config}) -> {Value, Config}; insert(Value, {[], Config}) -> {Value, Config};
@ -179,6 +201,10 @@ config_test_() ->
#config{labels=existing_atom}, #config{labels=existing_atom},
parse_config([{labels, existing_atom}]) parse_config([{labels, existing_atom}])
)}, )},
{"return_maps true", ?_assertEqual(
#config{return_maps=true},
parse_config([return_maps])
)},
{"invalid opt flag", ?_assertError(badarg, parse_config([error]))}, {"invalid opt flag", ?_assertError(badarg, parse_config([error]))},
{"invalid opt tuple", ?_assertError(badarg, parse_config([{error, true}]))} {"invalid opt tuple", ?_assertError(badarg, parse_config([{error, true}]))}
]. ].
@ -283,6 +309,34 @@ rep_manipulation_test_() ->
)} )}
]. ].
-ifdef(maps_support).
return_maps_test_() ->
[
{"an empty map", ?_assertEqual(
#{},
jsx:decode(<<"{}">>, [return_maps])
)},
{"an empty map", ?_assertEqual(
[{}],
jsx:decode(<<"{}">>, [])
)},
{"a small map", ?_assertEqual(
#{<<"awesome">> => true, <<"library">> => <<"jsx">>},
jsx:decode(<<"{\"library\": \"jsx\", \"awesome\": true}">>, [return_maps])
)},
{"a recursive map", ?_assertEqual(
#{<<"key">> => #{<<"key">> => true}},
jsx:decode(<<"{\"key\": {\"key\": true}}">>, [return_maps])
)},
{"a map inside a list", ?_assertEqual(
[#{}],
jsx:decode(<<"[{}]">>, [return_maps])
)}
].
-endif.
handle_event_test_() -> handle_event_test_() ->
Data = jsx:test_cases(), Data = jsx:test_cases(),