Browse Source

Now atom() is allowed as an object key (in encoding)

Takeru Ohta 10 years ago
parent
commit
76009547bf
5 changed files with 49 additions and 37 deletions
  1. 15 12
      README.md
  2. 21 19
      doc/jsone.md
  3. 3 1
      src/jsone.erl
  4. 4 3
      src/jsone_encode.erl
  5. 6 2
      test/jsone_encode_tests.erl

+ 15 - 12
README.md

@@ -80,17 +80,20 @@ Usage Example
 > jsone:encode({[{<<"key">>, <<"value">>}]}).
 <<"{\"key\":\"value\"}">>
 
+> jsone:encode({[{key, <<"value">>}]}). % atom key is allowed
+<<"{\"key\":\"value\"}">>
+
 % error: raises exception
-> jsone:encode({[{key, <<"value">>}]}). % non binary key is not allowed
+> jsone:encode({[{123, <<"value">>}]}). % non binary|atom key is not allowed
 ** exception error: bad argument
      in function  jsone_encode:object_members/3
-        called as jsone_encode:object_members([{key,<<"value">>}],[],<<"{">>)
+        called as jsone_encode:object_members([{123,<<"value">>}],[],<<"{">>)
      in call from jsone:encode/1 (src/jsone.erl, line 97)
 
 % error: returns {error, Reason}
-> jsone:try_encode({[{key, <<"value">>}]}).
+> jsone:try_encode({[{123, <<"value">>}]}).
 {error,{badarg,[{jsone_encode,object_members,
-                              [[{key,<<"value">>}],[],<<"{">>],
+                              [[{123,<<"value">>}],[],<<"{">>],
                               [{line,138}]}]}}
 ```
 
@@ -98,14 +101,14 @@ Usage Example
 Data Mapping (Erlang <=> JSON)
 -------------------------------
 
-|         | Erlang                       | JSON            |
-|:-------:|-----------------------------:|----------------:|
-| number  |                          123 |             123 |
-| null    |                         null |            null |
-| boolean |                         true |            true |
-| string  |                    <<"abc">> |           "abc" |
-| array   |                      [1,2,3] |         [1,2,3] |
-| object  | {[{<<"key">>, <<"value">>}]} | {"key":"value"} |
+|         | Erlang                             | JSON            |
+|:-------:|-----------------------------------:|----------------:|
+| number  |                                123 |             123 |
+| null    |                               null |            null |
+| boolean |                               true |            true |
+| string  |                          <<"abc">> |           "abc" |
+| array   |                            [1,2,3] |         [1,2,3] |
+| object  | {[{<<"key">> | key, <<"value">>}]} | {"key":"value"} |
 
 
 API

+ 21 - 19
doc/jsone.md

@@ -79,12 +79,26 @@ json_object() = {<a href="#type-json_object_members">json_object_members()</a>}
 
 
 
+### <a name="type-json_object_key">json_object_key()</a> ###
+
+
+
+<pre><code>
+json_object_key() = <a href="#type-json_string">json_string()</a> | atom()
+</code></pre>
+
+
+
+ NOTE: `decode/1` always returns `json_string()` key
+
+
+
 ### <a name="type-json_object_members">json_object_members()</a> ###
 
 
 
 <pre><code>
-json_object_members() = [{<a href="#type-json_string">json_string()</a>, <a href="#type-json_value">json_value()</a>}]
+json_object_members() = [{<a href="#type-json_object_key">json_object_key()</a>, <a href="#type-json_value">json_value()</a>}]
 </code></pre>
 
 
@@ -132,9 +146,7 @@ json_value() = <a href="#type-json_number">json_number()</a> | <a href="#type-js
 <pre><code>
 decode(Json::binary()) -&gt; <a href="#type-json_value">json_value()</a>
 </code></pre>
-
-<br></br>
-
+<br />
 
 
 Decodes an erlang term from json text (a utf8 encoded binary)
@@ -163,9 +175,7 @@ Raises an error exception if input is not valid json
 <pre><code>
 encode(JsonValue::<a href="#type-json_value">json_value()</a>) -&gt; binary()
 </code></pre>
-
-<br></br>
-
+<br />
 
 Equivalent to [`encode(JsonValue, [])`](#encode-2).
 <a name="encode-2"></a>
@@ -176,9 +186,7 @@ Equivalent to [`encode(JsonValue, [])`](#encode-2).
 <pre><code>
 encode(JsonValue::<a href="#type-json_value">json_value()</a>, Options::[<a href="#type-encode_option">encode_option()</a>]) -&gt; binary()
 </code></pre>
-
-<br></br>
-
+<br />
 
 
 Encodes an erlang term into json text (a utf8 encoded binary)
@@ -207,9 +215,7 @@ Raises an error exception if input is not an instance of type `json_value()`
 <pre><code>
 try_decode(Json::binary()) -&gt; {ok, <a href="#type-json_value">json_value()</a>, Remainings::binary()} | {error, {Reason::term(), [<a href="erlang.md#type-stack_item">erlang:stack_item()</a>]}}
 </code></pre>
-
-<br></br>
-
+<br />
 
 
 Decodes an erlang term from json text (a utf8 encoded binary)
@@ -233,9 +239,7 @@ Decodes an erlang term from json text (a utf8 encoded binary)
 <pre><code>
 try_encode(JsonValue::<a href="#type-json_value">json_value()</a>) -&gt; {ok, binary()} | {error, {Reason::term(), [<a href="erlang.md#type-stack_item">erlang:stack_item()</a>]}}
 </code></pre>
-
-<br></br>
-
+<br />
 
 Equivalent to [`try_encode(JsonValue, [])`](#try_encode-2).
 <a name="try_encode-2"></a>
@@ -246,9 +250,7 @@ Equivalent to [`try_encode(JsonValue, [])`](#try_encode-2).
 <pre><code>
 try_encode(JsonValue::<a href="#type-json_value">json_value()</a>, Options::[<a href="#type-encode_option">encode_option()</a>]) -&gt; {ok, binary()} | {error, {Reason::term(), [<a href="erlang.md#type-stack_item">erlang:stack_item()</a>]}}
 </code></pre>
-
-<br></br>
-
+<br />
 
 
 Encodes an erlang term into json text (a utf8 encoded binary)

+ 3 - 1
src/jsone.erl

@@ -42,6 +42,7 @@
               json_array/0,
               json_object/0,
               json_object_members/0,
+              json_object_key/0,
               json_boolean/0,
 
               encode_option/0
@@ -56,7 +57,8 @@
 -type json_string()         :: binary().
 -type json_array()          :: [json_value()].
 -type json_object()         :: {json_object_members()}.
--type json_object_members() :: [{json_string(), json_value()}].
+-type json_object_members() :: [{json_object_key(), json_value()}].
+-type json_object_key()     :: json_string() | atom(). % NOTE: `decode/1' always returns `json_string()' key
 
 -type encode_option() :: native_utf8.
 %% native_utf8: Encodes UTF-8 characters as a human-readable(non-escaped) string

+ 4 - 3
src/jsone_encode.erl

@@ -160,9 +160,10 @@ object({Members}, Nexts, Buf, Opt) ->
     object_members(Members, Nexts, <<Buf/binary, ${>>, Opt).
 
 -spec object_members(jsone:json_object_members(), [next()], binary(), encode_opt()) -> encode_result().
-object_members([],                             Nexts, Buf, Opt) -> next(Nexts, <<Buf/binary, $}>>, Opt);
-object_members([{<<Key/binary>>, Value} | Xs], Nexts, Buf, Opt) -> string(Key, [{object_value, Value, Xs} | Nexts], Buf, Opt);
-object_members(Arg, Nexts, Buf, _)                            -> ?ERROR(object_members, [Arg, Nexts, Buf]).
+object_members([],                             Nexts, Buf, Opt)        -> next(Nexts, <<Buf/binary, $}>>, Opt);
+object_members([{<<Key/binary>>, Value} | Xs], Nexts, Buf, Opt)        -> string(Key, [{object_value, Value, Xs} | Nexts], Buf, Opt);
+object_members([{Key, Value} | Xs], Nexts, Buf, Opt) when is_atom(Key) -> string(atom_to_binary(Key, utf8), [{object_value, Value, Xs} | Nexts], Buf, Opt);
+object_members(Arg, Nexts, Buf, _)                                     -> ?ERROR(object_members, [Arg, Nexts, Buf]).
 
 -spec object_value(jsone:json_value(), jsone:json_object_members(), [next()], binary(), encode_opt()) -> encode_result().
 object_value(Value, Members, Nexts, Buf, Opt) ->

+ 6 - 2
test/jsone_encode_tests.erl

@@ -108,11 +108,15 @@ encode_test_() ->
               Expected = <<"{}">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input))
       end},
+     {"atom key is allowed",
+      fun () ->
+              Expected = <<"{\"key\":2}">>,
+              ?assertEqual({ok, Expected}, jsone_encode:encode({[{key, 2}]}))
+      end},
      {"non binary object member key is disallowed",
       fun () ->
               ?assertMatch({error, {badarg, _}}, jsone_encode:encode({[{1, 2}]})),
-              ?assertMatch({error, {badarg, _}}, jsone_encode:encode({[{"1", 2}]})),
-              ?assertMatch({error, {badarg, _}}, jsone_encode:encode({[{true, 2}]}))
+              ?assertMatch({error, {badarg, _}}, jsone_encode:encode({[{"1", 2}]}))
       end},
 
      %% Others