Преглед на файлове

Fixes and tests for deep-list handling in trunc_io:format

This solves an issue reported by 'cloudhead' in IRC where deep lists
weren't being flattened when printed with format specifiers like ~s ~p
and ~P, all of which should flatten the list.
pull/6/head
Andrew Thompson преди 13 години
родител
ревизия
03d3fa1a95
променени са 1 файла, в които са добавени 53 реда и са изтрити 12 реда
  1. +53
    -12
      src/lager_trunc_io.erl

+ 53
- 12
src/lager_trunc_io.erl Целия файл

@ -34,9 +34,13 @@
-author('matthias@corelatus.se').
%% And thanks to Chris Newcombe for a bug fix
-export([format/3, print/2, fprint/2, safe/2]). % interface functions
-export([perf/0, perf/3, perf1/0, test/0, test/2]). % testing functions
-version("$Id: trunc_io.erl,v 1.11 2009-02-23 12:01:06 matthias Exp $").
-ifdef(TEST).
-export([perf/0, perf/3, perf1/0, test/0, test/2]). % testing functions
-include_lib("eunit/include/eunit.hrl").
-endif.
format(String, Args, Max) ->
Parts = re:split(String,
"(~(?:-??\\d+\\.|\\*\\.|\\.|)(?:-??\\d+\\.|\\*\\.|\\.|)(?:-??\\d+|\\*|)(?:t|)(?:[cfegswpWPBX#bx+ni~]))",
@ -66,11 +70,16 @@ format([[$~|H]| T], [AH1, _AH2 | AT], Max, Acc, ArgAcc) when H == "W"; H == "P"
%% trunc_io isn't (yet) depth aware, so we can't honor this format string
%% safely at the moment, so just treat it like a regular ~p
%% TODO support for depth limiting
case print(AH1, Max + 2) of
Input = case H == "P" andalso lager_stdlib:string_p(AH1) of
true ->
lists:flatten(AH1);
_ -> AH1
end,
case print(Input, Max + 2) of
{_Res, Max} ->
% this isn't the last argument, but it consumed all available space
% delay calculating the print size until the end
format(T, AT, Max + 2, ["~s" | Acc], [{future, AH1} | ArgAcc]);
format(T, AT, Max + 2, ["~s" | Acc], [{future, Input} | ArgAcc]);
{String, Length} ->
format(T, AT, Max + 2 - Length, ["~s" | Acc], [String | ArgAcc])
end;
@ -78,12 +87,17 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) when length(H) == 1 ->
% single character format specifier, relatively simple
case H of
_ when H == "p"; H == "w"; H == "s" ->
Input = case (H == "s" orelse H == "p") andalso lager_stdlib:string_p(AH) of
true ->
lists:flatten(AH);
_ -> AH
end,
%okay, these are prime candidates for rewriting
case print(AH, Max + 2) of
case print(Input, Max + 2) of
{_Res, Max} ->
% this isn't the last argument, but it consumed all available space
% delay calculating the print size until the end
format(T, AT, Max + 2, ["~s" | Acc], [{future, AH} | ArgAcc]);
format(T, AT, Max + 2, ["~s" | Acc], [{future, Input} | ArgAcc]);
{String, Length} ->
{Value, RealLen} = case H of
"s" ->
@ -92,7 +106,7 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) when length(H) == 1 ->
_ ->
{String, Length}
end,
format(T, AT, Max + 2 - RealLen, ["~s" | Acc], [Value | ArgAcc])
format(T, AT, Max + 2 - RealLen, ["~s" | Acc], [lists:flatten(Value) | ArgAcc])
end;
_ ->
% whatever, just pass them on through
@ -103,14 +117,19 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) ->
case lists:nth(length(H), H) of
C when C == $p; C == $w; C == $s ->
%okay, these are prime candidates for rewriting
case print(AH, Max + length(H) + 1) of
Input = case (C == $s orelse C == $p) andalso lager_stdlib:string_p(AH) of
true ->
lists:flatten(AH);
_ -> AH
end,
case print(Input, Max + length(H) + 1) of
{_Res, Max} ->
% this isn't the last argument, but it consumed all available space
% delay calculating the print size until the end
format(T, AT, Max + length(H) + 1, ["~s" | Acc], [{future, AH} | ArgAcc]);
format(T, AT, Max + length(H) + 1, ["~s" | Acc], [{future, Input} | ArgAcc]);
{String, Length} ->
{Value, RealLen} = case H of
"s" ->
{Value, RealLen} = case C of
$s ->
% strip off the doublequotes
{string:substr(String, 2, length(String) -2), Length -2};
_ ->
@ -124,11 +143,16 @@ format([[$~|H]| T], [AH | AT], Max, Acc, ArgAcc) ->
%% safely at the moment, so just treat it like a regular ~p
%% TODO support for depth limiting
[_ | AT2] = AT,
case print(AH, Max + 2) of
Input = case C == $P andalso lager_stdlib:string_p(AH) of
true ->
lists:flatten(AH);
_ -> AH
end,
case print(Input, Max + 2) of
{_Res, Max} ->
% this isn't the last argument, but it consumed all available space
% delay calculating the print size until the end
format(T, AT2, Max + 2, ["~s" | Acc], [{future, AH} | ArgAcc]);
format(T, AT2, Max + 2, ["~s" | Acc], [{future, Input} | ArgAcc]);
{String, Length} ->
format(T, AT2, Max + 2 - Length, ["~s" | Acc], [String | ArgAcc])
end;
@ -296,6 +320,7 @@ alist(L, Max) ->
{[$", $[, R, $]], Len + 3}.
-ifdef(TEST).
%%--------------------
%% The start of a test suite. So far, it only checks for not crashing.
-spec test() -> ok.
@ -352,3 +377,19 @@ perf1() ->
{N, _} = timer:tc(trunc_io, print, [A, 1500]),
{M, _} = timer:tc(io_lib, write, [A]),
{N, M}.
format_test() ->
%% simple format strings
?assertEqual("foobar", lists:flatten(format("~s", [["foo", $b, $a, $r]], 50))),
?assertEqual("\"foobar\"", lists:flatten(format("~p", [["foo", $b, $a, $r]], 50))),
?assertEqual("\"foobar\"", lists:flatten(format("~P", [["foo", $b, $a, $r], 10], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~w", [["foo", $b, $a, $r], 10], 50))),
%% complex ones
?assertEqual("foobar", lists:flatten(format("~10s", [["foo", $b, $a, $r]], 50))),
?assertEqual("\"foobar\"", lists:flatten(format("~10p", [["foo", $b, $a, $r]], 50))),
?assertEqual("\"foobar\"", lists:flatten(format("~10P", [["foo", $b, $a, $r], 10], 50))),
?assertEqual("[\"foo\",98,97,114]", lists:flatten(format("~10W", [["foo", $b, $a, $r], 10], 50))),
ok.
-endif.

Зареждане…
Отказ
Запис