Browse Source

Add formatter check to CI

Takeru Ohta 3 years ago
parent
commit
7a5e359054
10 changed files with 779 additions and 685 deletions
  1. 1 0
      .github/workflows/ci.yml
  2. 17 41
      rebar.config
  3. 9 8
      src/jsone.app.src
  4. 59 54
      src/jsone.erl
  5. 198 114
      src/jsone_decode.erl
  6. 289 226
      src/jsone_encode.erl
  7. 19 11
      src/jsone_inet.erl
  8. 68 96
      test/jsone_decode_tests.erl
  9. 111 124
      test/jsone_encode_tests.erl
  10. 8 11
      test/jsone_inet_tests.erl

+ 1 - 0
.github/workflows/ci.yml

@@ -19,6 +19,7 @@ jobs:
       - uses: actions/checkout@v2
       - run: rebar3 compile
       - run: rebar3 xref
+      - run: rebar3 efmt -c
       - run: rebar3 eunit
       - run: rebar3 dialyzer
       - run: rebar3 edoc

+ 17 - 41
rebar.config

@@ -1,56 +1,32 @@
 %% -*- erlang -*-
-{erl_opts, [
-            warnings_as_errors,
-            warn_export_all,
-            warn_untyped_record,
-            inline,
-            {platform_define, "^R[01][0-9]", 'NO_MAP_TYPE'},
-            {platform_define, "^(R|17)", 'NO_DIALYZER_SPEC'}
-           ]}.
-
-{xref_checks, [
-               fail_on_warning,
-               undefined_function_calls
-              ]}.
+{erl_opts,
+ [warnings_as_errors,
+  warn_export_all,
+  warn_untyped_record,
+  inline,
+  {platform_define, "^R[01][0-9]", 'NO_MAP_TYPE'},
+  {platform_define, "^(R|17)", 'NO_DIALYZER_SPEC'}]}.
+
+{xref_checks, [fail_on_warning, undefined_function_calls]}.
 
 {clean_files, [".eunit/*", "ebin/*.beam"]}.
 
 {cover_enabled, true}.
 
-{edoc_opts, [
-             {dialyzer_specs, all},
-             {report_missing_type, true},
-             {report_type_mismatch, true},
-             {pretty_print, erl_pp},
-             {preprocess, true}
-            ]}.
+{edoc_opts,
+ [{dialyzer_specs, all},
+  {report_missing_type, true},
+  {report_type_mismatch, true},
+  {pretty_print, erl_pp},
+  {preprocess, true}]}.
 {validate_app_modules, true}.
 
 {shell, [{apps, [jsone]}]}.
 
-{dialyzer,
- [
-  {warnings, [error_handling, race_conditions, unmatched_returns, unknown, no_improper_lists]}
- ]}.
+{dialyzer, [{warnings, [error_handling, race_conditions, unmatched_returns, unknown, no_improper_lists]}]}.
 
 {profiles,
- [
-  {native,
-   [
-    {erl_opts, [{d, 'ENABLE_HIPE'}]}
-   ]},
-  {edown,
-   [
-    {edoc_opts,
-     [
-      {doclet, edown_doclet}
-     ]},
-    {deps,
-     [
-      edown
-     ]}
-   ]}
- ]}.
+ [{native, [{erl_opts, [{d, 'ENABLE_HIPE'}]}]}, {edown, [{edoc_opts, [{doclet, edown_doclet}]}, {deps, [edown]}]}]}.
 
 {project_plugins, [covertool]}.
 {cover_export_enabled, true}.

+ 9 - 8
src/jsone.app.src

@@ -1,8 +1,9 @@
-{application,jsone,
-             [{description,"Erlang JSON Library"},
-              {vsn,"1.7.0"},
-              {registered,[]},
-              {applications,[kernel,stdlib]},
-              {licenses,["MIT"]},
-              {links,[{"GitHub","https://github.com/sile/jsone"}]},
-              {env,[]}]}.
+{application,
+ jsone,
+ [{description, "Erlang JSON Library"},
+  {vsn, "1.7.0"},
+  {registered, []},
+  {applications, [kernel, stdlib]},
+  {licenses, ["MIT"]},
+  {links, [{"GitHub", "https://github.com/sile/jsone"}]},
+  {env, []}]}.

+ 59 - 54
src/jsone.erl

@@ -29,17 +29,18 @@
 %%--------------------------------------------------------------------------------
 %% Exported API
 %%--------------------------------------------------------------------------------
--export([
-         decode/1, decode/2,
-         try_decode/1, try_decode/2,
-         encode/1, encode/2,
-         try_encode/1, try_encode/2,
+-export([decode/1,
+         decode/2,
+         try_decode/1,
+         try_decode/2,
+         encode/1,
+         encode/2,
+         try_encode/1,
+         try_encode/2,
          term_to_json_string/1,
-         ip_address_to_json_string/1
-        ]).
+         ip_address_to_json_string/1]).
 
--export_type([
-              json_value/0,
+-export_type([json_value/0,
               json_boolean/0,
               json_number/0,
               json_string/0,
@@ -55,23 +56,30 @@
               encode_option/0,
               decode_option/0,
               float_format_option/0,
-              datetime_encode_format/0, datetime_format/0,
-              timezone/0, utc_offset_seconds/0, stack_item/0
-             ]).
+              datetime_encode_format/0,
+              datetime_format/0,
+              timezone/0,
+              utc_offset_seconds/0,
+              stack_item/0]).
 
 %%--------------------------------------------------------------------------------
 %% Types & Macros
 %%--------------------------------------------------------------------------------
--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
--type json_array()          :: [json_value()].
--type json_object()         :: json_object_format_tuple()
-                             | json_object_format_proplist()
-                             | json_object_format_map().
+-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
+-type json_array() :: [json_value()].
+-type json_object() :: json_object_format_tuple() | json_object_format_proplist() | json_object_format_map().
 -type json_object_members() :: [{json_string(), json_value()}].
--type json_term()           :: {{json, iolist()}} | {{json_utf8, unicode:chardata()}}.
+-type json_term() :: {{json, iolist()}} | {{json_utf8, unicode:chardata()}}.
 %% `json_term()' allows inline already encoded JSON value. `json' variant
 %% expects byte encoded utf8 data values as list members. `json_utf8' expect
 %% Unicode code points as list members. Binaries are copied "as is" in both
@@ -126,9 +134,7 @@
 
 -type json_scalar() :: json_boolean() | json_number() | json_string().
 
--type float_format_option() :: {scientific, Decimals :: 0..249}
-                             | {decimals, Decimals :: 0..253}
-                             | compact.
+-type float_format_option() :: {scientific, Decimals :: 0 .. 249} | {decimals, Decimals :: 0 .. 253} | compact.
 %% `scientific': <br />
 %% - The float will be formatted using scientific notation with `Decimals' digits of precision. <br />
 %%
@@ -155,8 +161,7 @@
 %% <<"1.23">>
 %% '''
 
--type datetime_encode_format() :: Format::datetime_format()
-                                | {Format::datetime_format(), TimeZone::timezone()}.
+-type datetime_encode_format() :: Format :: datetime_format() | {Format :: datetime_format(), TimeZone :: timezone()}.
 %% Datetime encoding format.
 %%
 %% The default value of `TimeZone' is `utc'.
@@ -183,24 +188,24 @@
 
 -type datetime_format() :: iso8601.
 -type timezone() :: utc | local | utc_offset_seconds().
--type utc_offset_seconds() :: -86399..86399.
+-type utc_offset_seconds() :: -86399 .. 86399.
 
 -type common_option() :: undefined_as_null.
 %%
 %% `undefined_as_null': <br />
 %% - Treats `undefined' in Erlang as the conversion target for `null' in JSON. This means that `undefined' will be encoded to `null' and `null' will be decoded to `undefined'<br />
 
--type encode_option() :: native_utf8
-                       | native_forward_slash
-                       | canonical_form
-                       | {float_format, [float_format_option()]}
-                       | {datetime_format, datetime_encode_format()}
-                       | {object_key_type, string | scalar | value}
-                       | {space, non_neg_integer()}
-                       | {indent, non_neg_integer()}
-                       | {map_unknown_value, undefined | fun ((term()) -> {ok, json_value()} | error)}
-                       | skip_undefined
-                       | common_option().
+-type encode_option() :: native_utf8 |
+                         native_forward_slash |
+                         canonical_form |
+                         {float_format, [float_format_option()]} |
+                         {datetime_format, datetime_encode_format()} |
+                         {object_key_type, string | scalar | value} |
+                         {space, non_neg_integer()} |
+                         {indent, non_neg_integer()} |
+                         {map_unknown_value, undefined | fun ((term()) -> {ok, json_value()} | error)} |
+                         skip_undefined |
+                         common_option().
 %% `native_utf8': <br />
 %% - Encodes non ASCII UTF-8 characters as a human-readable(non-escaped) string <br />
 %%
@@ -242,12 +247,12 @@
 %% - If `Fun' is `undefined', the encoding results in an error if there are unknown values. <br />
 %% - default: `term_to_json_string/1' <br />
 
--type decode_option() :: {object_format, tuple | proplist | map}
-                       | {allow_ctrl_chars, boolean()}
-                       | reject_invalid_utf8
-                       | {'keys', 'binary' | 'atom' | 'existing_atom' | 'attempt_atom'}
-                       | {duplicate_map_keys, first | last}
-                       | common_option().
+-type decode_option() :: {object_format, tuple | proplist | map} |
+                         {allow_ctrl_chars, boolean()} |
+                         reject_invalid_utf8 |
+                         {'keys', 'binary' | 'atom' | 'existing_atom' | 'attempt_atom'} |
+                         {duplicate_map_keys, first | last} |
+                         common_option().
 %% `object_format': <br />
 %% - Decoded JSON object format <br />
 %% - `tuple': An object is decoded as `{[]}' if it is empty, otherwise `{[{Key, Value}]}'. <br />
@@ -291,8 +296,7 @@
 -type stack_item() :: {Module :: module(),
                        Function :: atom(),
                        Arity :: arity() | (Args :: [term()]),
-                       Location :: [{file, Filename :: string()} |
-                                    {line, Line :: pos_integer()}]}.
+                       Location :: [{file, Filename :: string()} | {line, Line :: pos_integer()}]}.
 %% An item in a stack back-trace.
 %%
 %% Note that the `erlang' module already defines the same `stack_item/0' type,
@@ -338,12 +342,12 @@ decode(Json, Options) ->
         check_decode_remainings(Remainings),
         Value
     catch
-        error:{badmatch, {error, {Reason, [StackItem]}}} ?CAPTURE_STACKTRACE ->
+        error:{badmatch, {error, {Reason, [StackItem]}}} ?CAPTURE_STACKTRACE->
             erlang:raise(error, Reason, [StackItem | ?GET_STACKTRACE])
     end.
 
 %% @equiv try_decode(Json, [])
--spec try_decode(binary()) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [stack_item()]}}.
+-spec try_decode(binary()) -> {ok, json_value(), Remainings :: binary()} | {error, {Reason :: term(), [stack_item()]}}.
 try_decode(Json) ->
     try_decode(Json, []).
 
@@ -358,7 +362,8 @@ try_decode(Json) ->
 %%                               [<<"wrong json">>,1,[],<<>>],
 %%                               [{line,208}]}]}}
 %% '''
--spec try_decode(binary(), [decode_option()]) -> {ok, json_value(), Remainings::binary()} | {error, {Reason::term(), [stack_item()]}}.
+-spec try_decode(binary(), [decode_option()]) ->
+          {ok, json_value(), Remainings :: binary()} | {error, {Reason :: term(), [stack_item()]}}.
 try_decode(Json, Options) ->
     jsone_decode:decode(Json, Options).
 
@@ -387,12 +392,12 @@ encode(JsonValue, Options) ->
         {ok, Binary} = try_encode(JsonValue, Options),
         Binary
     catch
-        error:{badmatch, {error, {Reason, [StackItem]}}} ?CAPTURE_STACKTRACE ->
+        error:{badmatch, {error, {Reason, [StackItem]}}} ?CAPTURE_STACKTRACE->
             erlang:raise(error, Reason, [StackItem | ?GET_STACKTRACE])
     end.
 
 %% @equiv try_encode(JsonValue, [])
--spec try_encode(json_value()) -> {ok, binary()} | {error, {Reason::term(), [stack_item()]}}.
+-spec try_encode(json_value()) -> {ok, binary()} | {error, {Reason :: term(), [stack_item()]}}.
 try_encode(JsonValue) ->
     try_encode(JsonValue, []).
 
@@ -407,7 +412,7 @@ try_encode(JsonValue) ->
 %%                               [hoge,[{array_values,[2]}],<<"[1,">>],
 %%                               [{line,86}]}]}}
 %% '''
--spec try_encode(json_value(), [encode_option()]) -> {ok, binary()} | {error, {Reason::term(), [stack_item()]}}.
+-spec try_encode(json_value(), [encode_option()]) -> {ok, binary()} | {error, {Reason :: term(), [stack_item()]}}.
 try_encode(JsonValue, Options) ->
     jsone_encode:encode(JsonValue, Options).
 
@@ -439,7 +444,7 @@ term_to_json_string(X) ->
 %% > jsone:encode([foo, {0, 0, 0, 0, 0, 16#FFFF, 16#7F00, 16#0001}], EncodeOpt).
 %% <<"[\"foo\",\"::ffff:127.0.0.1\"]">>
 %% '''
--spec ip_address_to_json_string(inet:ip_address()|any()) -> {ok, json_string()} | error.
+-spec ip_address_to_json_string(inet:ip_address() | any()) -> {ok, json_string()} | error.
 ip_address_to_json_string(X) ->
     jsone_inet:ip_address_to_json_string(X).
 
@@ -449,7 +454,7 @@ ip_address_to_json_string(X) ->
 -spec check_decode_remainings(binary()) -> ok.
 check_decode_remainings(<<>>) ->
     ok;
-check_decode_remainings(<<$  , Bin/binary>>) ->
+check_decode_remainings(<<$ , Bin/binary>>) ->
     check_decode_remainings(Bin);
 check_decode_remainings(<<$\t, Bin/binary>>) ->
     check_decode_remainings(Bin);

+ 198 - 114
src/jsone_decode.erl

@@ -49,29 +49,27 @@
 -define(LIST_TO_MAP(X), maps:from_list(X)).
 -endif.
 
--type next() :: {array_next, [jsone:json_value()]}
-              | {object_value, jsone:json_object_members()}
-              | {object_next, jsone:json_string(), jsone:json_object_members()}.
+-type next() :: {array_next, [jsone:json_value()]} |
+                {object_value, jsone:json_object_members()} |
+                {object_next, jsone:json_string(), jsone:json_object_members()}.
 
--type whitespace_next() :: value
-                         | array
-                         | object
-                         | {array_next, [jsone:json_value()]}
-                         | {object_key, jsone:json_object_members()}
-                         | {object_value, jsone:json_string(), jsone:json_object_members()}
-                         | {object_next, jsone:json_object_members()}.
+-type whitespace_next() :: value |
+                           array |
+                           object |
+                           {array_next, [jsone:json_value()]} |
+                           {object_key, jsone:json_object_members()} |
+                           {object_value, jsone:json_string(), jsone:json_object_members()} |
+                           {object_next, jsone:json_object_members()}.
 
--type decode_result() :: {ok, jsone:json_value(), Rest::binary()} | {error, {Reason::term(), [jsone:stack_item()]}}.
+-type decode_result() :: {ok, jsone:json_value(), Rest :: binary()} | {error, {Reason :: term(), [jsone:stack_item()]}}.
 
 -record(decode_opt_v2,
-        {
-          object_format=?DEFAULT_OBJECT_FORMAT :: tuple | proplist | map,
-          allow_ctrl_chars=false :: boolean(),
-          reject_invalid_utf8=false :: boolean(),
-          keys=binary :: 'binary' | 'atom' | 'existing_atom' | 'attempt_atom',
-          undefined_as_null=false :: boolean(),
-          duplicate_map_keys=first :: first | last
-        }).
+        {object_format = ?DEFAULT_OBJECT_FORMAT :: tuple | proplist | map,
+         allow_ctrl_chars = false :: boolean(),
+         reject_invalid_utf8 = false :: boolean(),
+         keys = binary :: 'binary' | 'atom' | 'existing_atom' | 'attempt_atom',
+         undefined_as_null = false :: boolean(),
+         duplicate_map_keys = first :: first | last}).
 -define(OPT, #decode_opt_v2).
 -type opt() :: #decode_opt_v2{}.
 
@@ -95,73 +93,114 @@ next(<<Bin/binary>>, Value, [], _Buf, _Opt) ->
     {ok, Value, Bin};
 next(<<Bin/binary>>, Value, [Next | Nexts], Buf, Opt) ->
     case Next of
-        {array_next, Values}        -> whitespace(Bin, {array_next, [Value | Values]}, Nexts, Buf, Opt);
-        {object_value, Members}     -> whitespace(Bin, {object_value, Value, Members}, Nexts, Buf, Opt);
-        {object_next, Key, Members} -> whitespace(Bin, {object_next, [{Key, Value} | Members]}, Nexts, Buf, Opt)
+        {array_next, Values} ->
+            whitespace(Bin, {array_next, [Value | Values]}, Nexts, Buf, Opt);
+        {object_value, Members} ->
+            whitespace(Bin, {object_value, Value, Members}, Nexts, Buf, Opt);
+        {object_next, Key, Members} ->
+            whitespace(Bin, {object_next, [{Key, Value} | Members]}, Nexts, Buf, Opt)
     end.
 
 -spec whitespace(binary(), whitespace_next(), [next()], binary(), opt()) -> decode_result().
-whitespace(<<$  , Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
-whitespace(<<$\t, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
-whitespace(<<$\r, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
-whitespace(<<$\n, Bin/binary>>, Next, Nexts, Buf, Opt) -> whitespace(Bin, Next, Nexts, Buf, Opt);
-whitespace(<<Bin/binary>>,      Next, Nexts, Buf, Opt) ->
+whitespace(<<$ , Bin/binary>>, Next, Nexts, Buf, Opt) ->
+    whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<$\t, Bin/binary>>, Next, Nexts, Buf, Opt) ->
+    whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<$\r, Bin/binary>>, Next, Nexts, Buf, Opt) ->
+    whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<$\n, Bin/binary>>, Next, Nexts, Buf, Opt) ->
+    whitespace(Bin, Next, Nexts, Buf, Opt);
+whitespace(<<Bin/binary>>, Next, Nexts, Buf, Opt) ->
     case Next of
-        value  -> value(Bin, Nexts, Buf, Opt);
-        array  -> array(Bin, Nexts, Buf, Opt);
-        object -> object(Bin, Nexts, Buf, Opt);
-        {object_key, Members}        -> object_key(Bin, Members, Nexts, Buf, Opt);
-        {array_next, Values}         -> array_next(Bin, Values, Nexts, Buf, Opt);
-        {object_value, Key, Members} -> object_value(Bin, Key, Members, Nexts, Buf, Opt);
-        {object_next, Members}       -> object_next(Bin, Members, Nexts, Buf, Opt)
+        value ->
+            value(Bin, Nexts, Buf, Opt);
+        array ->
+            array(Bin, Nexts, Buf, Opt);
+        object ->
+            object(Bin, Nexts, Buf, Opt);
+        {object_key, Members} ->
+            object_key(Bin, Members, Nexts, Buf, Opt);
+        {array_next, Values} ->
+            array_next(Bin, Values, Nexts, Buf, Opt);
+        {object_value, Key, Members} ->
+            object_value(Bin, Key, Members, Nexts, Buf, Opt);
+        {object_next, Members} ->
+            object_next(Bin, Members, Nexts, Buf, Opt)
     end.
 
 -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);
-value(<<$", Bin/binary>>, Nexts, Buf, Opt)      -> string(Bin, byte_size(Buf), Nexts, Buf, Opt);
-value(<<Bin/binary>>, Nexts, Buf, Opt)          -> number(Bin, Nexts, Buf, Opt).
+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);
+value(<<$", Bin/binary>>, Nexts, Buf, Opt) ->
+    string(Bin, byte_size(Buf), Nexts, Buf, Opt);
+value(<<Bin/binary>>, Nexts, Buf, Opt) ->
+    number(Bin, Nexts, Buf, Opt).
 
 -spec array(binary(), [next()], binary(), opt()) -> decode_result().
-array(<<$], Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, [], Nexts, Buf, Opt);
-array(<<Bin/binary>>, Nexts, Buf, Opt)     -> value(Bin, [{array_next, []} | Nexts], Buf, Opt).
+array(<<$], Bin/binary>>, Nexts, Buf, Opt) ->
+    next(Bin, [], Nexts, Buf, Opt);
+array(<<Bin/binary>>, Nexts, Buf, Opt) ->
+    value(Bin, [{array_next, []} | Nexts], Buf, Opt).
 
 -spec array_next(binary(), [jsone:json_value()], [next()], binary(), opt()) -> decode_result().
-array_next(<<$], Bin/binary>>, Values, Nexts, Buf, Opt) -> next(Bin, lists:reverse(Values), Nexts, Buf, Opt);
-array_next(<<$,, Bin/binary>>, Values, Nexts, Buf, Opt) -> whitespace(Bin, value, [{array_next, Values} | Nexts], Buf, Opt);
-array_next(Bin,                Values, Nexts, Buf, Opt) -> ?ERROR(array_next, [Bin, Values, Nexts, Buf, Opt]).
+array_next(<<$], Bin/binary>>, Values, Nexts, Buf, Opt) ->
+    next(Bin, lists:reverse(Values), Nexts, Buf, Opt);
+array_next(<<$,, Bin/binary>>, Values, Nexts, Buf, Opt) ->
+    whitespace(Bin, value, [{array_next, Values} | Nexts], Buf, Opt);
+array_next(Bin, Values, Nexts, Buf, Opt) ->
+    ?ERROR(array_next, [Bin, Values, Nexts, Buf, Opt]).
 
 -spec object(binary(), [next()], binary(), opt()) -> decode_result().
-object(<<$}, Bin/binary>>, Nexts, Buf, Opt) -> next(Bin, make_object([], Opt), Nexts, Buf, Opt);
-object(<<Bin/binary>>, Nexts, Buf, Opt)     -> object_key(Bin, [], Nexts, Buf, Opt).
+object(<<$}, Bin/binary>>, Nexts, Buf, Opt) ->
+    next(Bin, make_object([], Opt), Nexts, Buf, Opt);
+object(<<Bin/binary>>, Nexts, Buf, Opt) ->
+    object_key(Bin, [], Nexts, Buf, Opt).
 
 -spec object_key(binary(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
-object_key(<<$", Bin/binary>>, Members, Nexts, Buf, Opt) -> string(Bin, byte_size(Buf), [{object_value, Members} | Nexts], Buf, Opt);
-object_key(<<Bin/binary>>, Members, Nexts, Buf, Opt)     -> ?ERROR(object_key, [Bin, Members, Nexts, Buf, Opt]).
+object_key(<<$", Bin/binary>>, Members, Nexts, Buf, Opt) ->
+    string(Bin, byte_size(Buf), [{object_value, Members} | Nexts], Buf, Opt);
+object_key(<<Bin/binary>>, Members, Nexts, Buf, Opt) ->
+    ?ERROR(object_key, [Bin, Members, Nexts, Buf, Opt]).
 
--spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
+-spec object_value(binary(), jsone:json_string(), jsone:json_object_members(), [next()], binary(), opt()) ->
+          decode_result().
 object_value(<<$:, Bin/binary>>, Key, Members, Nexts, Buf, Opt) ->
     whitespace(Bin, value, [{object_next, object_key(Key, Opt), Members} | Nexts], Buf, Opt);
-object_value(Bin,                Key, Members, Nexts, Buf, Opt) -> ?ERROR(object_value, [Bin, Key, Members, Nexts, Buf, Opt]).
+object_value(Bin, Key, Members, Nexts, Buf, Opt) ->
+    ?ERROR(object_value, [Bin, Key, Members, Nexts, Buf, Opt]).
 
 -compile({inline, [object_key/2]}).
-object_key(Key, ?OPT{keys = binary}) -> Key;
-object_key(Key, ?OPT{keys = atom}) -> binary_to_atom(Key, utf8);
-object_key(Key, ?OPT{keys = existing_atom}) -> binary_to_existing_atom(Key, utf8);
+object_key(Key, ?OPT{keys = binary}) ->
+    Key;
+object_key(Key, ?OPT{keys = atom}) ->
+    binary_to_atom(Key, utf8);
+object_key(Key, ?OPT{keys = existing_atom}) ->
+    binary_to_existing_atom(Key, utf8);
 object_key(Key, ?OPT{keys = attempt_atom}) ->
-    try binary_to_existing_atom(Key, utf8)
-    catch error:badarg -> Key
+    try
+        binary_to_existing_atom(Key, utf8)
+    catch
+        error:badarg ->
+            Key
     end.
 
 -spec object_next(binary(), jsone:json_object_members(), [next()], binary(), opt()) -> decode_result().
-object_next(<<$}, Bin/binary>>, Members, Nexts, Buf, Opt) -> next(Bin, make_object(Members, Opt), Nexts, Buf, Opt);
-object_next(<<$,, Bin/binary>>, Members, Nexts, Buf, Opt) -> whitespace(Bin, {object_key, Members}, Nexts, Buf, Opt);
-object_next(Bin,                Members, Nexts, Buf, Opt) -> ?ERROR(object_next, [Bin, Members, Nexts, Buf, Opt]).
+object_next(<<$}, Bin/binary>>, Members, Nexts, Buf, Opt) ->
+    next(Bin, make_object(Members, Opt), Nexts, Buf, Opt);
+object_next(<<$,, Bin/binary>>, Members, Nexts, Buf, Opt) ->
+    whitespace(Bin, {object_key, Members}, Nexts, Buf, Opt);
+object_next(Bin, Members, Nexts, Buf, Opt) ->
+    ?ERROR(object_next, [Bin, Members, Nexts, Buf, Opt]).
 
 -spec string(binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
 string(<<Bin/binary>>, Start, Nexts, Buf, Opt) ->
@@ -171,7 +210,8 @@ string(<<Bin/binary>>, Start, Nexts, Buf, Opt) ->
 string(<<$", Bin/binary>>, Base, Start, Nexts, Buf, Opt) ->
     Prefix = binary:part(Base, 0, byte_size(Base) - byte_size(Bin) - 1),
     case Start =:= byte_size(Buf) of
-        true  -> next(Bin, Prefix, Nexts, Buf, Opt);
+        true ->
+            next(Bin, Prefix, Nexts, Buf, Opt);
         false ->
             Buf2 = <<Buf/binary, Prefix/binary>>,
             next(Bin, binary:part(Buf2, Start, byte_size(Buf2) - Start), Nexts, Buf2, Opt)
@@ -179,18 +219,29 @@ string(<<$", Bin/binary>>, Base, Start, Nexts, Buf, Opt) ->
 string(<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt) ->
     Prefix = binary:part(Base, 0, byte_size(Base) - byte_size(B) - 1),
     case B of
-        <<$", Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $">>, Opt);
-        <<$/, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $/>>, Opt);
-        <<$\\,Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\\>>, Opt);
-        <<$b, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\b>>, Opt);
-        <<$f, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\f>>, Opt);
-        <<$n, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\n>>, Opt);
-        <<$r, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\r>>, Opt);
-        <<$t, Bin/binary>> -> string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\t>>, Opt);
-        <<$u, Bin/binary>> -> unicode_string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary>>, Opt);
-        _                  -> ?ERROR(string, [<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt])
+        <<$", Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $">>, Opt);
+        <<$/, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $/>>, Opt);
+        <<$\\, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\\>>, Opt);
+        <<$b, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\b>>, Opt);
+        <<$f, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\f>>, Opt);
+        <<$n, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\n>>, Opt);
+        <<$r, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\r>>, Opt);
+        <<$t, Bin/binary>> ->
+            string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary, $\t>>, Opt);
+        <<$u, Bin/binary>> ->
+            unicode_string(Bin, Start, Nexts, <<Buf/binary, Prefix/binary>>, Opt);
+        _ ->
+            ?ERROR(string, [<<$\\, B/binary>>, Base, Start, Nexts, Buf, Opt])
     end;
-string(<<_, Bin/binary>>, Base, Start, Nexts, Buf, Opt) when Opt?OPT.allow_ctrl_chars, not Opt?OPT.reject_invalid_utf8 ->
+string(<<_, Bin/binary>>, Base, Start, Nexts, Buf, Opt)
+  when Opt?OPT.allow_ctrl_chars, not Opt?OPT.reject_invalid_utf8 ->
     string(Bin, Base, Start, Nexts, Buf, Opt);
 string(<<C, Bin/binary>>, Base, Start, Nexts, Buf, Opt) when 16#20 =< C, not Opt?OPT.reject_invalid_utf8 ->
     string(Bin, Base, Start, Nexts, Buf, Opt);
@@ -199,39 +250,53 @@ string(<<_/utf8, Bin/binary>>, Base, Start, Nexts, Buf, Opt) when Opt?OPT.allow_
 string(<<C/utf8, Bin/binary>>, Base, Start, Nexts, Buf, Opt) when 16#20 =< C ->
     string(Bin, Base, Start, Nexts, Buf, Opt);
 string(Bin, Base, Start, Nexts, Buf, Opt) ->
-     ?ERROR(string, [Bin, Base, Start, Nexts, Buf, Opt]).
+    ?ERROR(string, [Bin, Base, Start, Nexts, Buf, Opt]).
 
 -spec unicode_string(binary(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
 unicode_string(<<N:4/binary, Bin/binary>>, Start, Nexts, Buf, Opt) ->
-    try binary_to_integer(N, 16) of
+    try
+        binary_to_integer(N, 16)
+    of
         High when 16#D800 =< High, High =< 16#DBFF ->
             %% surrogate pair
             case Bin of
                 <<$\\, $u, N2:4/binary, Bin2/binary>> ->
-                    try binary_to_integer(N2, 16) of
+                    try
+                        binary_to_integer(N2, 16)
+                    of
                         Low when 16#DC00 =< Low, Low =< 16#DFFF ->
                             <<Unicode/utf16>> = <<High:16, Low:16>>,
                             string(Bin2, Start, Nexts, <<Buf/binary, Unicode/utf8>>, Opt);
-                        _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
-                    catch error:badarg -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
+                        _ ->
+                            ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
+                    catch
+                        error:badarg ->
+                            ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
                     end;
-                _ -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
+                _ ->
+                    ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
             end;
-        Unicode when 16#DC00 =< Unicode, Unicode =< 16#DFFF;  % second part of surrogate pair (without first part)
-                     0 > Unicode ->
+        Unicode
+          when 16#DC00 =< Unicode,
+               Unicode =< 16#DFFF;  % second part of surrogate pair (without first part)
+               0 > Unicode ->
             ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt]);
         Unicode ->
             string(Bin, Start, Nexts, <<Buf/binary, Unicode/utf8>>, Opt)
-    catch error:badarg -> ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
+    catch
+        error:badarg ->
+            ?ERROR(unicode_string, [<<N/binary, Bin/binary>>, Start, Nexts, Buf, Opt])
     end;
 unicode_string(Bin, Start, Nexts, Buf, Opt) ->
     ?ERROR(unicode_string, [Bin, Start, Nexts, Buf, Opt]).
 
 -spec number(binary(), [next()], binary(), opt()) -> decode_result().
-number(<<$-, Bin/binary>>, Nexts, Buf, Opt) -> number_integer_part(Bin, -1, Nexts, Buf, Opt);
-number(<<Bin/binary>>,     Nexts, Buf, Opt) -> number_integer_part(Bin,  1, Nexts, Buf, Opt).
+number(<<$-, Bin/binary>>, Nexts, Buf, Opt) ->
+    number_integer_part(Bin, -1, Nexts, Buf, Opt);
+number(<<Bin/binary>>, Nexts, Buf, Opt) ->
+    number_integer_part(Bin, 1, Nexts, Buf, Opt).
 
--spec number_integer_part(binary(), 1|-1, [next()], binary(), opt()) -> decode_result().
+-spec number_integer_part(binary(), 1 | -1, [next()], binary(), opt()) -> decode_result().
 number_integer_part(<<$0, Bin/binary>>, Sign, Nexts, Buf, Opt) ->
     number_fraction_part(Bin, Sign, 0, Nexts, Buf, Opt);
 number_integer_part(<<C, Bin/binary>>, Sign, Nexts, Buf, Opt) when $1 =< C, C =< $9 ->
@@ -239,19 +304,20 @@ number_integer_part(<<C, Bin/binary>>, Sign, Nexts, Buf, Opt) when $1 =< C, C =<
 number_integer_part(Bin, Sign, Nexts, Buf, Opt) ->
     ?ERROR(number_integer_part, [Bin, Sign, Nexts, Buf, Opt]).
 
--spec number_integer_part_rest(binary(), non_neg_integer(), 1|-1, [next()], binary(), opt()) -> decode_result().
+-spec number_integer_part_rest(binary(), non_neg_integer(), 1 | -1, [next()], binary(), opt()) -> decode_result().
 number_integer_part_rest(<<C, Bin/binary>>, N, Sign, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
     number_integer_part_rest(Bin, N * 10 + C - $0, Sign, Nexts, Buf, Opt);
 number_integer_part_rest(<<Bin/binary>>, N, Sign, Nexts, Buf, Opt) ->
     number_fraction_part(Bin, Sign, N, Nexts, Buf, Opt).
 
--spec number_fraction_part(binary(), 1|-1, non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+-spec number_fraction_part(binary(), 1 | -1, non_neg_integer(), [next()], binary(), opt()) -> decode_result().
 number_fraction_part(<<$., Bin/binary>>, Sign, Int, Nexts, Buf, Opt) ->
     number_fraction_part_rest(Bin, Sign, Int, 0, Nexts, Buf, Opt);
 number_fraction_part(<<Bin/binary>>, Sign, Int, Nexts, Buf, Opt) ->
     number_exponation_part(Bin, Sign * Int, 0, Nexts, Buf, Opt).
 
--spec number_fraction_part_rest(binary(), 1|-1, non_neg_integer(), non_neg_integer(), [next()], binary(), opt()) -> decode_result().
+-spec number_fraction_part_rest(binary(), 1 | -1, non_neg_integer(), non_neg_integer(), [next()], binary(), opt()) ->
+          decode_result().
 number_fraction_part_rest(<<C, Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
     number_fraction_part_rest(Bin, Sign, N * 10 + C - $0, DecimalOffset + 1, Nexts, Buf, Opt);
 number_fraction_part_rest(<<Bin/binary>>, Sign, N, DecimalOffset, Nexts, Buf, Opt) when DecimalOffset > 0 ->
@@ -274,54 +340,72 @@ number_exponation_part(<<$E, Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
     number_exponation_part(Bin, N, DecimalOffset, 1, 0, true, Nexts, Buf, Opt);
 number_exponation_part(<<Bin/binary>>, N, DecimalOffset, Nexts, Buf, Opt) ->
     case DecimalOffset of
-        0 -> next(Bin, N, Nexts, Buf, Opt);
-        _ -> next(Bin, N / math:pow(10, DecimalOffset), Nexts, Buf, Opt)
+        0 ->
+            next(Bin, N, Nexts, Buf, Opt);
+        _ ->
+            next(Bin, N / math:pow(10, DecimalOffset), Nexts, Buf, Opt)
     end.
 
--spec number_exponation_part(binary(), integer(), non_neg_integer(), 1|-1, non_neg_integer(), boolean(), [next()], binary(), opt()) -> decode_result().
+-spec number_exponation_part(binary(),
+                             integer(),
+                             non_neg_integer(),
+                             1 | -1,
+                             non_neg_integer(),
+                             boolean(),
+                             [next()],
+                             binary(),
+                             opt()) -> decode_result().
 number_exponation_part(<<C, Bin/binary>>, N, DecimalOffset, ExpSign, Exp, _, Nexts, Buf, Opt) when $0 =< C, C =< $9 ->
     number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp * 10 + C - $0, false, Nexts, Buf, Opt);
 number_exponation_part(<<Bin/binary>>, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf, Opt) ->
     Pos = ExpSign * Exp - DecimalOffset,
     try
         case Pos of
-            Pos when Pos >= 0 -> N * math:pow(10, Pos);
-            _                 -> N / math:pow(10, -Pos) % multiplying by decimal makes float errors larger.
+            Pos when Pos >= 0 ->
+                N * math:pow(10, Pos);
+            _ ->
+                N / math:pow(10, -Pos)  % multiplying by decimal makes float errors larger.
         end
-    of Res -> next(Bin, Res, Nexts, Buf, Opt)
-    catch error:badarith ->
-        ?ERROR(number_exponation_part, [Bin, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf, Opt])
+    of
+        Res ->
+            next(Bin, Res, Nexts, Buf, Opt)
+    catch
+        error:badarith ->
+            ?ERROR(number_exponation_part, [Bin, N, DecimalOffset, ExpSign, Exp, false, Nexts, Buf, Opt])
     end;
 number_exponation_part(Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf, Opt) ->
     ?ERROR(number_exponation_part, [Bin, N, DecimalOffset, ExpSign, Exp, IsFirst, Nexts, Buf, Opt]).
 
 -spec make_object(jsone:json_object_members(), opt()) -> jsone:json_object().
-make_object(Members, ?OPT{object_format = tuple}) -> {lists:reverse(Members)};
+make_object(Members, ?OPT{object_format = tuple}) ->
+    {lists:reverse(Members)};
 make_object(Members, ?OPT{object_format = map, duplicate_map_keys = last}) ->
     ?LIST_TO_MAP(lists:reverse(Members));
-make_object(Members, ?OPT{object_format = map})   -> ?LIST_TO_MAP(Members);
-make_object([],      _)                           -> [{}];
-make_object(Members, _)                           -> lists:reverse(Members).
+make_object(Members, ?OPT{object_format = map}) ->
+    ?LIST_TO_MAP(Members);
+make_object([], _) ->
+    [{}];
+make_object(Members, _) ->
+    lists:reverse(Members).
 
 -spec parse_options([jsone:decode_option()]) -> opt().
 parse_options(Options) ->
     parse_option(Options, ?OPT{}).
 
 -spec parse_option([jsone:decode_option()], opt()) -> opt().
-parse_option([], Opt) -> Opt;
-parse_option([{object_format,F}|T], Opt) when F =:= tuple; F =:= proplist; F =:= map ->
-    parse_option(T, Opt?OPT{object_format=F});
-parse_option([{allow_ctrl_chars,B}|T], Opt) when is_boolean(B) ->
-    parse_option(T, Opt?OPT{allow_ctrl_chars=B});
-parse_option([reject_invalid_utf8|T], Opt) ->
-    parse_option(T, Opt?OPT{reject_invalid_utf8=true});
-parse_option([{keys, K}|T], Opt)
-  when K =:= binary; K =:= atom; K =:= existing_atom; K =:= attempt_atom ->
+parse_option([], Opt) ->
+    Opt;
+parse_option([{object_format, F} | T], Opt) when F =:= tuple; F =:= proplist; F =:= map ->
+    parse_option(T, Opt?OPT{object_format = F});
+parse_option([{allow_ctrl_chars, B} | T], Opt) when is_boolean(B) ->
+    parse_option(T, Opt?OPT{allow_ctrl_chars = B});
+parse_option([reject_invalid_utf8 | T], Opt) ->
+    parse_option(T, Opt?OPT{reject_invalid_utf8 = true});
+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([undefined_as_null | T], Opt) ->
     parse_option(T, Opt?OPT{undefined_as_null = true});
-parse_option([{duplicate_map_keys, V} | T], Opt)
-  when V =:= first; V =:= last ->
-    parse_option(T, Opt?OPT{duplicate_map_keys=V});
+parse_option([{duplicate_map_keys, V} | T], Opt) when V =:= first; V =:= last ->
+    parse_option(T, Opt?OPT{duplicate_map_keys = V});
 parse_option(List, Opt) ->
     error(badarg, [List, Opt]).

+ 289 - 226
src/jsone_encode.erl

@@ -42,10 +42,10 @@
 -define(ERROR(Function, Args), {error, {badarg, [{?MODULE, Function, Args, [{line, ?LINE}]}]}}).
 -define(IS_STR(X), (is_binary(X) orelse is_atom(X))).
 -define(IS_UINT(X), (is_integer(X) andalso X >= 0)).
--define(IS_PNUM(X), (is_number(X) andalso X >=0)).
--define(IS_DATETIME(Y,M,D,H,Mi,S), (?IS_UINT(Y) andalso ?IS_UINT(M) andalso ?IS_UINT(D) andalso
-                                    ?IS_UINT(H) andalso ?IS_UINT(Mi) andalso
-                                    ?IS_PNUM(S))).
+-define(IS_PNUM(X), (is_number(X) andalso X >= 0)).
+-define(IS_DATETIME(Y, M, D, H, Mi, S),
+        (?IS_UINT(Y) andalso ?IS_UINT(M) andalso ?IS_UINT(D) andalso ?IS_UINT(H) andalso ?IS_UINT(Mi) andalso
+         ?IS_PNUM(S))).
 
 -ifdef('NO_MAP_TYPE').
 -define(IS_MAP(X), is_tuple(X)).
@@ -55,25 +55,25 @@
 -define(ENCODE_MAP(Value, Nexts, Buf, Opt), object(maps:to_list(Value), Nexts, Buf, Opt)).
 -endif.
 
--type encode_result() :: {ok, binary()} | {error, {Reason::term(), [jsone:stack_item()]}}.
--type next() :: {array_values, [jsone:json_value()]}
-              | {object_value, jsone:json_value(), jsone:json_object_members()}
-              | {object_members, jsone:json_object_members()}
-              | {char, binary()}.
-
--record(encode_opt_v2, {
-          native_utf8 = false :: boolean(),
-          native_forward_slash = false :: boolean(),
-          canonical_form = false :: boolean(),
-          float_format = [{scientific, 20}] :: [jsone:float_format_option()],
-          datetime_format = {iso8601, 0} :: {jsone:datetime_format(), jsone:utc_offset_seconds()},
-          object_key_type = string :: string | scalar | value,
-          space = 0 :: non_neg_integer(),
-          indent = 0 :: non_neg_integer(),
-          undefined_as_null = false :: boolean(),
-          skip_undefined = false :: boolean(),
-          map_unknown_value = fun jsone:term_to_json_string/1 :: undefined | fun ((term()) -> {ok, jsone:json_value()} | error)
-         }).
+-type encode_result() :: {ok, binary()} | {error, {Reason :: term(), [jsone:stack_item()]}}.
+-type next() :: {array_values, [jsone:json_value()]} |
+                {object_value, jsone:json_value(), jsone:json_object_members()} |
+                {object_members, jsone:json_object_members()} |
+                {char, binary()}.
+
+-record(encode_opt_v2,
+        {native_utf8 = false :: boolean(),
+         native_forward_slash = false :: boolean(),
+         canonical_form = false :: boolean(),
+         float_format = [{scientific, 20}] :: [jsone:float_format_option()],
+         datetime_format = {iso8601, 0} :: {jsone:datetime_format(), jsone:utc_offset_seconds()},
+         object_key_type = string :: string | scalar | value,
+         space = 0 :: non_neg_integer(),
+         indent = 0 :: non_neg_integer(),
+         undefined_as_null = false :: boolean(),
+         skip_undefined = false :: boolean(),
+         map_unknown_value = fun jsone:term_to_json_string/1 :: undefined |
+                                                                fun ((term()) -> {ok, jsone:json_value()} | error)}).
 -define(OPT, #encode_opt_v2).
 -type opt() :: #encode_opt_v2{}.
 
@@ -93,64 +93,90 @@ encode(Value, Options) ->
 %% Internal Functions
 %%--------------------------------------------------------------------------------
 -spec next([next()], binary(), opt()) -> encode_result().
-next([], Buf, _)                       -> {ok, Buf};
+next([], Buf, _) ->
+    {ok, Buf};
 next(Level = [Next | Nexts], Buf, Opt) ->
     case Next of
         {array_values, Values} ->
             case Values of
-                [] -> array_values(Values, Nexts, Buf, Opt);
-                _  -> array_values(Values, Nexts, pp_newline_or_space(<<Buf/binary, $,>>, Level, Opt), Opt)
+                [] ->
+                    array_values(Values, Nexts, Buf, Opt);
+                _ ->
+                    array_values(Values, Nexts, pp_newline_or_space(<<Buf/binary, $,>>, Level, Opt), Opt)
             end;
         {object_value, Value, Members} ->
             object_value(Value, Members, Nexts, pp_space(<<Buf/binary, $:>>, Opt), Opt);
         {object_members, Members} ->
             case Members of
-                [] -> object_members(Members, Nexts, Buf, Opt);
-                _  -> object_members(Members, Nexts, pp_newline_or_space(<<Buf/binary, $,>>, Level, Opt), Opt)
+                [] ->
+                    object_members(Members, Nexts, Buf, Opt);
+                _ ->
+                    object_members(Members, Nexts, pp_newline_or_space(<<Buf/binary, $,>>, Level, Opt), Opt)
             end;
         {char, C} ->
             next(Nexts, <<Buf/binary, C>>, Opt)
     end.
 
 -spec value(jsone:json_value(), [next()], binary(), opt()) -> encode_result().
-value(null, Nexts, Buf, Opt)                         -> next(Nexts, <<Buf/binary, "null">>, Opt);
-value(undefined, Nexts, Buf, Opt = ?OPT{undefined_as_null = true}) -> next(Nexts, <<Buf/binary, "null">>, Opt);
-value(false, Nexts, Buf, Opt)                        -> next(Nexts, <<Buf/binary, "false">>, Opt);
-value(true, Nexts, Buf, Opt)                         -> next(Nexts, <<Buf/binary, "true">>, Opt);
+value(null, Nexts, Buf, Opt) ->
+    next(Nexts, <<Buf/binary, "null">>, Opt);
+value(undefined, Nexts, Buf, Opt = ?OPT{undefined_as_null = true}) ->
+    next(Nexts, <<Buf/binary, "null">>, Opt);
+value(false, Nexts, Buf, Opt) ->
+    next(Nexts, <<Buf/binary, "false">>, Opt);
+value(true, Nexts, Buf, Opt) ->
+    next(Nexts, <<Buf/binary, "true">>, Opt);
 value({{json, T}}, Nexts, Buf, Opt) ->
     try
         next(Nexts, <<Buf/binary, (iolist_to_binary(T))/binary>>, Opt)
     catch
-         error:badarg ->
+        error:badarg ->
             ?ERROR(value, [{json, T}, Nexts, Buf, Opt])
     end;
 value({{json_utf8, T}}, Nexts, Buf, Opt) ->
-    try unicode:characters_to_binary(T) of
+    try
+        unicode:characters_to_binary(T)
+    of
         {error, OK, Invalid} ->
-            {error, {{invalid_json_utf8, OK, Invalid}, [{?MODULE, value, [{json_utf8, T}, Nexts, Buf, Opt], [{line, ?LINE}]}]}};
+            {error,
+             {{invalid_json_utf8, OK, Invalid},
+              [{?MODULE, value, [{json_utf8, T}, Nexts, Buf, Opt], [{line, ?LINE}]}]}};
         B when is_binary(B) ->
             next(Nexts, <<Buf/binary, B/binary>>, Opt)
     catch
         error:badarg ->
             ?ERROR(value, [{json_utf8, T}, Nexts, Buf, Opt])
     end;
-value(Value, Nexts, Buf, Opt) when is_integer(Value) -> next(Nexts, <<Buf/binary, (integer_to_binary(Value))/binary>>, Opt);
-value(Value, Nexts, Buf, Opt) when is_float(Value)   -> next(Nexts, <<Buf/binary, (float_to_binary(Value, Opt?OPT.float_format))/binary>>, Opt);
-value(Value, Nexts, Buf, Opt) when ?IS_STR(Value)    -> string(Value, Nexts, Buf, Opt);
-value({{_,_,_},{_,_,_}} = Value, Nexts, Buf, Opt)    -> datetime(Value, Nexts, Buf, Opt);
-value({Value}, Nexts, Buf, Opt) when is_list(Value)  -> object(Value, Nexts, Buf, Opt);
-value([{}], Nexts, Buf, Opt)                         -> object([], Nexts, Buf, Opt);
-value([{{_,_,_},{_,_,_}}|_] = Value, Nexts, Buf, Opt)-> array(Value, Nexts, Buf, Opt);
-value([{_, _}|_] = Value, Nexts, Buf, Opt)           -> object(Value, Nexts, Buf, Opt);
-value(Value, Nexts, Buf, Opt) when ?IS_MAP(Value)    -> ?ENCODE_MAP(Value, Nexts, Buf, Opt);
-value(Value, Nexts, Buf, Opt) when is_list(Value)    -> array(Value, Nexts, Buf, Opt);
-value(Value, Nexts, Buf, Opt)                        ->
+value(Value, Nexts, Buf, Opt) when is_integer(Value) ->
+    next(Nexts, <<Buf/binary, (integer_to_binary(Value))/binary>>, Opt);
+value(Value, Nexts, Buf, Opt) when is_float(Value) ->
+    next(Nexts, <<Buf/binary, (float_to_binary(Value, Opt?OPT.float_format))/binary>>, Opt);
+value(Value, Nexts, Buf, Opt) when ?IS_STR(Value) ->
+    string(Value, Nexts, Buf, Opt);
+value({{_, _, _}, {_, _, _}} = Value, Nexts, Buf, Opt) ->
+    datetime(Value, Nexts, Buf, Opt);
+value({Value}, Nexts, Buf, Opt) when is_list(Value) ->
+    object(Value, Nexts, Buf, Opt);
+value([{}], Nexts, Buf, Opt) ->
+    object([], Nexts, Buf, Opt);
+value([{{_, _, _}, {_, _, _}} | _] = Value, Nexts, Buf, Opt) ->
+    array(Value, Nexts, Buf, Opt);
+value([{_, _} | _] = Value, Nexts, Buf, Opt) ->
+    object(Value, Nexts, Buf, Opt);
+value(Value, Nexts, Buf, Opt) when ?IS_MAP(Value) ->
+    ?ENCODE_MAP(Value, Nexts, Buf, Opt);
+value(Value, Nexts, Buf, Opt) when is_list(Value) ->
+    array(Value, Nexts, Buf, Opt);
+value(Value, Nexts, Buf, Opt) ->
     case Opt?OPT.map_unknown_value of
-        undefined -> ?ERROR(value, [Value, Nexts, Buf, Opt]);
-        Fun       ->
+        undefined ->
+            ?ERROR(value, [Value, Nexts, Buf, Opt]);
+        Fun ->
             case Fun(Value) of
-                error          -> ?ERROR(value, [Value, Nexts, Buf, Opt]);
-                {ok, NewValue} -> value(NewValue, Nexts, Buf, Opt)
+                error ->
+                    ?ERROR(value, [Value, Nexts, Buf, Opt]);
+                {ok, NewValue} ->
+                    value(NewValue, Nexts, Buf, Opt)
             end
     end.
 
@@ -163,12 +189,21 @@ string(Str, Nexts, Buf, Opt) ->
     string(atom_to_binary(Str, utf8), Nexts, Buf, Opt).
 
 -spec datetime(calendar:datetime(), [next()], binary(), opt()) -> encode_result().
-datetime({{Y,M,D}, {H,Mi,S}}, Nexts, Buf, Opt) when ?IS_DATETIME(Y,M,D,H,Mi,S) ->
+datetime({{Y, M, D}, {H, Mi, S}}, Nexts, Buf, Opt) when ?IS_DATETIME(Y, M, D, H, Mi, S) ->
     {iso8601, Tz} = Opt?OPT.datetime_format,
     Str =
-    [format_year(Y), $-, format2digit(M), $-, format2digit(D), $T,
-     format2digit(H), $:, format2digit(Mi), $:, format_seconds(S),
-     format_tz(Tz)],
+        [format_year(Y),
+         $-,
+         format2digit(M),
+         $-,
+         format2digit(D),
+         $T,
+         format2digit(H),
+         $:,
+         format2digit(Mi),
+         $:,
+         format_seconds(S),
+         format_tz(Tz)],
     next(Nexts, <<Buf/binary, $", (list_to_binary(Str))/binary, $">>, Opt);
 datetime(Datetime, Nexts, Buf, Opt) ->
     ?ERROR(datetime, [Datetime, Nexts, Buf, Opt]).
@@ -177,32 +212,49 @@ datetime(Datetime, Nexts, Buf, Opt) ->
 -dialyzer({no_improper_lists, [format_year/1]}).
 -endif.
 -spec format_year(non_neg_integer()) -> iodata().
-format_year(Y) when Y > 999 -> integer_to_binary(Y);
+format_year(Y) when Y > 999 ->
+    integer_to_binary(Y);
 format_year(Y) ->
     B = integer_to_binary(Y),
-    [lists:duplicate(4-byte_size(B), $0)|B].
+    [lists:duplicate(4 - byte_size(B), $0) | B].
 
 -spec format2digit(non_neg_integer()) -> iolist().
-format2digit(0) -> "00";
-format2digit(1) -> "01";
-format2digit(2) -> "02";
-format2digit(3) -> "03";
-format2digit(4) -> "04";
-format2digit(5) -> "05";
-format2digit(6) -> "06";
-format2digit(7) -> "07";
-format2digit(8) -> "08";
-format2digit(9) -> "09";
-format2digit(X) -> integer_to_list(X).
+format2digit(0) ->
+    "00";
+format2digit(1) ->
+    "01";
+format2digit(2) ->
+    "02";
+format2digit(3) ->
+    "03";
+format2digit(4) ->
+    "04";
+format2digit(5) ->
+    "05";
+format2digit(6) ->
+    "06";
+format2digit(7) ->
+    "07";
+format2digit(8) ->
+    "08";
+format2digit(9) ->
+    "09";
+format2digit(X) ->
+    integer_to_list(X).
 
 -spec format_seconds(non_neg_integer() | float()) -> iolist().
-format_seconds(S) when is_integer(S) -> format2digit(S);
-format_seconds(S) when is_float(S) -> io_lib:format("~6.3.0f", [S]).
+format_seconds(S) when is_integer(S) ->
+    format2digit(S);
+format_seconds(S) when is_float(S) ->
+    io_lib:format("~6.3.0f", [S]).
 
 -spec format_tz(integer()) -> byte() | iolist().
-format_tz(0) -> $Z;
-format_tz(Tz) when Tz > 0 -> [$+|format_tz_(Tz)];
-format_tz(Tz) -> [$-|format_tz_(-Tz)].
+format_tz(0) ->
+    $Z;
+format_tz(Tz) when Tz > 0 ->
+    [$+ | format_tz_(Tz)];
+format_tz(Tz) ->
+    [$- | format_tz_(-Tz)].
 
 -define(SECONDS_PER_MINUTE, 60).
 -define(SECONDS_PER_HOUR, 3600).
@@ -218,12 +270,15 @@ object_key(Key, Nexts, Buf, Opt) when ?IS_STR(Key) ->
     string(Key, Nexts, Buf, Opt);
 object_key(Key, Nexts, Buf, Opt = ?OPT{object_key_type = scalar}) when is_number(Key) ->
     value(Key, [{char, $"} | Nexts], <<Buf/binary, $">>, Opt);
-object_key(Key = {{Y,M,D},{H,Mi,S}}, Nexts, Buf, Opt = ?OPT{object_key_type = Type}) when ?IS_DATETIME(Y,M,D,H,Mi,S), Type =/= string ->
+object_key(Key = {{Y, M, D}, {H, Mi, S}}, Nexts, Buf, Opt = ?OPT{object_key_type = Type})
+  when ?IS_DATETIME(Y, M, D, H, Mi, S), Type =/= string ->
     value(Key, Nexts, Buf, Opt);
 object_key(Key, Nexts, Buf, Opt = ?OPT{object_key_type = value}) ->
     case value(Key, [], <<>>, Opt) of
-        {error, Reason} -> {error, Reason};
-        {ok, BinaryKey} -> string(BinaryKey, Nexts, Buf, Opt)
+        {error, Reason} ->
+            {error, Reason};
+        {ok, BinaryKey} ->
+            string(BinaryKey, Nexts, Buf, Opt)
     end;
 object_key(Key, Nexts, Buf, Opt) ->
     ?ERROR(object_key, [Key, Nexts, Buf, Opt]).
@@ -233,100 +288,94 @@ object_key(Key, Nexts, Buf, Opt) ->
 
 -ifdef(ENABLE_HIPE).
 -define(COPY_UTF8,
-escape_string(<<2#110:3, C1:5, C2, Str/binary>>, Nexts, Buf, Opt) ->
+        escape_string(<<2#110:3, C1:5, C2, Str/binary>>, Nexts, Buf, Opt) ->
     escape_string(Str, Nexts, <<Buf/binary, (2#11000000+C1), C2>>, Opt);
 escape_string(<<2#1110:4, C1:4, C2:16, Str/binary>>, Nexts, Buf, Opt) ->
     escape_string(Str, Nexts, <<Buf/binary, (2#11100000+C1), C2:16>>, Opt);
 escape_string(<<2#11110:5, C1:3, C2:24, Str/binary>>, Nexts, Buf, Opt) ->
-    escape_string(Str, Nexts, <<Buf/binary, (2#11110000+C1), C2:24>>, Opt)
-    ).
+    escape_string(Str, Nexts, <<Buf/binary, (2#11110000+C1), C2:24>>, Opt)).
 -else.
 -define(COPY_UTF8,
-escape_string(<<Ch/utf8, Str/binary>>, Nexts, Buf, Opt) ->
-    escape_string(Str, Nexts, <<Buf/binary, Ch/utf8>>, Opt)
-    ).
+        escape_string(<<Ch/utf8, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, Ch/utf8>>, Opt)).
 -endif.
 
 -spec escape_string(binary(), [next()], binary(), opt()) -> encode_result().
-escape_string(<<"">>,                   Nexts, Buf, Opt) -> next(Nexts, <<Buf/binary, $">>, Opt);
-escape_string(<<$", Str/binary>>,       Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $">>, Opt);
-escape_string(<<$\\, Str/binary>>,      Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $\\>>, Opt);
-escape_string(<<$\b, Str/binary>>,      Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $b>>, Opt);
-escape_string(<<$\f, Str/binary>>,      Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $f>>, Opt);
-escape_string(<<$\n, Str/binary>>,      Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $n>>, Opt);
-escape_string(<<$\r, Str/binary>>,      Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $r>>, Opt);
-escape_string(<<$\t, Str/binary>>,      Nexts, Buf, Opt) -> escape_string(Str, Nexts, <<Buf/binary, $\\, $t>>, Opt);
-escape_string(<<$\/, Str/binary>>,      Nexts, Buf, Opt) when not Opt?OPT.native_forward_slash ->
+escape_string(<<"">>, Nexts, Buf, Opt) ->
+    next(Nexts, <<Buf/binary, $">>, Opt);
+escape_string(<<$", Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $">>, Opt);
+escape_string(<<$\\, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $\\>>, Opt);
+escape_string(<<$\b, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $b>>, Opt);
+escape_string(<<$\f, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $f>>, Opt);
+escape_string(<<$\n, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $n>>, Opt);
+escape_string(<<$\r, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $r>>, Opt);
+escape_string(<<$\t, Str/binary>>, Nexts, Buf, Opt) ->
+    escape_string(Str, Nexts, <<Buf/binary, $\\, $t>>, Opt);
+escape_string(<<$\/, Str/binary>>, Nexts, Buf, Opt) when not Opt?OPT.native_forward_slash ->
     escape_string(Str, Nexts, <<Buf/binary, $\\, $\/>>, Opt);
 escape_string(<<0:1, C:7, Str/binary>>, Nexts, Buf, Opt) ->
     case C < 16#20 of
-        true  -> escape_string(Str, Nexts, <<Buf/binary, "\\u00", ?H8(C)>>, Opt);
+        true ->
+            escape_string(Str, Nexts, <<Buf/binary, "\\u00", ?H8(C)>>, Opt);
         false ->
             Len = unescaped_string_length(Str, Opt),
             <<Unescaped:Len/binary, Rest/binary>> = Str,
             escape_string(Rest, Nexts, <<Buf/binary, C, Unescaped/binary>>, Opt)
 
     end;
-escape_string(<<Ch/utf8, Str/binary>>,  Nexts, Buf, Opt = ?OPT{native_utf8 = false}) ->
-     if
-         Ch =< 16#FFFF ->
-             escape_string(Str, Nexts,<<Buf/binary, $\\, $u, ?H16(Ch)>>, Opt);
-         true ->
-             <<H1, H2, L1, L2>> = <<Ch/utf16>>,
-             escape_string(Str, Nexts, <<Buf/binary, $\\, $u, ?H8(H1), ?H8(H2), $\\, $u, ?H8(L1), ?H8(L2)>>, Opt)
-     end;
+escape_string(<<Ch/utf8, Str/binary>>, Nexts, Buf, Opt = ?OPT{native_utf8 = false}) ->
+    if
+        Ch =< 16#FFFF ->
+            escape_string(Str, Nexts, <<Buf/binary, $\\, $u, ?H16(Ch)>>, Opt);
+        true ->
+            <<H1, H2, L1, L2>> = <<Ch/utf16>>,
+            escape_string(Str, Nexts, <<Buf/binary, $\\, $u, ?H8(H1), ?H8(H2), $\\, $u, ?H8(L1), ?H8(L2)>>, Opt)
+    end;
 ?COPY_UTF8;
 escape_string(Str, Nexts, Buf, Opt) ->
     ?ERROR(escape_string, [Str, Nexts, Buf, Opt]).
 
 -define(UNESCAPED_CHARS_WITH_SLASH,
-        {false,false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,true,true,false,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,false,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false}).
+        {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false}).
 
 -define(UNESCAPED_CHARS_WITHOUT_SLASH,
-        {false,false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,true,true,false,
-         true,true,true,true,true,true,true,true,true,true,true,true,false,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,false,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,true,true,true,true,true,true,
-         true,true,true,true,true,true,true,true,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false,false,false,false,false,false,false,false,false,
-         false,false,false}).
-
+        {false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         true, true, false, true, true, true, true, true, true, true, true, true, true, true, true, false, true, true,
+         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, false, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true, true,
+         true, true, true, true, true, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false, false, false, false, false, false, false, false, false, false, false,
+         false, false, false, false, false, false}).
 
 -compile({inline, [unescaped_string_length/2]}).
 -spec unescaped_string_length(binary(), opt()) -> non_neg_integer().
@@ -338,71 +387,63 @@ unescaped_string_length(Str, _) ->
 -spec unescaped_string_length(binary(), non_neg_integer(), tuple()) -> non_neg_integer().
 unescaped_string_length(<<C, Str/binary>>, N, Table) ->
     case element(C + 1, Table) of
-        true  -> unescaped_string_length(Str, N + 1, Table);
-        false -> N
+        true ->
+            unescaped_string_length(Str, N + 1, Table);
+        false ->
+            N
     end;
 unescaped_string_length(_, N, _) ->
     N.
 
 -compile({inline, [hex/1]}).
--spec hex(byte()) -> 0..16#FFFF.
+-spec hex(byte()) -> 0 .. 16#FFFF.
 hex(X) ->
-  element(
-    X+1,
-    {16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037,
-     16#3038, 16#3039, 16#3061, 16#3062, 16#3063, 16#3064, 16#3065, 16#3066,
-     16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137,
-     16#3138, 16#3139, 16#3161, 16#3162, 16#3163, 16#3164, 16#3165, 16#3166,
-     16#3230, 16#3231, 16#3232, 16#3233, 16#3234, 16#3235, 16#3236, 16#3237,
-     16#3238, 16#3239, 16#3261, 16#3262, 16#3263, 16#3264, 16#3265, 16#3266,
-     16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337,
-     16#3338, 16#3339, 16#3361, 16#3362, 16#3363, 16#3364, 16#3365, 16#3366,
-     16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437,
-     16#3438, 16#3439, 16#3461, 16#3462, 16#3463, 16#3464, 16#3465, 16#3466,
-     16#3530, 16#3531, 16#3532, 16#3533, 16#3534, 16#3535, 16#3536, 16#3537,
-     16#3538, 16#3539, 16#3561, 16#3562, 16#3563, 16#3564, 16#3565, 16#3566,
-     16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637,
-     16#3638, 16#3639, 16#3661, 16#3662, 16#3663, 16#3664, 16#3665, 16#3666,
-     16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737,
-     16#3738, 16#3739, 16#3761, 16#3762, 16#3763, 16#3764, 16#3765, 16#3766,
-     16#3830, 16#3831, 16#3832, 16#3833, 16#3834, 16#3835, 16#3836, 16#3837,
-     16#3838, 16#3839, 16#3861, 16#3862, 16#3863, 16#3864, 16#3865, 16#3866,
-     16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937,
-     16#3938, 16#3939, 16#3961, 16#3962, 16#3963, 16#3964, 16#3965, 16#3966,
-     16#6130, 16#6131, 16#6132, 16#6133, 16#6134, 16#6135, 16#6136, 16#6137,
-     16#6138, 16#6139, 16#6161, 16#6162, 16#6163, 16#6164, 16#6165, 16#6166,
-     16#6230, 16#6231, 16#6232, 16#6233, 16#6234, 16#6235, 16#6236, 16#6237,
-     16#6238, 16#6239, 16#6261, 16#6262, 16#6263, 16#6264, 16#6265, 16#6266,
-     16#6330, 16#6331, 16#6332, 16#6333, 16#6334, 16#6335, 16#6336, 16#6337,
-     16#6338, 16#6339, 16#6361, 16#6362, 16#6363, 16#6364, 16#6365, 16#6366,
-     16#6430, 16#6431, 16#6432, 16#6433, 16#6434, 16#6435, 16#6436, 16#6437,
-     16#6438, 16#6439, 16#6461, 16#6462, 16#6463, 16#6464, 16#6465, 16#6466,
-     16#6530, 16#6531, 16#6532, 16#6533, 16#6534, 16#6535, 16#6536, 16#6537,
-     16#6538, 16#6539, 16#6561, 16#6562, 16#6563, 16#6564, 16#6565, 16#6566,
-     16#6630, 16#6631, 16#6632, 16#6633, 16#6634, 16#6635, 16#6636, 16#6637,
-     16#6638, 16#6639, 16#6661, 16#6662, 16#6663, 16#6664, 16#6665, 16#6666}
-          ).
+    element(X + 1,
+            {16#3030, 16#3031, 16#3032, 16#3033, 16#3034, 16#3035, 16#3036, 16#3037, 16#3038, 16#3039, 16#3061, 16#3062,
+             16#3063, 16#3064, 16#3065, 16#3066, 16#3130, 16#3131, 16#3132, 16#3133, 16#3134, 16#3135, 16#3136, 16#3137,
+             16#3138, 16#3139, 16#3161, 16#3162, 16#3163, 16#3164, 16#3165, 16#3166, 16#3230, 16#3231, 16#3232, 16#3233,
+             16#3234, 16#3235, 16#3236, 16#3237, 16#3238, 16#3239, 16#3261, 16#3262, 16#3263, 16#3264, 16#3265, 16#3266,
+             16#3330, 16#3331, 16#3332, 16#3333, 16#3334, 16#3335, 16#3336, 16#3337, 16#3338, 16#3339, 16#3361, 16#3362,
+             16#3363, 16#3364, 16#3365, 16#3366, 16#3430, 16#3431, 16#3432, 16#3433, 16#3434, 16#3435, 16#3436, 16#3437,
+             16#3438, 16#3439, 16#3461, 16#3462, 16#3463, 16#3464, 16#3465, 16#3466, 16#3530, 16#3531, 16#3532, 16#3533,
+             16#3534, 16#3535, 16#3536, 16#3537, 16#3538, 16#3539, 16#3561, 16#3562, 16#3563, 16#3564, 16#3565, 16#3566,
+             16#3630, 16#3631, 16#3632, 16#3633, 16#3634, 16#3635, 16#3636, 16#3637, 16#3638, 16#3639, 16#3661, 16#3662,
+             16#3663, 16#3664, 16#3665, 16#3666, 16#3730, 16#3731, 16#3732, 16#3733, 16#3734, 16#3735, 16#3736, 16#3737,
+             16#3738, 16#3739, 16#3761, 16#3762, 16#3763, 16#3764, 16#3765, 16#3766, 16#3830, 16#3831, 16#3832, 16#3833,
+             16#3834, 16#3835, 16#3836, 16#3837, 16#3838, 16#3839, 16#3861, 16#3862, 16#3863, 16#3864, 16#3865, 16#3866,
+             16#3930, 16#3931, 16#3932, 16#3933, 16#3934, 16#3935, 16#3936, 16#3937, 16#3938, 16#3939, 16#3961, 16#3962,
+             16#3963, 16#3964, 16#3965, 16#3966, 16#6130, 16#6131, 16#6132, 16#6133, 16#6134, 16#6135, 16#6136, 16#6137,
+             16#6138, 16#6139, 16#6161, 16#6162, 16#6163, 16#6164, 16#6165, 16#6166, 16#6230, 16#6231, 16#6232, 16#6233,
+             16#6234, 16#6235, 16#6236, 16#6237, 16#6238, 16#6239, 16#6261, 16#6262, 16#6263, 16#6264, 16#6265, 16#6266,
+             16#6330, 16#6331, 16#6332, 16#6333, 16#6334, 16#6335, 16#6336, 16#6337, 16#6338, 16#6339, 16#6361, 16#6362,
+             16#6363, 16#6364, 16#6365, 16#6366, 16#6430, 16#6431, 16#6432, 16#6433, 16#6434, 16#6435, 16#6436, 16#6437,
+             16#6438, 16#6439, 16#6461, 16#6462, 16#6463, 16#6464, 16#6465, 16#6466, 16#6530, 16#6531, 16#6532, 16#6533,
+             16#6534, 16#6535, 16#6536, 16#6537, 16#6538, 16#6539, 16#6561, 16#6562, 16#6563, 16#6564, 16#6565, 16#6566,
+             16#6630, 16#6631, 16#6632, 16#6633, 16#6634, 16#6635, 16#6636, 16#6637, 16#6638, 16#6639, 16#6661, 16#6662,
+             16#6663, 16#6664, 16#6665, 16#6666}).
 
 -spec array(jsone:json_array(), [next()], binary(), opt()) -> encode_result().
-array([],   Nexts, Buf, Opt) ->
+array([], Nexts, Buf, Opt) ->
     next(Nexts, <<Buf/binary, $[, $]>>, Opt);
 array(List, Nexts, Buf, Opt) ->
     array_values(List, Nexts, pp_newline(<<Buf/binary, $[>>, Nexts, 1, Opt), Opt).
 
 -spec array_values(jsone:json_array(), [next()], binary(), opt()) -> encode_result().
-array_values([],       Nexts, Buf, Opt) -> next(Nexts, <<(pp_newline(Buf, Nexts, Opt))/binary, $]>>, Opt);
-array_values([X | Xs], Nexts, Buf, Opt) -> value(X, [{array_values, Xs} | Nexts], Buf, Opt).
+array_values([], Nexts, Buf, Opt) ->
+    next(Nexts, <<(pp_newline(Buf, Nexts, Opt))/binary, $]>>, Opt);
+array_values([X | Xs], Nexts, Buf, Opt) ->
+    value(X, [{array_values, Xs} | Nexts], Buf, Opt).
 
 -spec object(jsone:json_object_members(), [next()], binary(), opt()) -> encode_result().
-object(Members, Nexts, Buf, ?OPT{skip_undefined = true}=Opt) ->
+object(Members, Nexts, Buf, ?OPT{skip_undefined = true} = Opt) ->
     object1(lists:filter(fun ({_, V}) -> V =/= undefined end, Members), Nexts, Buf, Opt);
 object(Members, Nexts, Buf, Opt) ->
     object1(Members, Nexts, Buf, Opt).
 
 -spec object1(jsone:json_object_members(), [next()], binary(), opt()) -> encode_result().
-object1([],      Nexts, Buf, Opt) ->
+object1([], Nexts, Buf, Opt) ->
     next(Nexts, <<Buf/binary, ${, $}>>, Opt);
-object1(Members, Nexts, Buf, ?OPT{canonical_form = true}=Opt) ->
+object1(Members, Nexts, Buf, ?OPT{canonical_form = true} = Opt) ->
     object_members(lists:sort(Members), Nexts, pp_newline(<<Buf/binary, ${>>, Nexts, 1, Opt), Opt);
 object1(Members, Nexts, Buf, Opt) ->
     object_members(Members, Nexts, pp_newline(<<Buf/binary, ${>>, Nexts, 1, Opt), Opt).
@@ -420,70 +461,92 @@ object_value(Value, Members, Nexts, Buf, Opt) ->
     value(Value, [{object_members, Members} | Nexts], Buf, Opt).
 
 -spec pp_space(binary(), opt()) -> binary().
-pp_space(Buf, Opt) -> padding(Buf, Opt?OPT.space).
+pp_space(Buf, Opt) ->
+    padding(Buf, Opt?OPT.space).
 
 -spec pp_newline(binary(), list(), opt()) -> binary().
-pp_newline(Buf, Level, Opt) -> pp_newline(Buf, Level, 0, Opt).
+pp_newline(Buf, Level, Opt) ->
+    pp_newline(Buf, Level, 0, Opt).
 
 -spec pp_newline(binary(), list(), non_neg_integer(), opt()) -> binary().
-pp_newline(Buf, _, _,     ?OPT{indent = 0}) -> Buf;
-pp_newline(Buf, L, Extra, ?OPT{indent = N}) -> padding(<<Buf/binary, $\n>>, Extra * N + length(L) * N).
+pp_newline(Buf, _, _, ?OPT{indent = 0}) ->
+    Buf;
+pp_newline(Buf, L, Extra, ?OPT{indent = N}) ->
+    padding(<<Buf/binary, $\n>>, Extra * N + length(L) * N).
 
 -spec pp_newline_or_space(binary(), list(), opt()) -> binary().
-pp_newline_or_space(Buf, _, Opt = ?OPT{indent = 0}) -> pp_space(Buf, Opt);
-pp_newline_or_space(Buf, L, Opt)                    -> pp_newline(Buf, L, Opt).
+pp_newline_or_space(Buf, _, Opt = ?OPT{indent = 0}) ->
+    pp_space(Buf, Opt);
+pp_newline_or_space(Buf, L, Opt) ->
+    pp_newline(Buf, L, Opt).
 
 -spec padding(binary(), non_neg_integer()) -> binary().
-padding(Buf, 0) -> Buf;
-padding(Buf, 1) -> <<Buf/binary, " ">>;
-padding(Buf, 2) -> <<Buf/binary, "  ">>;
-padding(Buf, 3) -> <<Buf/binary, "   ">>;
-padding(Buf, 4) -> <<Buf/binary, "    ">>;
-padding(Buf, 5) -> <<Buf/binary, "     ">>;
-padding(Buf, 6) -> <<Buf/binary, "      ">>;
-padding(Buf, 7) -> <<Buf/binary, "       ">>;
-padding(Buf, 8) -> <<Buf/binary, "        ">>;
-padding(Buf, N) -> padding(<<Buf/binary, "         ">>, N - 9).
+padding(Buf, 0) ->
+    Buf;
+padding(Buf, 1) ->
+    <<Buf/binary, " ">>;
+padding(Buf, 2) ->
+    <<Buf/binary, "  ">>;
+padding(Buf, 3) ->
+    <<Buf/binary, "   ">>;
+padding(Buf, 4) ->
+    <<Buf/binary, "    ">>;
+padding(Buf, 5) ->
+    <<Buf/binary, "     ">>;
+padding(Buf, 6) ->
+    <<Buf/binary, "      ">>;
+padding(Buf, 7) ->
+    <<Buf/binary, "       ">>;
+padding(Buf, 8) ->
+    <<Buf/binary, "        ">>;
+padding(Buf, N) ->
+    padding(<<Buf/binary, "         ">>, N - 9).
 
 -spec parse_options([jsone:encode_option()]) -> opt().
 parse_options(Options) ->
     parse_option(Options, ?OPT{}).
 
 -spec parse_option([jsone:encode_option()], opt()) -> opt().
-parse_option([], Opt) -> Opt;
-parse_option([native_utf8|T], Opt) ->
-    parse_option(T, Opt?OPT{native_utf8=true});
-parse_option([native_forward_slash|T], Opt) ->
-    parse_option(T, Opt?OPT{native_forward_slash=true});
-parse_option([canonical_form|T], Opt) ->
-    parse_option(T, Opt?OPT{canonical_form=true});
-parse_option([{float_format, F}|T], Opt) when is_list(F) ->
+parse_option([], Opt) ->
+    Opt;
+parse_option([native_utf8 | T], Opt) ->
+    parse_option(T, Opt?OPT{native_utf8 = true});
+parse_option([native_forward_slash | T], Opt) ->
+    parse_option(T, Opt?OPT{native_forward_slash = true});
+parse_option([canonical_form | T], Opt) ->
+    parse_option(T, Opt?OPT{canonical_form = true});
+parse_option([{float_format, F} | T], Opt) when is_list(F) ->
     parse_option(T, Opt?OPT{float_format = F});
-parse_option([{space, N}|T], Opt) when is_integer(N), N >= 0 ->
+parse_option([{space, N} | T], Opt) when is_integer(N), N >= 0 ->
     parse_option(T, Opt?OPT{space = N});
-parse_option([{indent, N}|T], Opt) when is_integer(N), N >= 0 ->
+parse_option([{indent, N} | T], Opt) when is_integer(N), N >= 0 ->
     parse_option(T, Opt?OPT{indent = N});
-parse_option([{object_key_type, Type}|T], Opt) when Type =:= string; Type =:= scalar; Type =:= value ->
+parse_option([{object_key_type, Type} | T], Opt) when Type =:= string; Type =:= scalar; Type =:= value ->
     parse_option(T, Opt?OPT{object_key_type = Type});
-parse_option([{datetime_format, Fmt}|T], Opt) ->
+parse_option([{datetime_format, Fmt} | T], Opt) ->
     case Fmt of
-        iso8601                                 -> parse_option(T, Opt?OPT{datetime_format = {iso8601, 0}});
-        {iso8601, utc}                          -> parse_option(T, Opt?OPT{datetime_format = {iso8601, 0}});
-        {iso8601, local}                        -> parse_option(T, Opt?OPT{datetime_format = {iso8601, local_offset()}});
-        {iso8601, N} when -86400 < N, N < 86400 -> parse_option(T, Opt?OPT{datetime_format = {iso8601, N}});
-        _                                       -> error(badarg, [[{datetime_format, Fmt}|T], Opt])
+        iso8601 ->
+            parse_option(T, Opt?OPT{datetime_format = {iso8601, 0}});
+        {iso8601, utc} ->
+            parse_option(T, Opt?OPT{datetime_format = {iso8601, 0}});
+        {iso8601, local} ->
+            parse_option(T, Opt?OPT{datetime_format = {iso8601, local_offset()}});
+        {iso8601, N} when -86400 < N, N < 86400 ->
+            parse_option(T, Opt?OPT{datetime_format = {iso8601, N}});
+        _ ->
+            error(badarg, [[{datetime_format, Fmt} | T], Opt])
     end;
-parse_option([undefined_as_null|T],Opt) ->
+parse_option([undefined_as_null | T], Opt) ->
     parse_option(T, Opt?OPT{undefined_as_null = true});
-parse_option([skip_undefined|T],Opt) ->
+parse_option([skip_undefined | T], Opt) ->
     parse_option(T, Opt?OPT{skip_undefined = true});
-parse_option([{map_unknown_value, F}|T], Opt) when is_function(F, 1); F =:= undefined ->
+parse_option([{map_unknown_value, F} | T], Opt) when is_function(F, 1); F =:= undefined ->
     parse_option(T, Opt?OPT{map_unknown_value = F});
 parse_option(List, Opt) ->
     error(badarg, [List, Opt]).
 
 -spec local_offset() -> jsone:utc_offset_seconds().
 local_offset() ->
-    UTC = {{1970, 1, 2}, {0,0,0}},
-    Local = calendar:universal_time_to_local_time({{1970, 1, 2}, {0,0,0}}),
+    UTC = {{1970, 1, 2}, {0, 0, 0}},
+    Local = calendar:universal_time_to_local_time({{1970, 1, 2}, {0, 0, 0}}),
     calendar:datetime_to_gregorian_seconds(Local) - calendar:datetime_to_gregorian_seconds(UTC).

+ 19 - 11
src/jsone_inet.erl

@@ -51,7 +51,7 @@
 %% @doc Convert an IP address into a text representation.
 %%
 %% Please refer to the doc of `jsone:ip_address_to_json_string/1' for the detail.
--spec ip_address_to_json_string(inet:ip_address()|any()) -> {ok, jsone:json_string()} | error.
+-spec ip_address_to_json_string(inet:ip_address() | any()) -> {ok, jsone:json_string()} | error.
 ip_address_to_json_string({A, B, C, D}) when ?IS_IPV4(A, B, C, D) ->
     {ok, iolist_to_binary(io_lib:format("~p.~p.~p.~p", [A, B, C, D]))};
 ip_address_to_json_string({A, B, C, D, E, F, G, H}) when ?IS_IPV6(A, B, C, D, E, F, G, H) ->
@@ -84,33 +84,41 @@ ip_address_to_json_string(_) ->
 %%--------------------------------------------------------------------------------
 %% Internal Functions
 %%--------------------------------------------------------------------------------
--spec format_ipv6([0..65535]) -> string().
+-spec format_ipv6([0 .. 65535]) -> string().
 format_ipv6(Xs) ->
     case format_ipv6(Xs, 0, 0) of
-        {Ys, shortening} -> [$: | string:join(Ys, ":")];
+        {Ys, shortening} ->
+            [$: | string:join(Ys, ":")];
         {Ys, _} ->
             Text = string:join(Ys, ":"),
             case lists:last(Text) of
-                $: -> [Text | ":"];
-                _  -> Text
+                $: ->
+                    [Text | ":"];
+                _ ->
+                    Text
             end
     end.
 
--spec format_ipv6([0..65535], non_neg_integer(), non_neg_integer()) -> {[string()], not_shortened | shortening | shortened}.
+-spec format_ipv6([0 .. 65535], non_neg_integer(), non_neg_integer()) ->
+          {[string()], not_shortened | shortening | shortened}.
 format_ipv6([], _Zeros, _MaxZeros) ->
     {[], not_shortened};
 format_ipv6([X | Xs], Zeros0, MaxZeros) ->
     Zeros1 =
         case X of
-            0 -> Zeros0 + 1;
-            _ -> 0
+            0 ->
+                Zeros0 + 1;
+            _ ->
+                0
         end,
     Shorten = Zeros1 > MaxZeros andalso Zeros1 > 1,
     case format_ipv6(Xs, Zeros1, max(Zeros1, MaxZeros)) of
         {Ys, not_shortened} ->
             case Shorten of
-                true  -> {["" | Ys], shortening};
-                false -> {[to_hex(X) | Ys], not_shortened}
+                true ->
+                    {["" | Ys], shortening};
+                false ->
+                    {[to_hex(X) | Ys], not_shortened}
             end;
         {Ys, shortening} when X =:= 0 ->
             {Ys, shortening};
@@ -118,6 +126,6 @@ format_ipv6([X | Xs], Zeros0, MaxZeros) ->
             {[to_hex(X) | Ys], shortened}
     end.
 
--spec to_hex(0..65535) -> string().
+-spec to_hex(0 .. 65535) -> string().
 to_hex(N) ->
     string:lowercase(integer_to_list(N, 16)).

+ 68 - 96
test/jsone_decode_tests.erl

@@ -15,39 +15,21 @@
 -define(OBJ0, #{}).
 -define(OBJ1(K, V), #{K => V}).
 -define(OBJ2(K1, V1, K2, V2), #{K1 => V1, K2 => V2}).
--define(OBJ2_DUP_KEY(K1, V1, _K2, _V2), #{K1 => V1}). % the first (leftmost) value is used
--define(OBJ2_DUP_KEY_LAST(_K1, _V1, K2, V2), #{K2 => V2}). % the last value is used
+-define(OBJ2_DUP_KEY(K1, V1, _K2, _V2), #{K1 => V1}).  % the first (leftmost) value is used
+-define(OBJ2_DUP_KEY_LAST(_K1, _V1, K2, V2), #{K2 => V2}).  % the last value is used
 -endif.
 
 decode_test_() ->
     [
      %% Symbols
-     {"false",
-      fun () ->
-              ?assertEqual({ok, false, <<"">>}, jsone_decode:decode(<<"false">>))
-      end},
-     {"true",
-      fun () ->
-              ?assertEqual({ok, true, <<"">>}, jsone_decode:decode(<<"true">>))
-      end},
-     {"null",
-      fun () ->
-              ?assertEqual({ok, null, <<"">>}, jsone_decode:decode(<<"null">>))
-      end},
+     {"false", fun () -> ?assertEqual({ok, false, <<"">>}, jsone_decode:decode(<<"false">>))end},
+     {"true", fun () -> ?assertEqual({ok, true, <<"">>}, jsone_decode:decode(<<"true">>))end},
+     {"null", fun () -> ?assertEqual({ok, null, <<"">>}, jsone_decode:decode(<<"null">>))end},
 
      %% Numbers: Integer
-     {"positive integer",
-      fun () ->
-              ?assertEqual({ok, 1, <<"">>}, jsone_decode:decode(<<"1">>))
-      end},
-     {"zero",
-      fun () ->
-              ?assertEqual({ok, 0, <<"">>}, jsone_decode:decode(<<"0">>))
-      end},
-     {"negative integer",
-      fun () ->
-              ?assertEqual({ok, -1, <<"">>}, jsone_decode:decode(<<"-1">>))
-      end},
+     {"positive integer", fun () -> ?assertEqual({ok, 1, <<"">>}, jsone_decode:decode(<<"1">>))end},
+     {"zero", fun () -> ?assertEqual({ok, 0, <<"">>}, jsone_decode:decode(<<"0">>))end},
+     {"negative integer", fun () -> ?assertEqual({ok, -1, <<"">>}, jsone_decode:decode(<<"-1">>))end},
      {"large integer (no limit on size)",
       fun () ->
               ?assertEqual({ok, 111111111111111111111111111111111111111111111111111111111111111111111111111111, <<"">>},
@@ -60,22 +42,17 @@ decode_test_() ->
               ?assertEqual({ok, 0, <<"1">>}, jsone_decode:decode(<<"-01">>))
       end},
      {"integer can't begin with an explicit plus sign",
-      fun () ->
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"+1">>))
-      end},
+      fun () -> ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"+1">>))end},
 
      %% Numbers: Floats
-     {"float: decimal notation",
-      fun () ->
-              ?assertEqual({ok, 1.23, <<"">>}, jsone_decode:decode(<<"1.23">>))
-      end},
+     {"float: decimal notation", fun () -> ?assertEqual({ok, 1.23, <<"">>}, jsone_decode:decode(<<"1.23">>))end},
      {"float: exponential notation",
       fun () ->
-              ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345e-3">>)), % lower case 'e'
-              ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345E-3">>)), % upper case 'E'
+              ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345e-3">>)),  % lower case 'e'
+              ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345E-3">>)),  % upper case 'E'
               ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"12345.0e-3">>)),
               ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345E2">>)),
-              ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345e+2">>)), % exponent part can begin with plus sign
+              ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345e+2">>)),  % exponent part can begin with plus sign
               ?assertEqual({ok, 12.345, <<"">>}, jsone_decode:decode(<<"0.12345E+2">>)),
               ?assertEqual({ok, -12.345, <<"">>}, jsone_decode:decode(<<"-0.012345e3">>)),
               ?assertEqual({ok, 123.0, <<"">>}, jsone_decode:decode(<<"1.23000000000000000000e+02">>))
@@ -83,80 +60,76 @@ decode_test_() ->
      {"float: invalid format",
       fun () ->
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<".123">>)),  % omitted integer part
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.">>)),    % omitted fraction part: EOS
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.e+3">>)), % omitted fraction part: with exponent part
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e">>)),    % imcomplete fraction part
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e-">>)),   % imcomplete fraction part
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1ee-1">>)), % duplicated 'e'
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e--1">>)), % duplicated sign
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"1e999">>)),   % exponent out of range
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e999">>)), % exponent out of range
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"100000000000000000000000000000000000e300">>)), % product out of range
-              ?assertEqual({ok, 0.1, <<".2">>}, jsone_decode:decode(<<"0.1.2">>))     % duplicated '.': interpreted as individual tokens
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.">>)),  % omitted fraction part: EOS
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.e+3">>)),  % omitted fraction part: with exponent part
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e">>)),  % imcomplete fraction part
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e-">>)),  % imcomplete fraction part
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1ee-1">>)),  % duplicated 'e'
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e--1">>)),  % duplicated sign
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"1e999">>)),  % exponent out of range
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"0.1e999">>)),  % exponent out of range
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"100000000000000000000000000000000000e300">>)),  % product out of range
+              ?assertEqual({ok, 0.1, <<".2">>}, jsone_decode:decode(<<"0.1.2">>))  % duplicated '.': interpreted as individual tokens
       end},
 
      %% Strings
-     {"simple string",
-      fun () ->
-              ?assertEqual({ok, <<"abc">>,  <<"">>}, jsone_decode:decode(<<"\"abc\"">>))
-      end},
+     {"simple string", fun () -> ?assertEqual({ok, <<"abc">>, <<"">>}, jsone_decode:decode(<<"\"abc\"">>))end},
      {"string: escaped characters",
       fun () ->
-              Input    = list_to_binary([$", [[$\\, C] || C <- [$", $/, $\\, $b, $f, $n, $r, $t]], $"]),
+              Input = list_to_binary([$", [[$\\, C] || C <- [$", $/, $\\, $b, $f, $n, $r, $t]], $"]),
               Expected = <<"\"\/\\\b\f\n\r\t">>,
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
       end},
      {"string: escaped Unicode characters",
       fun () ->
               %% japanese
-              Input1    = <<"\"\\u3042\\u3044\\u3046\\u3048\\u304A\"">>,
+              Input1 = <<"\"\\u3042\\u3044\\u3046\\u3048\\u304A\"">>,
               Expected1 = <<"あいうえお">>,  % assumed that the encoding of this file is UTF-8
               ?assertEqual({ok, Expected1, <<"">>}, jsone_decode:decode(Input1)),
 
               %% ascii
-              Input2    = <<"\"\\u0061\\u0062\\u0063\"">>,
+              Input2 = <<"\"\\u0061\\u0062\\u0063\"">>,
               Expected2 = <<"abc">>,
               ?assertEqual({ok, Expected2, <<"">>}, jsone_decode:decode(Input2)),
 
               %% other multi-byte characters
-              Input3    = <<"\"\\u06DD\\u06DE\\u10AE\\u10AF\"">>,
+              Input3 = <<"\"\\u06DD\\u06DE\\u10AE\\u10AF\"">>,
               Expected3 = <<"۝۞ႮႯ">>,
               ?assertEqual({ok, Expected3, <<"">>}, jsone_decode:decode(Input3)),
 
               %% mixture of ascii and japanese characters
-              Input4    = <<"\"a\\u30421\\u3044bb\\u304622\\u3048ccc\\u304A333\"">>,
+              Input4 = <<"\"a\\u30421\\u3044bb\\u304622\\u3048ccc\\u304A333\"">>,
               Expected4 = <<"aあ1いbbう22えcccお333">>,  % assumed that the encoding of this file is UTF-8
               ?assertEqual({ok, Expected4, <<"">>}, jsone_decode:decode(Input4))
       end},
      {"string: surrogate pairs",
       fun () ->
-              Input    = <<"\"\\ud848\\udc49\\ud848\\udc9a\\ud848\\udcfc\"">>,
+              Input = <<"\"\\ud848\\udc49\\ud848\\udc9a\\ud848\\udcfc\"">>,
               Expected = <<"𢁉𢂚𢃼">>,
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
       end},
      {"string: control characters",
       fun () ->
               Ctrls = lists:seq(0, 16#1f),
-              lists:foreach(
-                fun (C) ->
-                        %% Control characters are unacceptable
-                        ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<$", C, $">>))
-                end,
-                Ctrls),
-              lists:foreach(
-                fun (C) ->
-                        %% `allow_ctrl_chars' option allows strings which contain unescaped control characters
-                        ?assertEqual({ok, <<C>>, <<"">>}, jsone_decode:decode(<<$", C, $">>, [{allow_ctrl_chars, true}]))
-                end,
-                Ctrls)
+              lists:foreach(fun (C) ->
+                                    %% Control characters are unacceptable
+                                    ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<$", C, $">>))
+                            end,
+                            Ctrls),
+              lists:foreach(fun (C) ->
+                                    %% `allow_ctrl_chars' option allows strings which contain unescaped control characters
+                                    ?assertEqual({ok, <<C>>, <<"">>},
+                                                 jsone_decode:decode(<<$", C, $">>, [{allow_ctrl_chars, true}]))
+                            end,
+                            Ctrls)
       end},
      {"string: invalid escape characters",
       fun () ->
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\z\"">>)),    % '\z' is undefined
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\z\"">>)),  % '\z' is undefined
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\uab\"">>)),  % too few hex characters
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\"">>)), % high(first) surrogate only
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\udc49\"">>)), % low(second) surrogate only
-              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\\u0061\"">>)), % missing low(second) surrogate
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\"">>)),  % high(first) surrogate only
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\udc49\"">>)),  % low(second) surrogate only
+              ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\\u0061\"">>)),  % missing low(second) surrogate
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\udf0u\"">>)),
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\ud848\\udf0u\"">>)),
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(<<"\"\\u-3351\"">>))
@@ -165,13 +138,13 @@ decode_test_() ->
      %% Arrays
      {"simple array",
       fun () ->
-              Input    = <<"[1,2,\"abc\",null]">>,
+              Input = <<"[1,2,\"abc\",null]">>,
               Expected = [1, 2, <<"abc">>, null],
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
       end},
      {"array: contains whitespaces",
       fun () ->
-              Input    = <<"[  1,\t2, \n \"abc\",\r null]">>,
+              Input = <<"[  1,\t2, \n \"abc\",\r null]">>,
               Expected = [1, 2, <<"abc">>, null],
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
       end},
@@ -187,7 +160,7 @@ decode_test_() ->
       end},
      {"array: missing comma",
       fun () ->
-              Input = <<"[1 2, \"abc\", null]">>, % a missing comma between '1' and '2'
+              Input = <<"[1 2, \"abc\", null]">>,  % a missing comma between '1' and '2'
               ?assertMatch({error, {badarg, _}}, jsone_decode:decode(Input))
       end},
      {"array: missing closing bracket",
@@ -199,21 +172,21 @@ decode_test_() ->
      %% Objects
      {"simple object",
       fun () ->
-              Input    = <<"{\"1\":2,\"key\":\"value\"}">>,
+              Input = <<"{\"1\":2,\"key\":\"value\"}">>,
               Expected = ?OBJ2(<<"1">>, 2, <<"key">>, <<"value">>),
-              ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input)), % `map' is the default format
+              ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input)),  % `map' is the default format
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input, [{object_format, ?MAP_OBJECT_TYPE}]))
       end},
      {"simple object: tuple or proplist",
       fun () ->
-              Input    = <<"{\"1\":2,\"key\":\"value\"}">>,
-              Expected = {[{<<"1">>, 2},{<<"key">>, <<"value">>}]},
+              Input = <<"{\"1\":2,\"key\":\"value\"}">>,
+              Expected = {[{<<"1">>, 2}, {<<"key">>, <<"value">>}]},
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input, [{object_format, tuple}])),
               ?assertEqual({ok, element(1, Expected), <<"">>}, jsone_decode:decode(Input, [{object_format, proplist}]))
       end},
      {"object: contains whitespaces",
       fun () ->
-              Input    = <<"{  \"1\" :\t 2,\n\r\"key\" :   \n  \"value\"}">>,
+              Input = <<"{  \"1\" :\t 2,\n\r\"key\" :   \n  \"value\"}">>,
               Expected = ?OBJ2(<<"1">>, 2, <<"key">>, <<"value">>),
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input))
       end},
@@ -230,17 +203,16 @@ decode_test_() ->
       end},
      {"duplicated members: map",
       fun () ->
-              Input    = <<"{\"1\":\"first\",\"1\":\"second\"}">>,
+              Input = <<"{\"1\":\"first\",\"1\":\"second\"}">>,
               Expected = ?OBJ2_DUP_KEY(<<"1">>, <<"first">>, <<"1">>, <<"second">>),
               ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input, [{object_format, ?MAP_OBJECT_TYPE}]))
       end},
      {"duplicated members last: map",
       fun () ->
-              Input    = <<"{\"1\":\"first\",\"1\":\"second\"}">>,
+              Input = <<"{\"1\":\"first\",\"1\":\"second\"}">>,
               Expected = ?OBJ2_DUP_KEY_LAST(<<"1">>, <<"first">>, <<"1">>, <<"second">>),
-              ?assertEqual({ok, Expected, <<"">>}, jsone_decode:decode(Input,
-                                                                       [{object_format, ?MAP_OBJECT_TYPE},
-                                                                        {duplicate_map_keys, last}]))
+              ?assertEqual({ok, Expected, <<"">>},
+                           jsone_decode:decode(Input, [{object_format, ?MAP_OBJECT_TYPE}, {duplicate_map_keys, last}]))
       end},
      {"object: trailing comma is disallowed",
       fun () ->
@@ -275,8 +247,7 @@ decode_test_() ->
       end},
      {"atom keys",
       fun () ->
-              KeyOpt = fun(Keys) -> [{keys, Keys}, {object_format, proplist}]
-                       end,
+              KeyOpt = fun (Keys) -> [{keys, Keys}, {object_format, proplist}]end,
               Input = <<"{\"foo\":\"ok\"}">>,
               ?assertEqual([{<<"foo">>, <<"ok">>}], jsone:decode(Input, KeyOpt(binary))),
               ?assertEqual([{foo, <<"ok">>}], jsone:decode(Input, KeyOpt(atom))),
@@ -286,31 +257,32 @@ decode_test_() ->
               ?assertEqual([{<<"@#$%^!">>, <<"ok">>}], jsone:decode(<<"{\"@#$%^!\":\"ok\"}">>, KeyOpt(attempt_atom))),
               Value = integer_to_binary(1234),
               % do not make atom in test code
-              [{Atom,  <<"ok">>}] = jsone:decode(<<"{\"", Value/binary, "\":\"ok\"}">>, KeyOpt(atom)),
+              [{Atom, <<"ok">>}] = jsone:decode(<<"{\"", Value/binary, "\":\"ok\"}">>, KeyOpt(atom)),
               ?assertEqual(Value, atom_to_binary(Atom, latin1))
       end},
      {"garbage remainings chars",
       fun () ->
               ?assertError(badarg, jsone:decode(<<"1@">>)),
-              ?assertEqual(1, jsone:decode(<<"1 \n\t\r ">>)) % Whitespaces are OK
+              ?assertEqual(1, jsone:decode(<<"1 \n\t\r ">>))  % Whitespaces are OK
       end},
 
      %% Others
      {"compound data",
       fun () ->
-              Input    = <<"  [true, {\"1\" : 2, \"array\":[[[[1]]], {\"ab\":\"cd\"}, false]}, null]   ">>,
+              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
+      fun () ->
+              ?assertEqual({ok, undefined, <<>>}, jsone_decode:decode(<<"null">>, [undefined_as_null])),  % OK
+              ?assertEqual({ok, null, <<>>}, jsone_decode:decode(<<"null">>, []))  % OK
       end},
      {"Invalid UTF-8 characters",
       fun () ->
-              Input = <<123,34,105,100,34,58,34,190,72,94,90,253,121,94,71,73,68,91,122,211,253,32,94,86,67,163,253,230,34,125>>,
+              Input =
+                  <<123, 34, 105, 100, 34, 58, 34, 190, 72, 94, 90, 253, 121, 94, 71, 73, 68, 91, 122, 211, 253, 32, 94,
+                    86, 67, 163, 253, 230, 34, 125>>,
               ?assertMatch({ok, _, _}, jsone:try_decode(Input)),
               ?assertMatch({error, {badarg, _}}, jsone:try_decode(Input, [reject_invalid_utf8]))
-      end}
-    ].
+      end}].

+ 111 - 124
test/jsone_encode_tests.erl

@@ -19,52 +19,30 @@
 encode_test_() ->
     [
      %% Symbols
-     {"false",
-      fun () ->
-              ?assertEqual({ok, <<"false">>}, jsone_encode:encode(false))
-      end},
-     {"true",
-      fun () ->
-              ?assertEqual({ok, <<"true">>}, jsone_encode:encode(true))
-      end},
-     {"null",
-      fun () ->
-              ?assertEqual({ok, <<"null">>}, jsone_encode:encode(null))
-      end},
+     {"false", fun () -> ?assertEqual({ok, <<"false">>}, jsone_encode:encode(false))end},
+     {"true", fun () -> ?assertEqual({ok, <<"true">>}, jsone_encode:encode(true))end},
+     {"null", fun () -> ?assertEqual({ok, <<"null">>}, jsone_encode:encode(null))end},
 
      %% Numbers: Inline json term
      {"json",
       fun () ->
-              ?assertEqual(
-                 {ok, <<"{\"foo\":[1,2,3],\"bar\":\"",195,169,"ok\"}">>},
-                 jsone_encode:encode(
-                   ?OBJ2(foo, {{json, ["["|[$1, ",2",<<",3]">>]]}},
-                         <<"bar">>, {{json_utf8, [$", 233, "ok", $"]}}))),
-              ?assertEqual(
-                 {ok, <<"{\"foo\":[1,2,3],\"bar\":\"",233,"ok\"}">>},
-                 jsone_encode:encode(
-                   ?OBJ2(foo, {{json, ["["|[$1, ",2",<<",3]">>]]}},
-                         <<"bar">>, {{json, [$", 233, "ok", $"]}}))),
-              ?assertEqual(
-                 {ok, <<"{\"json\":\"[1,2,3]\"}">>},
-                 jsone_encode:encode([{json, <<"[1,2,3]">>}])),
-              ?assertEqual(
-                 {ok, <<"[[1,2,3]]">>},
-                 jsone_encode:encode([{{json, <<"[1,2,3]">>}}]))
+              ?assertEqual({ok, <<"{\"foo\":[1,2,3],\"bar\":\"", 195, 169, "ok\"}">>},
+                           jsone_encode:encode(?OBJ2(foo,
+                                                     {{json, ["[" | [$1, ",2", <<",3]">>]]}},
+                                                     <<"bar">>,
+                                                     {{json_utf8, [$", 233, "ok", $"]}}))),
+              ?assertEqual({ok, <<"{\"foo\":[1,2,3],\"bar\":\"", 233, "ok\"}">>},
+                           jsone_encode:encode(?OBJ2(foo,
+                                                     {{json, ["[" | [$1, ",2", <<",3]">>]]}},
+                                                     <<"bar">>,
+                                                     {{json, [$", 233, "ok", $"]}}))),
+              ?assertEqual({ok, <<"{\"json\":\"[1,2,3]\"}">>}, jsone_encode:encode([{json, <<"[1,2,3]">>}])),
+              ?assertEqual({ok, <<"[[1,2,3]]">>}, jsone_encode:encode([{{json, <<"[1,2,3]">>}}]))
       end},
      %% Numbers: Integer
-     {"zero",
-      fun () ->
-              ?assertEqual({ok, <<"0">>}, jsone_encode:encode(0))
-      end},
-     {"positive integer",
-      fun () ->
-              ?assertEqual({ok, <<"1">>}, jsone_encode:encode(1))
-      end},
-     {"negative integer",
-      fun () ->
-              ?assertEqual({ok, <<"-1">>}, jsone_encode:encode(-1))
-      end},
+     {"zero", fun () -> ?assertEqual({ok, <<"0">>}, jsone_encode:encode(0))end},
+     {"positive integer", fun () -> ?assertEqual({ok, <<"1">>}, jsone_encode:encode(1))end},
+     {"negative integer", fun () -> ?assertEqual({ok, <<"-1">>}, jsone_encode:encode(-1))end},
      {"large number",
       fun () ->
               ?assertEqual({ok, <<"11111111111111111111111111111111111111111111111111111111111111111111111">>},
@@ -82,24 +60,18 @@ encode_test_() ->
       fun () ->
               Input = 1.23,
               ?assertEqual({ok, <<"1.22999999999999998224e+00">>}, jsone_encode:encode(Input)),
-              ?assertEqual({ok, <<"1.2300e+00">>},                 jsone_encode:encode(Input, [{float_format, [{scientific, 4}]}])),
-              ?assertEqual({ok, <<"1.2e+00">>},                    jsone_encode:encode(Input, [{float_format, [{scientific, 1}]}])),
-              ?assertEqual({ok, <<"1.2300">>},                     jsone_encode:encode(Input, [{float_format, [{decimals, 4}]}])),
-              ?assertEqual({ok, <<"1.23">>},                       jsone_encode:encode(Input, [{float_format, [{decimals, 4}, compact]}]))
+              ?assertEqual({ok, <<"1.2300e+00">>}, jsone_encode:encode(Input, [{float_format, [{scientific, 4}]}])),
+              ?assertEqual({ok, <<"1.2e+00">>}, jsone_encode:encode(Input, [{float_format, [{scientific, 1}]}])),
+              ?assertEqual({ok, <<"1.2300">>}, jsone_encode:encode(Input, [{float_format, [{decimals, 4}]}])),
+              ?assertEqual({ok, <<"1.23">>}, jsone_encode:encode(Input, [{float_format, [{decimals, 4}, compact]}]))
       end},
 
      %% Strings
-     {"simple string",
-      fun () ->
-              ?assertEqual({ok, <<"\"abc\"">>}, jsone_encode:encode(<<"abc">>))
-      end},
-     {"atom is regarded as string",
-      fun () ->
-              ?assertEqual({ok, <<"\"abc\"">>}, jsone_encode:encode(abc))
-      end},
+     {"simple string", fun () -> ?assertEqual({ok, <<"\"abc\"">>}, jsone_encode:encode(<<"abc">>))end},
+     {"atom is regarded as string", fun () -> ?assertEqual({ok, <<"\"abc\"">>}, jsone_encode:encode(abc))end},
      {"string: contains escaped characters",
       fun () ->
-              Input    = <<"\"\/\\\b\f\n\r\t">>,
+              Input = <<"\"\/\\\b\f\n\r\t">>,
               Expected = list_to_binary([$", [[$\\, C] || C <- [$", $/, $\\, $b, $f, $n, $r, $t]], $"]),
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input)),
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input, [native_utf8]))
@@ -112,8 +84,8 @@ encode_test_() ->
       end},
      {"string: contains control characters",
       fun () ->
-              Ctrls    = lists:seq(16#00, 16#1F) -- [$\b, $\f, $\n, $\r, $\t],
-              Input    = list_to_binary(Ctrls),
+              Ctrls = lists:seq(16#00, 16#1F) -- [$\b, $\f, $\n, $\r, $\t],
+              Input = list_to_binary(Ctrls),
               Expected = list_to_binary([$", [io_lib:format("\\u00~2.16.0b", [C]) || C <- Ctrls], $"]),
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input)),
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input, [native_utf8]))
@@ -121,14 +93,14 @@ encode_test_() ->
      {"string: contains multi-byte (UTF-8 encoded) characters",
       fun () ->
               %% japanese
-              Input1    = <<"あいうえお">>,  % assumed that the encoding of this file is UTF-8
+              Input1 = <<"あいうえお">>,  % assumed that the encoding of this file is UTF-8
               Expected1 = <<"\"\\u3042\\u3044\\u3046\\u3048\\u304a\"">>,
               ?assertEqual({ok, Expected1}, jsone_encode:encode(Input1)),
               Expected12 = <<$", Input1/binary, $">>,
               ?assertEqual({ok, Expected12}, jsone_encode:encode(Input1, [native_utf8])),
 
               %% other multi-byte characters
-              Input2    = <<"۝۞ႮႯ">>,
+              Input2 = <<"۝۞ႮႯ">>,
               Expected2 = <<"\"\\u06dd\\u06de\\u10ae\\u10af\"">>,
               ?assertEqual({ok, Expected2}, jsone_encode:encode(Input2)),
               Expected22 = <<$", Input2/binary, $">>,
@@ -136,7 +108,7 @@ encode_test_() ->
       end},
      {"string: containts surrogate pairs",
       fun () ->
-              Input    = <<"𢁉𢂚𢃼">>,
+              Input = <<"𢁉𢂚𢃼">>,
               Expected = <<"\"\\ud848\\udc49\\ud848\\udc9a\\ud848\\udcfc\"">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input))
       end},
@@ -144,49 +116,55 @@ encode_test_() ->
      %% Strings variant: Datetimes
      {"datetime: iso8601: utc",
       fun () ->
-              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>}, jsone_encode:encode({{2015,6,25},{14,57,25}})),
-              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>}, jsone_encode:encode({{2015,6,25},{14,57,25}}, [{datetime_format, iso8601}])),
-              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>}, jsone_encode:encode({{2015,6,25},{14,57,25}}, [{datetime_format, {iso8601, utc}}]))
+              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>}, jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}})),
+              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>},
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}}, [{datetime_format, iso8601}])),
+              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>},
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}}, [{datetime_format, {iso8601, utc}}]))
       end},
      {"datetime: iso8601: local",
       fun () ->
-              {ok, Json} = jsone_encode:encode({{2015,6,25},{14,57,25}}, [{datetime_format, {iso8601, local}}]),
+              {ok, Json} = jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}}, [{datetime_format, {iso8601, local}}]),
 
-              UTC = {{1970, 1, 2}, {0,0,0}},
-              Local = calendar:universal_time_to_local_time({{1970, 1, 2}, {0,0,0}}),
+              UTC = {{1970, 1, 2}, {0, 0, 0}},
+              Local = calendar:universal_time_to_local_time({{1970, 1, 2}, {0, 0, 0}}),
               case UTC =:= Local of
-                  false -> ?assertMatch(<<"\"2015-06-25T14:57:25",_:6/binary,"\"">>, Json);
-                  true  -> ?assertMatch(<<"\"2015-06-25T14:57:25Z\"">>, Json)
+                  false ->
+                      ?assertMatch(<<"\"2015-06-25T14:57:25", _:6/binary, "\"">>, Json);
+                  true ->
+                      ?assertMatch(<<"\"2015-06-25T14:57:25Z\"">>, Json)
               end
       end},
      {"datetime: iso8601: timezone",
       fun () ->
-              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>},      jsone_encode:encode({{2015,6,25},{14,57,25}}, [{datetime_format, {iso8601, 0}}])),
-              ?assertEqual({ok, <<"\"2015-06-25T14:57:25+00:01\"">>}, jsone_encode:encode({{2015,6,25},{14,57,25}}, [{datetime_format, {iso8601, 60}}])),
-              ?assertEqual({ok, <<"\"2015-06-25T14:57:25-00:01\"">>}, jsone_encode:encode({{2015,6,25},{14,57,25}}, [{datetime_format, {iso8601, -60}}]))
+              ?assertEqual({ok, <<"\"2015-06-25T14:57:25Z\"">>},
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}}, [{datetime_format, {iso8601, 0}}])),
+              ?assertEqual({ok, <<"\"2015-06-25T14:57:25+00:01\"">>},
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}}, [{datetime_format, {iso8601, 60}}])),
+              ?assertEqual({ok, <<"\"2015-06-25T14:57:25-00:01\"">>},
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 25}}, [{datetime_format, {iso8601, -60}}]))
       end},
      {"datetime as head of array",
-       ?_assertEqual({ok, <<"[\"2015-06-25T14:57:25Z\"]">>},
-                      jsone_encode:encode([{{2015,6,25},{14,57,25}}]))},
+      ?_assertEqual({ok, <<"[\"2015-06-25T14:57:25Z\"]">>}, jsone_encode:encode([{{2015, 6, 25}, {14, 57, 25}}]))},
 
      {"datetime: iso8601: with fractions of seconds",
       fun () ->
               ?assertEqual({ok, <<"\"2015-06-25T14:57:25.325Z\"">>},
-                           jsone_encode:encode({{2015,6,25},{14,57,25.3245}})),
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 25.3245}})),
               ?assertEqual({ok, <<"\"2015-06-25T14:57:05.320Z\"">>},
-                           jsone_encode:encode({{2015,6,25},{14,57,5.32}}))
+                           jsone_encode:encode({{2015, 6, 25}, {14, 57, 5.32}}))
       end},
 
      %% Arrays
      {"simple array",
       fun () ->
-              Input    = [1, 2, 3],
+              Input = [1, 2, 3],
               Expected = <<"[1,2,3]">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input))
       end},
      {"empty array",
       fun () ->
-              Input    = [],
+              Input = [],
               Expected = <<"[]">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input))
       end},
@@ -194,16 +172,16 @@ encode_test_() ->
      %% Objects
      {"simple object",
       fun () ->
-              Input1   = {[{<<"key">>, <<"value">>}, {<<"1">>, 2}]},
-              Input2   = [{<<"key">>, <<"value">>}, {<<"1">>, 2}],
+              Input1 = {[{<<"key">>, <<"value">>}, {<<"1">>, 2}]},
+              Input2 = [{<<"key">>, <<"value">>}, {<<"1">>, 2}],
               Expected = <<"{\"key\":\"value\",\"1\":2}">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input1)),
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input2))
       end},
      {"empty object",
       fun () ->
-              Input1   = {[]},
-              Input2   = [{}],
+              Input1 = {[]},
+              Input2 = [{}],
               Expected = <<"{}">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input1)),
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input2))
@@ -228,29 +206,32 @@ encode_test_() ->
      {"object_key_type option",
       fun () ->
               %% key: atom
-              ?assertEqual({ok, <<"{\"a\":2}">>}, jsone_encode:encode(?OBJ1(a, 2), [{object_key_type, string}])), % OK
-              ?assertEqual({ok, <<"{\"a\":2}">>}, jsone_encode:encode(?OBJ1(a, 2), [{object_key_type, scalar}])), % OK
+              ?assertEqual({ok, <<"{\"a\":2}">>}, jsone_encode:encode(?OBJ1(a, 2), [{object_key_type, string}])),  % OK
+              ?assertEqual({ok, <<"{\"a\":2}">>}, jsone_encode:encode(?OBJ1(a, 2), [{object_key_type, scalar}])),  % OK
               ?assertEqual({ok, <<"{\"a\":2}">>}, jsone_encode:encode(?OBJ1(a, 2), [{object_key_type, value}])),  % OK
 
               %% key: number
-              ?assertMatch({error, {badarg, _}},  jsone_encode:encode(?OBJ1(1, 2), [{object_key_type, string}])), % NG
-              ?assertEqual({ok, <<"{\"1\":2}">>}, jsone_encode:encode(?OBJ1(1, 2), [{object_key_type, scalar}])), % OK
+              ?assertMatch({error, {badarg, _}}, jsone_encode:encode(?OBJ1(1, 2), [{object_key_type, string}])),  % NG
+              ?assertEqual({ok, <<"{\"1\":2}">>}, jsone_encode:encode(?OBJ1(1, 2), [{object_key_type, scalar}])),  % OK
               ?assertEqual({ok, <<"{\"1\":2}">>}, jsone_encode:encode(?OBJ1(1, 2), [{object_key_type, value}])),  % OK
 
               %% key: datetime
-              ?assertMatch({error, {badarg, _}},  jsone_encode:encode(?OBJ1({{2000,1,1}, {0,0,0}}, 2), [{object_key_type, string}])), % NG
-              ?assertEqual({ok, <<"{\"2000-01-01T00:00:00Z\":2}">>}, jsone_encode:encode(?OBJ1({{2000,1,1}, {0,0,0}}, 2), [{object_key_type, scalar}])), % OK
-              ?assertEqual({ok, <<"{\"2000-01-01T00:00:00Z\":2}">>}, jsone_encode:encode(?OBJ1({{2000,1,1}, {0,0,0}}, 2), [{object_key_type, value}])),  % OK
+              ?assertMatch({error, {badarg, _}},
+                           jsone_encode:encode(?OBJ1({{2000, 1, 1}, {0, 0, 0}}, 2), [{object_key_type, string}])),  % NG
+              ?assertEqual({ok, <<"{\"2000-01-01T00:00:00Z\":2}">>},
+                           jsone_encode:encode(?OBJ1({{2000, 1, 1}, {0, 0, 0}}, 2), [{object_key_type, scalar}])),  % OK
+              ?assertEqual({ok, <<"{\"2000-01-01T00:00:00Z\":2}">>},
+                           jsone_encode:encode(?OBJ1({{2000, 1, 1}, {0, 0, 0}}, 2), [{object_key_type, value}])),  % OK
 
               %% key: array
-              ?assertMatch({error, {badarg, _}},    jsone_encode:encode(?OBJ1([1], 2), [{object_key_type, string}])), % NG
-              ?assertMatch({error, {badarg, _}},    jsone_encode:encode(?OBJ1([1], 2), [{object_key_type, scalar}])), % NG
+              ?assertMatch({error, {badarg, _}}, jsone_encode:encode(?OBJ1([1], 2), [{object_key_type, string}])),  % NG
+              ?assertMatch({error, {badarg, _}}, jsone_encode:encode(?OBJ1([1], 2), [{object_key_type, scalar}])),  % NG
               ?assertEqual({ok, <<"{\"[1]\":2}">>}, jsone_encode:encode(?OBJ1([1], 2), [{object_key_type, value}])),  % OK
 
               %% key: object
-              ?assertMatch({error, {badarg, _}},   jsone_encode:encode(?OBJ1(?OBJ0, 2), [{object_key_type, string}])), % NG
-              ?assertMatch({error, {badarg, _}},   jsone_encode:encode(?OBJ1(?OBJ0, 2), [{object_key_type, scalar}])), % NG
-              ?assertEqual({ok, <<"{\"{}\":2}">>}, jsone_encode:encode(?OBJ1(?OBJ0, 2), [{object_key_type, value}]))    % OK
+              ?assertMatch({error, {badarg, _}}, jsone_encode:encode(?OBJ1(?OBJ0, 2), [{object_key_type, string}])),  % NG
+              ?assertMatch({error, {badarg, _}}, jsone_encode:encode(?OBJ1(?OBJ0, 2), [{object_key_type, scalar}])),  % NG
+              ?assertEqual({ok, <<"{\"{}\":2}">>}, jsone_encode:encode(?OBJ1(?OBJ0, 2), [{object_key_type, value}]))  % OK
       end},
      {"non binary object member key is disallowed",
       fun () ->
@@ -258,23 +239,24 @@ encode_test_() ->
               ?assertMatch({error, {badarg, _}}, jsone_encode:encode({[{"1", 2}]}))
       end},
      {"undefined_as_null option",
-      fun() ->
-              ?assertEqual({ok,<<"null">>},          jsone_encode:encode(undefined,[undefined_as_null])), % OK
-              ?assertEqual({ok,<<"\"undefined\"">>}, jsone_encode:encode(undefined,[])) % OK
+      fun () ->
+              ?assertEqual({ok, <<"null">>}, jsone_encode:encode(undefined, [undefined_as_null])),  % OK
+              ?assertEqual({ok, <<"\"undefined\"">>}, jsone_encode:encode(undefined, []))  % OK
       end},
      {"skip_undefined option",
-      fun() ->
+      fun () ->
               Object = #{<<"1">> => undefined, <<"2">> => 3, <<"3">> => undefined},
-              ?assertEqual({ok,<<"{\"1\":null,\"2\":3,\"3\":null}">>}, jsone_encode:encode(Object,[undefined_as_null])),
-              ?assertEqual({ok,<<"{\"2\":3}">>},                       jsone_encode:encode(Object,[skip_undefined]))
+              ?assertEqual({ok, <<"{\"1\":null,\"2\":3,\"3\":null}">>},
+                           jsone_encode:encode(Object, [undefined_as_null])),
+              ?assertEqual({ok, <<"{\"2\":3}">>}, jsone_encode:encode(Object, [skip_undefined]))
       end},
 
      %% Pretty Print
      {"space",
       fun () ->
               ?assertEqual({ok, <<"[]">>}, jsone_encode:encode([], [{space, 1}])),
-              ?assertEqual({ok, <<"[1, 2, 3]">>}, jsone_encode:encode([1,2,3], [{space, 1}])),
-              ?assertEqual({ok, <<"[1,  2,  3]">>}, jsone_encode:encode([1,2,3], [{space, 2}])),
+              ?assertEqual({ok, <<"[1, 2, 3]">>}, jsone_encode:encode([1, 2, 3], [{space, 1}])),
+              ?assertEqual({ok, <<"[1,  2,  3]">>}, jsone_encode:encode([1, 2, 3], [{space, 2}])),
               ?assertEqual({ok, <<"{}">>}, jsone_encode:encode(?OBJ0, [{space, 1}])),
               ?assertEqual({ok, <<"{\"a\": 1, \"b\": 2}">>}, jsone_encode:encode(?OBJ2(a, 1, b, 2), [{space, 1}])),
               ?assertEqual({ok, <<"{\"a\":  1,  \"b\":  2}">>}, jsone_encode:encode(?OBJ2(a, 1, b, 2), [{space, 2}]))
@@ -282,37 +264,44 @@ encode_test_() ->
      {"indent",
       fun () ->
               ?assertEqual({ok, <<"[]">>}, jsone_encode:encode([], [{indent, 1}])),
-              ?assertEqual({ok, <<"[\n 1,\n 2,\n 3\n]">>}, jsone_encode:encode([1,2,3], [{indent, 1}])),
-              ?assertEqual({ok, <<"[\n  1,\n  2,\n  3\n]">>}, jsone_encode:encode([1,2,3], [{indent, 2}])),
+              ?assertEqual({ok, <<"[\n 1,\n 2,\n 3\n]">>}, jsone_encode:encode([1, 2, 3], [{indent, 1}])),
+              ?assertEqual({ok, <<"[\n  1,\n  2,\n  3\n]">>}, jsone_encode:encode([1, 2, 3], [{indent, 2}])),
               ?assertEqual({ok, <<"{}">>}, jsone_encode:encode(?OBJ0, [{indent, 1}])),
-              ?assertEqual({ok, <<"{\n \"a\":1,\n \"b\":2\n}">>}, jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 1}])),
-              ?assertEqual({ok, <<"{\n  \"a\":1,\n  \"b\":2\n}">>}, jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 2}]))
+              ?assertEqual({ok, <<"{\n \"a\":1,\n \"b\":2\n}">>},
+                           jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 1}])),
+              ?assertEqual({ok, <<"{\n  \"a\":1,\n  \"b\":2\n}">>},
+                           jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 2}]))
       end},
      {"indent+space",
       fun () ->
               ?assertEqual({ok, <<"[]">>}, jsone_encode:encode([], [{indent, 1}, {space, 1}])),
-              ?assertEqual({ok, <<"[\n 1,\n 2,\n 3\n]">>}, jsone_encode:encode([1,2,3], [{indent, 1}, {space, 1}])),
-              ?assertEqual({ok, <<"[\n  1,\n  2,\n  3\n]">>}, jsone_encode:encode([1,2,3], [{indent, 2}, {space, 2}])),
+              ?assertEqual({ok, <<"[\n 1,\n 2,\n 3\n]">>}, jsone_encode:encode([1, 2, 3], [{indent, 1}, {space, 1}])),
+              ?assertEqual({ok, <<"[\n  1,\n  2,\n  3\n]">>},
+                           jsone_encode:encode([1, 2, 3], [{indent, 2}, {space, 2}])),
               ?assertEqual({ok, <<"{}">>}, jsone_encode:encode(?OBJ0, [{indent, 1}, {space, 1}])),
-              ?assertEqual({ok, <<"{\n \"a\": 1,\n \"b\": 2\n}">>}, jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 1}, {space, 1}])),
-              ?assertEqual({ok, <<"{\n  \"a\":  1,\n  \"b\":  2\n}">>}, jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 2}, {space, 2}]))
+              ?assertEqual({ok, <<"{\n \"a\": 1,\n \"b\": 2\n}">>},
+                           jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 1}, {space, 1}])),
+              ?assertEqual({ok, <<"{\n  \"a\":  1,\n  \"b\":  2\n}">>},
+                           jsone_encode:encode(?OBJ2(a, 1, b, 2), [{indent, 2}, {space, 2}]))
       end},
 
      %% `map_unknown_value` option
      {"`map_unknown_value` option",
       fun () ->
-              Input = [{1,2,3,4}],
-              MapFun = fun ({_,_,_,_} = Ip4) -> {ok, list_to_binary(inet:ntoa(Ip4))};
-                           (_)               -> error
-                       end,
+              Input = [{1, 2, 3, 4}],
+              MapFun =
+                  fun ({_, _, _, _} = Ip4) ->
+                          {ok, list_to_binary(inet:ntoa(Ip4))};
+                      (_) ->
+                          error
+                  end,
               Expected = <<"[\"1.2.3.4\"]">>,
               ?assertEqual(Expected, jsone:encode(Input, [{map_unknown_value, MapFun}]))
       end},
      {"`map_unknown_value` option with singleton tuple",
       fun () ->
               Input = [{foo}],
-              MapFun = fun (Value) -> {ok, unicode:characters_to_binary(io_lib:format("~p~n", [Value]))}
-                       end,
+              MapFun = fun (Value) -> {ok, unicode:characters_to_binary(io_lib:format("~p~n", [Value]))}end,
               Expected = <<"[\"{foo}\\n\"]">>,
               ?assertEqual(Expected, jsone:encode(Input, [{map_unknown_value, MapFun}]))
       end},
@@ -329,11 +318,13 @@ encode_test_() ->
      %% Others
      {"compound data",
       fun () ->
-              Input    = [true, {[{<<"1">>, 2}, {<<"array">>, [[[[1]]], {[{<<"ab">>, <<"cd">>}]}, [], ?OBJ0, false]}]}, null],
+              Input =
+                  [true, {[{<<"1">>, 2}, {<<"array">>, [[[[1]]], {[{<<"ab">>, <<"cd">>}]}, [], ?OBJ0, false]}]}, null],
               Expected = <<"[true,{\"1\":2,\"array\":[[[[1]]],{\"ab\":\"cd\"},[],{},false]},null]">>,
               ?assertEqual({ok, Expected}, jsone_encode:encode(Input)),
 
-              PpExpected = <<"[\n true,\n {\n  \"1\": 2,\n  \"array\": [\n   [\n    [\n     [\n      1\n     ]\n    ]\n   ],\n   {\n    \"ab\": \"cd\"\n   },\n   [],\n   {},\n   false\n  ]\n },\n null\n]">>,
+              PpExpected =
+                  <<"[\n true,\n {\n  \"1\": 2,\n  \"array\": [\n   [\n    [\n     [\n      1\n     ]\n    ]\n   ],\n   {\n    \"ab\": \"cd\"\n   },\n   [],\n   {},\n   false\n  ]\n },\n null\n]">>,
               ?assertEqual({ok, PpExpected}, jsone_encode:encode(Input, [{indent, 1}, {space, 1}]))
       end},
      {"invalid value",
@@ -343,14 +334,10 @@ encode_test_() ->
               ?assertEqual({ok, <<$", PidString/binary, $">>}, jsone_encode:encode(Pid)),
               ?assertMatch({error, {badarg, _}}, jsone_encode:encode(Pid, [{map_unknown_value, undefined}]))
       end},
-     {"wrong option",
-      fun () ->
-              ?assertError(badarg, jsone_encode:encode(1, [{no_such_option, hoge}]))
-      end},
+     {"wrong option", fun () -> ?assertError(badarg, jsone_encode:encode(1, [{no_such_option, hoge}]))end},
      {"canonical_form",
       fun () ->
-          Obj1 = ?OBJECT_FROM_LIST( [{<<"key", (integer_to_binary(I))/binary >>, I} || I <- lists:seq(1000, 0, -1)] ),
-          Obj2 = ?OBJECT_FROM_LIST( [{<<"key", (integer_to_binary(I))/binary >>, I} || I <- lists:seq(0, 1000, 1)] ),
-          ?assertEqual(jsone_encode:encode(Obj1, [canonical_form]), jsone_encode:encode(Obj2, [canonical_form]))
-      end}
-    ].
+              Obj1 = ?OBJECT_FROM_LIST([{<<"key", (integer_to_binary(I))/binary>>, I} || I <- lists:seq(1000, 0, -1)]),
+              Obj2 = ?OBJECT_FROM_LIST([{<<"key", (integer_to_binary(I))/binary>>, I} || I <- lists:seq(0, 1000, 1)]),
+              ?assertEqual(jsone_encode:encode(Obj1, [canonical_form]), jsone_encode:encode(Obj2, [canonical_form]))
+      end}].

+ 8 - 11
test/jsone_inet_tests.erl

@@ -11,8 +11,7 @@ format_ipv4_test() ->
 
 format_ipv6_test() ->
     Addresses =
-        [
-         <<"::127.0.0.1">>,
+        [<<"::127.0.0.1">>,
          <<"::ffff:192.0.2.1">>,
          <<"::ffff:0:255.255.255.255">>,
          <<"64:ff9b::0.0.0.0">>,
@@ -24,15 +23,13 @@ format_ipv6_test() ->
          <<"2001:db8::1:0:0:1">>,
          <<"2001:db8:0:1:1:1:1:1">>,
          <<"2001:0:0:1::1">>,
-         <<"2001:db8:85a3::8a2e:370:7334">>
-        ],
-    lists:foreach(
-      fun (Expected) ->
-              {ok, Addr} = inet:parse_ipv6_address(binary_to_list(Expected)),
-              {ok, Bin} = jsone_inet:ip_address_to_json_string(Addr),
-              ?assertEqual(Expected, Bin)
-      end,
-      Addresses).
+         <<"2001:db8:85a3::8a2e:370:7334">>],
+    lists:foreach(fun (Expected) ->
+                          {ok, Addr} = inet:parse_ipv6_address(binary_to_list(Expected)),
+                          {ok, Bin} = jsone_inet:ip_address_to_json_string(Addr),
+                          ?assertEqual(Expected, Bin)
+                  end,
+                  Addresses).
 
 invalid_ip_addr_test() ->
     ?assertEqual(jsone_inet:ip_address_to_json_string(foo), error),