diff --git a/README.md b/README.md index ba1c5c3..0024ba1 100644 --- a/README.md +++ b/README.md @@ -12,7 +12,8 @@ to keep with the standard (rfc4627). Encoding is also compatible with rfc8259. | number() | binary() | json_object() | json_array(). -type json_object() :: #{json_key() => json_value()}. -type json_array() :: [json_value()]. --type json_opts() :: #{'keys' => 'atom' | 'existing_atom' | 'list'}. +-type json_opts() :: #{'keys' => 'atom' | 'existing_atom' | 'list' | + 'integet_and_atom'}. -spec lejson:decode(iodata()) -> json_object() | json_array() | {error, not_json}. -spec lejson:decode(iodata(), json_opts()) -> diff --git a/src/lejson.erl b/src/lejson.erl index dd5ffb1..b44a78e 100644 --- a/src/lejson.erl +++ b/src/lejson.erl @@ -23,7 +23,8 @@ | number() | binary() | json_object() | json_array(). -type json_object() :: #{json_key() => json_value()}. -type json_array() :: [json_value()]. --type json_opts() :: #{'keys' => 'atom' | 'existing_atom' | 'list'}. +-type json_opts() :: #{'keys' => 'atom' | 'existing_atom' | 'list' | + 'integer_and_atom' }. %% Encode --------------------------------------------------------------------- @@ -52,6 +53,7 @@ encode_value(#{} = Map) -> encode_map(Map); encode_value(Array) when is_list(Array) -> encode_array(Array). encode_key(Key) when is_atom(Key) -> atom_to_binary(Key, utf8); +encode_key(Key) when is_integer(Key) -> integer_to_binary(Key); encode_key(Key) -> Key. encode_string(Bin) when is_binary(Bin) -> @@ -257,4 +259,9 @@ is_json(_) -> false. convert_key(Key, #{keys:=atom}) -> binary_to_atom(Key, utf8); convert_key(Key, #{keys:=existing_atom}) -> binary_to_existing_atom(Key, utf8); convert_key(Key, #{keys:=list}) -> binary_to_list(Key); +convert_key(Key, #{keys:=integer_and_atom}) -> + try binary_to_integer(Key) + catch + _:_ -> binary_to_atom(Key, utf8) + end; convert_key(Key, #{}) -> Key. diff --git a/test/lejson_test.erl b/test/lejson_test.erl index 9c1bd51..5a50384 100644 --- a/test/lejson_test.erl +++ b/test/lejson_test.erl @@ -7,11 +7,15 @@ config_test_() -> fun setup_config/0, fun cleanup_config/1, {inorder, [ {timeout, 120, - {"encode", fun() -> test_encode({e,n,c}) end}} | - [ {timeout, 120, - {atom_to_list(Name), - fun() -> test_decode(Data) end}} || - {Name,_,_} = Data <- json_strings_should_pass()]]}}. + {"encode", fun() -> test_encode({e,n,c}) end}}, + [ {timeout, 120, + {atom_to_list(Name), + fun() -> test_opts(Data) end}} || + {Name,_,_,_} = Data <- maps_with_opts()], + [ {timeout, 120, + {atom_to_list(Name), + fun() -> test_decode(Data) end}} || + {Name,_,_} = Data <- json_strings_should_pass()]]}}. setup_config() -> ok. cleanup_config(_) -> ok. @@ -82,8 +86,15 @@ json_strings_should_pass() -> <<"{\"escaped_string\": \"\\t\\n\\r\\f\\b\\\\\\/\\\"\"}">>, #{<<"escaped_string">> => <<"\t\n\r\f\b\\/\"">>}}]. +maps_with_opts() -> + [{integer_as_key, + <<"{\"256\": 1}">>, + #{256 => 1}, #{keys => integer_and_atom}}]. + test_decode({_Type, Data, Expected}) -> - ?assertEqual(Expected, lejson:decode(Data)). + ?assertEqual(Expected, lejson:decode(Data)); +test_decode({_Type, Data, Expected, Opts}) -> + ?assertEqual(Expected, lejson:decode(Data, Opts)). test_encode({_Type, _Data, _Expected}) -> test_encode_decode(simple_json()). @@ -108,3 +119,9 @@ simple_json() -> "\"nested_array\": [[[79]]]," "\"another_array\": [1,2,3,[1,[2],3],12]}">>. +test_opts({_Type, ExpectedJson, Map, Opts}) -> + Json = lejson:encode(Map), + NewMap = lejson:decode(Json, Opts), + Json == ExpectedJson andalso + Map == NewMap. +