1 /++
2  + License: MIT
3  +/
4 
5 module asciitable;
6 
7 import std.string;
8 
9 struct Row
10 {
11     string[] columns;
12     this(string[] data)
13     {
14         this.columns = data;
15     }
16 }
17 
18 struct AsciiTable
19 {
20     ulong[] minimumWidths;
21     Row[] rows;
22     this(W...)(W minimumWidths)
23     {
24         this.minimumWidths = [minimumWidths];
25     }
26 
27     AsciiTable add(V...)(V values)
28     {
29         if (values.length != minimumWidths.length)
30         {
31             throw new Exception("All rows must have length %s".format(minimumWidths.length));
32         }
33         rows ~= Row([values]);
34         return this;
35     }
36 
37     string toString(string linePrefix = "")
38     {
39         import std.algorithm;
40         import std.string;
41 
42         foreach (row; rows)
43         {
44             foreach (idx, column; row.columns)
45             {
46                 minimumWidths[idx] = max(minimumWidths[idx], column.length + 1);
47             }
48         }
49         string res = "";
50         foreach (row; rows)
51         {
52             if (res.length > 0)
53             {
54                 res ~= "\n";
55             }
56             res ~= linePrefix;
57             foreach (idx, column; row.columns)
58             {
59                 res ~= leftJustify(column, minimumWidths[idx], ' ');
60             }
61         }
62         return res;
63     }
64 }
65 
66 @("asciitable") unittest
67 {
68     import unit_threaded;
69 
70     auto table = AsciiTable(10, 3, 5);
71     table.add("1", "2", "3");
72     table.add("4", "5", "6");
73     table.toString.shouldEqual("1         2  3    \n" ~ "4         5  6    \n");
74 }