File: table_printer.rb

package info (click to toggle)
ruby-thor 1.4.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 904 kB
  • sloc: ruby: 9,250; makefile: 8; sh: 1
file content (118 lines) | stat: -rw-r--r-- 3,006 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
require_relative "column_printer"
require_relative "terminal"

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|
            sentence << format_cell(column, row.size, index)
          end

          sentence = truncate(sentence)
          sentence << "|" if options[:borders]
          stdout.puts indentation + 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 options[:borders]
             "%-#{maxima}s".dup
          elsif index == colcount - 1
            # Don't output 2 trailing spaces when printing the last column
            "%-s".dup
          else
            "%-#{maxima + 2}s".dup
          end
        end

        @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
        separator = @maximas.map do |maxima|
          "+" + "-" * (maxima + 2 * @padding)
        end
        stdout.puts indentation + separator.join + "+"
      end

      def truncate(string)
        return string unless @truncate
        chars = string.chars.to_a
        if chars.length <= @truncate
          chars.join
        else
          chars[0, @truncate - 3 - @indent].join + "..."
        end
      end

      def indentation
        " " * @indent
      end
    end
  end
end