Skip to content

Commit a4d99cf

Browse files
authored
Merge pull request #855 from p8/features/print-table-with-borders
Add support for printing tables with borders
2 parents 9c9ab52 + aab2c57 commit a4d99cf

File tree

3 files changed

+90
-14
lines changed

3 files changed

+90
-14
lines changed

lib/thor/shell/basic.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,7 @@ def print_in_columns(array)
175175
# ==== Options
176176
# indent<Integer>:: Indent the first column by indent value.
177177
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
178+
# borders<Boolean>:: Adds ascii borders.
178179
#
179180
def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
180181
printer = TablePrinter.new(stdout, options)

lib/thor/shell/table_printer.rb

Lines changed: 51 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,55 +4,61 @@
44
class Thor
55
module Shell
66
class TablePrinter < ColumnPrinter
7+
BORDER_SEPARATOR = :separator
8+
79
def initialize(stdout, options = {})
810
super
911
@formats = []
1012
@maximas = []
1113
@colwidth = options[:colwidth]
1214
@truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
15+
@padding = 1
1316
end
1417

1518
def print(array)
1619
return if array.empty?
1720

1821
prepare(array)
1922

23+
print_border_separator if options[:borders]
24+
2025
array.each do |row|
26+
if options[:borders] && row == BORDER_SEPARATOR
27+
print_border_separator
28+
next
29+
end
30+
2131
sentence = "".dup
2232

2333
row.each_with_index do |column, index|
24-
maxima = @maximas[index]
25-
26-
f = if column.is_a?(Numeric)
27-
if index == row.size - 1
28-
# Don't output 2 trailing spaces when printing the last column
29-
"%#{maxima}s"
30-
else
31-
"%#{maxima}s "
32-
end
33-
else
34-
@formats[index]
35-
end
36-
sentence << f % column.to_s
34+
sentence << format_cell(column, row.size, index)
3735
end
3836

3937
sentence = truncate(sentence)
38+
sentence << "|" if options[:borders]
4039
stdout.puts sentence
40+
4141
end
42+
print_border_separator if options[:borders]
4243
end
4344

4445
private
4546

4647
def prepare(array)
48+
array = array.reject{|row| row == BORDER_SEPARATOR }
49+
4750
@formats << "%-#{@colwidth + 2}s".dup if @colwidth
4851
start = @colwidth ? 1 : 0
4952

5053
colcount = array.max { |a, b| a.size <=> b.size }.size
5154

5255
start.upto(colcount - 1) do |index|
5356
maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max
57+
5458
@maximas << maxima
55-
@formats << if index == colcount - 1
59+
@formats << if options[:borders]
60+
"%-#{maxima}s".dup
61+
elsif index == colcount - 1
5662
# Don't output 2 trailing spaces when printing the last column
5763
"%-s".dup
5864
else
@@ -64,6 +70,37 @@ def prepare(array)
6470
@formats << "%s"
6571
end
6672

73+
def format_cell(column, row_size, index)
74+
maxima = @maximas[index]
75+
76+
f = if column.is_a?(Numeric)
77+
if options[:borders]
78+
# With borders we handle padding separately
79+
"%#{maxima}s"
80+
elsif index == row_size - 1
81+
# Don't output 2 trailing spaces when printing the last column
82+
"%#{maxima}s"
83+
else
84+
"%#{maxima}s "
85+
end
86+
else
87+
@formats[index]
88+
end
89+
90+
cell = "".dup
91+
cell << "|" + " " * @padding if options[:borders]
92+
cell << f % column.to_s
93+
cell << " " * @padding if options[:borders]
94+
cell
95+
end
96+
97+
def print_border_separator
98+
top = @maximas.map do |maxima|
99+
" " * @indent + "+" + "-" * (maxima + 2 * @padding)
100+
end
101+
stdout.puts top.join + "+"
102+
end
103+
67104
def truncate(string)
68105
return string unless @truncate
69106
as_unicode do

spec/shell/basic_spec.rb

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,44 @@ def #456 Lanç...
432432
Erik 1234567890123 green
433433
TABLE
434434
end
435+
436+
it "prints a table with borders" do
437+
content = capture(:stdout) { shell.print_table(@table, borders: true) }
438+
expect(content).to eq(<<-TABLE)
439+
+-----+------+-------------+
440+
| abc | #123 | first three |
441+
| | #0 | empty |
442+
| xyz | #786 | last three |
443+
+-----+------+-------------+
444+
TABLE
445+
end
446+
447+
it "prints a table with borders and separators" do
448+
@table.insert(1, :separator)
449+
content = capture(:stdout) { shell.print_table(@table, borders: true) }
450+
expect(content).to eq(<<-TABLE)
451+
+-----+------+-------------+
452+
| abc | #123 | first three |
453+
+-----+------+-------------+
454+
| | #0 | empty |
455+
| xyz | #786 | last three |
456+
+-----+------+-------------+
457+
TABLE
458+
end
459+
460+
it "prints a table with borders and small numbers and right-aligns them" do
461+
table = [
462+
["Name", "Number", "Color"], # rubocop: disable Style/WordArray
463+
["Erik", 1, "green"]
464+
]
465+
content = capture(:stdout) { shell.print_table(table, borders: true) }
466+
expect(content).to eq(<<-TABLE)
467+
+------+--------+-------+
468+
| Name | Number | Color |
469+
| Erik | 1 | green |
470+
+------+--------+-------+
471+
TABLE
472+
end
435473
end
436474

437475
describe "#file_collision" do

0 commit comments

Comments
 (0)