Просмотр исходного кода

Add 'float_format' encoding option

Takeru Ohta 10 лет назад
Родитель
Сommit
20076d0d72
5 измененных файлов с 112 добавлено и 4 удалено
  1. 14 1
      README.md
  2. 49 1
      doc/jsone.md
  3. 36 1
      src/jsone.erl
  4. 4 1
      src/jsone_encode.erl
  5. 9 0
      test/jsone_encode_tests.erl

+ 14 - 1
README.md

@@ -1,4 +1,4 @@
-jsone (0.3.2)
+jsone (0.3.3)
 =============
 
 An Erlang library for encoding, decoding [JSON](http://json.org/index.html) data.
@@ -120,6 +120,19 @@ Usage Example
   null
 ]
 ok
+
+%% Number Format
+> jsone:encode(1). % integer
+<<"1">>
+
+> jsone:encode(1.23). % float
+<<"1.22999999999999998224e+00">> % default: scientific notation
+
+> jsone:encode(1.23, [{float_format, [{decimals, 4}]}]). % decimal notation
+<<"1.2300">>
+
+> jsone:encode(1.23, [{float_format, [{decimals, 4}, compact]}]). % compact decimal notation
+<<"1.23">>
 ```
 
 

+ 49 - 1
doc/jsone.md

@@ -41,7 +41,7 @@ decode_option() = {object_format, tuple | proplist | map}
 
 
 <pre><code>
-encode_option() = native_utf8 | {space, non_neg_integer()} | {indent, non_neg_integer()}
+encode_option() = native_utf8 | {float_format, [<a href="#type-float_format_option">float_format_option()</a>]} | {space, non_neg_integer()} | {indent, non_neg_integer()}
 </code></pre>
 
 
@@ -52,6 +52,12 @@ encode_option() = native_utf8 | {space, non_neg_integer()} | {indent, non_neg_in
 
 
 
+`{float_format, Optoins}`:
+- Encodes a `float()` value in the format which specified by `Options` <br />
+- default: `[{scientific, 20}]` <br />
+
+
+
 `{space, N}`: <br />
 - Inserts `N` spaces after every commna and colon <br />
 - default: `0` <br />
@@ -63,6 +69,48 @@ encode_option() = native_utf8 | {space, non_neg_integer()} | {indent, non_neg_in
 
 
 
+### <a name="type-float_format_option">float_format_option()</a> ###
+
+
+
+<pre><code>
+float_format_option() = {scientific, Decimals::0..249} | {decimals, Decimals::0..253} | compact
+</code></pre>
+
+
+
+
+`scientific`: <br />
+- The float will be formatted using scientific notation with `Decimals` digits of precision. <br />
+
+
+
+`decimals`: <br />
+- The encoded string will contain at most `Decimals` number of digits past the decimal point. <br />
+- If `compact` is provided the trailing zeros at the end of the string are truncated. <br />
+
+
+
+For more details, see [erlang:flaot_to_list/2](http://erlang.org/doc/man/erlang.md#float_to_list-2).
+
+
+
+```
+  > jsone:encode(1.23).
+  <<"1.22999999999999998224e+00">>
+  > jsone:encode(1.23, [{float_format, [{scientific, 4}]}]).
+  <"1.2300e+00">>
+  > jsone:encode(1.23, [{float_format, [{scientific, 1}]}]).
+  <<"1.2e+00">>
+  > jsone:encode(1.23, [{float_format, [{decimals, 4}]}]).
+  <<"1.2300">>
+  > jsone:encode(1.23, [{float_format, [{decimals, 4}, compact]}]).
+  <<"1.23">>
+```
+
+
+
+
 ### <a name="type-json_array">json_array()</a> ###
 
 

+ 36 - 1
src/jsone.erl

@@ -49,7 +49,8 @@
               json_object_format_map/0,
 
               encode_option/0,
-              decode_option/0
+              decode_option/0,
+              float_format_option/0
              ]).
 
 %%--------------------------------------------------------------------------------
@@ -69,12 +70,46 @@
 -type json_object_format_tuple() :: {json_object_members()}.
 -type json_object_format_proplist() :: [{}] | json_object_members().
 
+-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 />
+%%
+%% `decimals': <br />
+%% - The encoded string will contain at most `Decimals' number of digits past the decimal point. <br />
+%% - If `compact' is provided the trailing zeros at the end of the string are truncated. <br />
+%%
+%% For more details, see <a href="http://erlang.org/doc/man/erlang.html#float_to_list-2">erlang:flaot_to_list/2</a>.
+%%
+%% ```
+%% > jsone:encode(1.23).
+%% <<"1.22999999999999998224e+00">>
+%%
+%% > jsone:encode(1.23, [{float_format, [{scientific, 4}]}]).
+%% <"1.2300e+00">>
+%%
+%% > jsone:encode(1.23, [{float_format, [{scientific, 1}]}]).
+%% <<"1.2e+00">>
+%%
+%% > jsone:encode(1.23, [{float_format, [{decimals, 4}]}]).
+%% <<"1.2300">>
+%%
+%% > jsone:encode(1.23, [{float_format, [{decimals, 4}, compact]}]).
+%% <<"1.23">>
+%%'''
+
 -type encode_option() :: native_utf8
+                       | {float_format, [float_format_option()]}
                        | {space, non_neg_integer()}
                        | {indent, non_neg_integer()}.
 %% `native_utf8': <br />
 %% - Encodes UTF-8 characters as a human-readable(non-escaped) string <br />
 %%
+%% `{float_format, Optoins}`:
+%% - Encodes a `float()` value in the format which specified by `Options' <br />
+%% - default: `[{scientific, 20}]' <br />
+%%
 %% `{space, N}': <br />
 %% - Inserts `N' spaces after every commna and colon <br />
 %% - default: `0' <br />

+ 4 - 1
src/jsone_encode.erl

@@ -48,6 +48,7 @@
 
 -record(encode_opt_v1, {
           native_utf8 = false :: boolean(),
+          float_format = [{scientific, 20}] :: [jsone:float_format_option()],
           space = 0 :: non_neg_integer(),
           indent = 0 :: non_neg_integer()
          }).
@@ -92,7 +93,7 @@ value(null, Nexts, Buf, Opt)                         -> next(Nexts, <<Buf/binary
 value(false, Nexts, Buf, Opt)                        -> next(Nexts, <<Buf/binary, "false">>, Opt);
 value(true, Nexts, Buf, Opt)                         -> next(Nexts, <<Buf/binary, "true">>, 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))/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)                      -> object(Value, Nexts, Buf, Opt);
 value([{}], Nexts, Buf, Opt)                         -> object([], Nexts, Buf, Opt);
@@ -203,6 +204,8 @@ parse_options(Options) ->
 parse_option([], Opt) -> Opt;
 parse_option([native_utf8|T], Opt) ->
     parse_option(T, Opt?OPT{native_utf8=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(T, Opt?OPT{space = N});
 parse_option([{indent, N}|T], Opt) when is_integer(N), N >= 0 ->

+ 9 - 0
test/jsone_encode_tests.erl

@@ -46,6 +46,15 @@ encode_test_() ->
               ?assertMatch({ok, _}, jsone_encode:encode(Input)),
               ?assertEqual(Input, binary_to_float(element(2, jsone_encode:encode(Input))))
       end},
+     {"float_format option",
+      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]}]))
+      end},
 
      %% Strings
      {"simple string",