Browse Source

Add undefined_as_null to decoder

Heinz N. Gies 8 years ago
parent
commit
e3c0d6acdb
4 changed files with 16 additions and 5 deletions
  1. 2 2
      doc/jsone.md
  2. 3 2
      src/jsone.erl
  3. 6 1
      src/jsone_decode.erl
  4. 5 0
      test/jsone_decode_tests.erl

+ 2 - 2
doc/jsone.md

@@ -60,7 +60,7 @@ datetime_format() = iso8601
 
 
 <pre><code>
-decode_option() = {object_format, tuple | proplist | map} | {allow_ctrl_chars, boolean()} | {keys, binary | atom | existing_atom | attempt_atom}
+decode_option() = {object_format, tuple | proplist | map} | {allow_ctrl_chars, boolean()} | {keys, binary | atom | existing_atom | attempt_atom} | undefined_as_null
 </code></pre>
 
 `object_format`: <br />
@@ -318,7 +318,7 @@ A simple example is worth a thousand words.
 
 
 <pre><code>
-json_value() = <a href="#type-json_number">json_number()</a> | <a href="#type-json_string">json_string()</a> | <a href="#type-json_array">json_array()</a> | <a href="#type-json_object">json_object()</a> | <a href="#type-json_boolean">json_boolean()</a> | null | <a href="#type-json_term">json_term()</a>
+json_value() = <a href="#type-json_number">json_number()</a> | <a href="#type-json_string">json_string()</a> | <a href="#type-json_array">json_array()</a> | <a href="#type-json_object">json_object()</a> | <a href="#type-json_boolean">json_boolean()</a> | null | undefined | <a href="#type-json_term">json_term()</a>
 </code></pre>
 
 

+ 3 - 2
src/jsone.erl

@@ -60,7 +60,7 @@
 %%--------------------------------------------------------------------------------
 %% Types & Macros
 %%--------------------------------------------------------------------------------
--type json_value()          :: json_number() | json_string() | json_array() | json_object() | json_boolean() | null | json_term().
+-type json_value()          :: json_number() | json_string() | json_array() | json_object() | json_boolean() | null | undefined | json_term().
 -type json_boolean()        :: boolean().
 -type json_number()         :: number().
 -type json_string()         :: binary() | atom() | calendar:datetime(). % NOTE: `decode/1' always returns `binary()' value
@@ -226,7 +226,8 @@
 
 -type decode_option() :: {object_format, tuple | proplist | map}
                        | {allow_ctrl_chars, boolean()}
-                       | {'keys', 'binary' | 'atom' | 'existing_atom' | 'attempt_atom'}.
+                       | {'keys', 'binary' | 'atom' | 'existing_atom' | 'attempt_atom'}
+                       | undefined_as_null.
 %% `object_format': <br />
 %% - Decoded JSON object format <br />
 %% - `tuple': An object is decoded as `{[]}' if it is empty, otherwise `{[{Key, Value}]}'. <br />

+ 6 - 1
src/jsone_decode.erl

@@ -67,7 +67,8 @@
         {
           object_format=?DEFAULT_OBJECT_FORMAT :: tuple | proplist | map,
           allow_ctrl_chars=false :: boolean(),
-          keys=binary :: 'binary' | 'atom' | 'existing_atom' | 'attempt_atom'
+          keys=binary :: 'binary' | 'atom' | 'existing_atom' | 'attempt_atom',
+          undefined_as_null=false :: boolean()
         }).
 -define(OPT, #decode_opt_v2).
 -type opt() :: #decode_opt_v2{}.
@@ -116,6 +117,8 @@ whitespace(<<Bin/binary>>,      Next, Nexts, Buf, Opt) ->
 -spec value(binary(), [next()], binary(), opt()) -> decode_result().
 value(<<"false", Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, false, Nexts, Buf, Opt);
 value(<<"true", Bin/binary>>, Nexts, Buf, Opt)  -> next(Bin, true, Nexts, Buf, Opt);
+value(<<"null", Bin/binary>>, Nexts, Buf,
+      Opt = ?OPT{undefined_as_null = true})     -> next(Bin, undefined, Nexts, Buf, Opt);
 value(<<"null", Bin/binary>>, Nexts, Buf, Opt)  -> next(Bin, null, Nexts, Buf, Opt);
 value(<<$[, Bin/binary>>, Nexts, Buf, Opt)      -> whitespace(Bin, array, Nexts, Buf, Opt);
 value(<<${, Bin/binary>>, Nexts, Buf, Opt)      -> whitespace(Bin, object, Nexts, Buf, Opt);
@@ -301,5 +304,7 @@ parse_option([{allow_ctrl_chars,B}|T], Opt) when is_boolean(B) ->
 parse_option([{keys, K}|T], Opt)
   when K =:= binary; K =:= atom; K =:= existing_atom; K =:= attempt_atom ->
     parse_option(T, Opt?OPT{keys = K});
+parse_option([undefined_as_null|T], Opt) ->
+    parse_option(T, Opt?OPT{undefined_as_null = true});
 parse_option(List, Opt) ->
     error(badarg, [List, Opt]).

+ 5 - 0
test/jsone_decode_tests.erl

@@ -290,5 +290,10 @@ decode_test_() ->
               Input    = <<"  [true, {\"1\" : 2, \"array\":[[[[1]]], {\"ab\":\"cd\"}, false]}, null]   ">>,
               Expected = [true, ?OBJ2(<<"1">>, 2, <<"array">>, [[[[1]]], ?OBJ1(<<"ab">>, <<"cd">>), false]), null],
               ?assertEqual({ok, Expected, <<"   ">>}, jsone_decode:decode(Input))
+      end},
+     {"undefined_as_null option",
+      fun() ->
+              ?assertEqual({ok, undefined, <<>>},  jsone_decode:decode(<<"null">>,[undefined_as_null])), % OK
+              ?assertEqual({ok, null, <<>>},       jsone_decode:decode(<<"null">>,[])) % OK
       end}
     ].