Skip to content

Commit

Permalink
Merge pull request #855 from p8/features/print-table-with-borders
Browse files Browse the repository at this point in the history
Add support for printing tables with borders
  • Loading branch information
rafaelfranca authored Aug 23, 2023
2 parents 9c9ab52 + aab2c57 commit a4d99cf
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 14 deletions.
1 change: 1 addition & 0 deletions lib/thor/shell/basic.rb
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ def print_in_columns(array)
# ==== Options
# indent<Integer>:: Indent the first column by indent value.
# colwidth<Integer>:: Force the first column to colwidth spaces wide.
# borders<Boolean>:: Adds ascii borders.
#
def print_table(array, options = {}) # rubocop:disable Metrics/MethodLength
printer = TablePrinter.new(stdout, options)
Expand Down
65 changes: 51 additions & 14 deletions lib/thor/shell/table_printer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,55 +4,61 @@
class Thor
module Shell
class TablePrinter < ColumnPrinter
BORDER_SEPARATOR = :separator

def initialize(stdout, options = {})
super
@formats = []
@maximas = []
@colwidth = options[:colwidth]
@truncate = options[:truncate] == true ? Terminal.terminal_width : options[:truncate]
@padding = 1
end

def print(array)
return if array.empty?

prepare(array)

print_border_separator if options[:borders]

array.each do |row|
if options[:borders] && row == BORDER_SEPARATOR
print_border_separator
next
end

sentence = "".dup

row.each_with_index do |column, index|
maxima = @maximas[index]

f = if column.is_a?(Numeric)
if index == row.size - 1
# Don't output 2 trailing spaces when printing the last column
"%#{maxima}s"
else
"%#{maxima}s "
end
else
@formats[index]
end
sentence << f % column.to_s
sentence << format_cell(column, row.size, index)
end

sentence = truncate(sentence)
sentence << "|" if options[:borders]
stdout.puts sentence

end
print_border_separator if options[:borders]
end

private

def prepare(array)
array = array.reject{|row| row == BORDER_SEPARATOR }

@formats << "%-#{@colwidth + 2}s".dup if @colwidth
start = @colwidth ? 1 : 0

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

start.upto(colcount - 1) do |index|
maxima = array.map { |row| row[index] ? row[index].to_s.size : 0 }.max

@maximas << maxima
@formats << if index == colcount - 1
@formats << if options[:borders]
"%-#{maxima}s".dup
elsif index == colcount - 1
# Don't output 2 trailing spaces when printing the last column
"%-s".dup
else
Expand All @@ -64,6 +70,37 @@ def prepare(array)
@formats << "%s"
end

def format_cell(column, row_size, index)
maxima = @maximas[index]

f = if column.is_a?(Numeric)
if options[:borders]
# With borders we handle padding separately
"%#{maxima}s"
elsif index == row_size - 1
# Don't output 2 trailing spaces when printing the last column
"%#{maxima}s"
else
"%#{maxima}s "
end
else
@formats[index]
end

cell = "".dup
cell << "|" + " " * @padding if options[:borders]
cell << f % column.to_s
cell << " " * @padding if options[:borders]
cell
end

def print_border_separator
top = @maximas.map do |maxima|
" " * @indent + "+" + "-" * (maxima + 2 * @padding)
end
stdout.puts top.join + "+"
end

def truncate(string)
return string unless @truncate
as_unicode do
Expand Down
38 changes: 38 additions & 0 deletions spec/shell/basic_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,44 @@ def #456 Lanç...
Erik 1234567890123 green
TABLE
end

it "prints a table with borders" do
content = capture(:stdout) { shell.print_table(@table, borders: true) }
expect(content).to eq(<<-TABLE)
+-----+------+-------------+
| abc | #123 | first three |
| | #0 | empty |
| xyz | #786 | last three |
+-----+------+-------------+
TABLE
end

it "prints a table with borders and separators" do
@table.insert(1, :separator)
content = capture(:stdout) { shell.print_table(@table, borders: true) }
expect(content).to eq(<<-TABLE)
+-----+------+-------------+
| abc | #123 | first three |
+-----+------+-------------+
| | #0 | empty |
| xyz | #786 | last three |
+-----+------+-------------+
TABLE
end

it "prints a table with borders and small numbers and right-aligns them" do
table = [
["Name", "Number", "Color"], # rubocop: disable Style/WordArray
["Erik", 1, "green"]
]
content = capture(:stdout) { shell.print_table(table, borders: true) }
expect(content).to eq(<<-TABLE)
+------+--------+-------+
| Name | Number | Color |
| Erik | 1 | green |
+------+--------+-------+
TABLE
end
end

describe "#file_collision" do
Expand Down

0 comments on commit a4d99cf

Please sign in to comment.