Переглянути джерело

Add maps formatting

Note that compiling on OTP 17.0, or later, will produce beam files
(specifically lager_trunc_io) that are incompatible with R16B03-1, or
earlier, due to erlang:is_map/1 using a new beam opcode (156). However
if compiled on R16B03-1, or earlier, will produce beams files that are
compatible with 17.0, and later, and maps will be formatted where
supported by the active OTP release.
pull/236/head
James Fish 10 роки тому
джерело
коміт
8685853c91
3 змінених файлів з 108 додано та 1 видалено
  1. +5
    -0
      dialyzer.ignore-warnings
  2. +1
    -1
      rebar.config
  3. +102
    -0
      src/lager_trunc_io.erl

+ 5
- 0
dialyzer.ignore-warnings Переглянути файл

@ -0,0 +1,5 @@
lager_trunc_io.erl:283: Call to missing or unexported function erlang:is_map/1
lager_trunc_io.erl:335: Call to missing or unexported function erlang:map_size/1
Unknown functions:
lager_default_tracer:info/1
maps:to_list/1

+ 1
- 1
rebar.config Переглянути файл

@ -6,7 +6,7 @@
]}.
{xref_checks, []}.
{xref_queries, [{"(XC - UC) || (XU - X - B - lager_default_tracer : Mod)", []}]}.
{xref_queries, [{"(XC - UC) || (XU - X - B - lager_default_tracer : Mod - erlang:\"(is_map|map_size)\"/1 - maps:to_list/1)", []}]}.
{cover_enabled, true}.
{edoc_opts, [{stylesheet_file, "./priv/edoc.css"}]}.

+ 102
- 0
src/lager_trunc_io.erl Переглянути файл

@ -277,6 +277,15 @@ print(List, Max, Options) when is_list(List) ->
_ ->
{R, Len} = list_body(List, Max - 2, dec_depth(Options), false),
{[$[, R, $]], Len + 2}
end;
print(Map, Max, Options) ->
case erlang:is_builtin(erlang, is_map, 1) andalso erlang:is_map(Map) of
true ->
{MapBody, Len} = map_body(Map, Max - 3, dec_depth(Options)),
{[$#, ${, MapBody, $}], Len + 3};
false ->
error(badarg, [Map, Max, Options])
end.
%% Returns {List, Length}
@ -322,6 +331,36 @@ list_bodyc(X, Max, Options, _Tuple) -> %% improper list
{List, Len} = print(X, Max - 1, Options),
{[$|,List], Len + 1}.
map_body(Map, Max, #print_options{depth=Depth}) when Max < 4; Depth =:= 0 ->
case erlang:map_size(Map) of
0 -> {[], 0};
_ -> {"...", 3}
end;
map_body(Map, Max, Options) ->
case maps:to_list(Map) of
[] ->
{[], 0};
[{Key, Value} | Rest] ->
{KeyStr, KeyLen} = print(Key, Max - 4, Options),
DiffLen = KeyLen + 4,
{ValueStr, ValueLen} = print(Value, Max - DiffLen, Options),
DiffLen2 = DiffLen + ValueLen,
{Final, FLen} = map_bodyc(Rest, Max - DiffLen2, dec_depth(Options)),
{[KeyStr, " => ", ValueStr | Final], DiffLen2 + FLen}
end.
map_bodyc([], _Max, _Options) ->
{[], 0};
map_bodyc(_Rest, Max,#print_options{depth=Depth}) when Max < 5; Depth =:= 0 ->
{",...", 4};
map_bodyc([{Key, Value} | Rest], Max, Options) ->
{KeyStr, KeyLen} = print(Key, Max - 5, Options),
DiffLen = KeyLen + 5,
{ValueStr, ValueLen} = print(Value, Max - DiffLen, Options),
DiffLen2 = DiffLen + ValueLen,
{Final, FLen} = map_bodyc(Rest, Max - DiffLen2, dec_depth(Options)),
{[$,, KeyStr, " => ", ValueStr | Final], DiffLen2 + FLen}.
%% The head of a list we hope is ascii. Examples:
%%
%% [65,66,67] -> "ABC"
@ -703,6 +742,46 @@ tuple_printing_test() ->
22835963083295358096932575511191922182123945984}], 53))),
ok.
map_printing_test() ->
case erlang:is_builtin(erlang, is_map, 1) of
true ->
?assertEqual("#{}", lists:flatten(format("~p", [maps:new()], 50))),
?assertEqual("#{}", lists:flatten(format("~p", [maps:new()], 3))),
?assertEqual("#{}", lists:flatten(format("~w", [maps:new()], 50))),
?assertError(badarg, lists:flatten(format("~s", [maps:new()], 50))),
?assertEqual("#{...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 1))),
?assertEqual("#{...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 6))),
?assertEqual("#{bar => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 7))),
?assertEqual("#{bar => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 9))),
?assertEqual("#{bar => foo}", lists:flatten(format("~p", [maps:from_list([{bar, foo}])], 10))),
?assertEqual("#{bar => ...,...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 9))),
?assertEqual("#{bar => foo,...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 10))),
?assertEqual("#{bar => foo,...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 17))),
?assertEqual("#{bar => foo,foo => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 18))),
?assertEqual("#{bar => foo,foo => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 19))),
?assertEqual("#{bar => foo,foo => ...}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 20))),
?assertEqual("#{bar => foo,foo => bar}", lists:flatten(format("~p", [maps:from_list([{bar, foo}, {foo, bar}])], 21))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => ...}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
22835963083295358096932575511191922182123945984}])], 10))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => ...}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
bar}])], 10))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => ...}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
bar}])], 53))),
?assertEqual("#{22835963083295358096932575511191922182123945984 => bar}",
lists:flatten(format("~w", [
maps:from_list([{22835963083295358096932575511191922182123945984,
bar}])], 54))),
ok;
false ->
ok
end.
unicode_test() ->
?assertEqual([231,167,129], lists:flatten(format("~s", [<<231,167,129>>], 50))),
?assertEqual([31169], lists:flatten(format("~ts", [<<231,167,129>>], 50))),
@ -726,6 +805,29 @@ depth_limit_test() ->
?assertEqual("{a,{b,{c,{...}}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 7], 50))),
?assertEqual("{a,{b,{c,{d}}}}", lists:flatten(format("~P", [{a, {b, {c, {d}}}}, 8], 50))),
case erlang:is_builtin(erlang, is_map, 1) of
true ->
?assertEqual("#{a => #{...}}",
lists:flatten(format("~P",
[maps:from_list([{a, maps:from_list([{b, maps:from_list([{c, d}])}])}]), 2], 50))),
?assertEqual("#{a => #{b => #{...}}}",
lists:flatten(format("~P",
[maps:from_list([{a, maps:from_list([{b, maps:from_list([{c, d}])}])}]), 3], 50))),
?assertEqual("#{a => #{b => #{c => d}}}",
lists:flatten(format("~P",
[maps:from_list([{a, maps:from_list([{b, maps:from_list([{c, d}])}])}]), 4], 50))),
?assertEqual("#{}", lists:flatten(format("~P", [maps:new(), 1], 50))),
?assertEqual("#{...}", lists:flatten(format("~P", [maps:from_list([{1,1}, {2,2}, {3,3}]), 1], 50))),
?assertEqual("#{1 => 1,...}", lists:flatten(format("~P", [maps:from_list([{1,1}, {2,2}, {3,3}]), 2], 50))),
?assertEqual("#{1 => 1,2 => 2,...}", lists:flatten(format("~P", [maps:from_list([{1,1}, {2,2}, {3,3}]), 3], 50))),
?assertEqual("#{1 => 1,2 => 2,3 => 3}", lists:flatten(format("~P", [maps:from_list([{1,1}, {2,2}, {3,3}]), 4], 50))),
ok;
false ->
ok
end,
?assertEqual("{\"a\",[...]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 3], 50))),
?assertEqual("{\"a\",[\"b\",[[...]|...]]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 6], 50))),
?assertEqual("{\"a\",[\"b\",[\"c\",[\"d\"]]]}", lists:flatten(format("~P", [{"a", ["b", ["c", ["d"]]]}, 9], 50))),

Завантаження…
Відмінити
Зберегти