terminal-table 1.8.0 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,42 @@
1
+ #!/usr/bin/env ruby
2
+ require 'colorize'
3
+ require_relative '../lib/terminal-table.rb'
4
+
5
+ original_sample_data = [
6
+ ["Sep 2016", 33, [-38, -53.52], 46, [-25, -35.21]],
7
+ ["Oct 2016", 35, [2, 6.06], 50, [4, 8.69]]
8
+ ]
9
+
10
+ table = Terminal::Table.new headings: ["Month".cyan,"Monthly IT".cyan,"IT Difference OPM".cyan,
11
+ "Monthly OOT".cyan,"OOT Difference OPM".cyan], rows: original_sample_data
12
+
13
+ table.style = { padding_left: 2, padding_right: 2, border_x: "-".blue, border_y: "|".blue, border_i: "+".blue }
14
+
15
+ puts table
16
+
17
+ puts ""
18
+ puts "^ good table"
19
+ puts "v wonky table"
20
+ puts ""
21
+
22
+ split_column_sample_data = [
23
+ ["Sep 2016", 33, -38, -53.52, 46, -25, -35.21],
24
+ ["Oct 2016", 35, 2, 6.06, 50, 4, 8.69]
25
+ ]
26
+
27
+ table = Terminal::Table.new headings: ["Month".cyan,"Monthly IT".cyan,
28
+ {value: "IT Difference OPM".cyan, colspan: 2}, "Monthly OOT".cyan,
29
+ {value: "OOT Difference OPM".cyan, colspan: 2}], rows: split_column_sample_data
30
+
31
+ table.style = { padding_left: 2, padding_right: 2, border_x: "-".blue, border_y: "|".blue, border_i: "+".blue }
32
+
33
+ puts table
34
+
35
+
36
+ table = Terminal::Table.new headings: ["Month","Monthly IT",
37
+ {value: "IT Difference OPM", colspan: 2}, "Monthly OOT",
38
+ {value: "OOT Difference OPM", colspan: 2}], rows: split_column_sample_data
39
+
40
+ table.style = { padding_left: 2, padding_right: 2, border_x: "-".blue, border_y: "|".cyan, border_i: "+" }
41
+
42
+ puts table
@@ -0,0 +1,34 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "csv"
4
+ $LOAD_PATH << "#{__dir__}/../lib"
5
+ require "terminal-table"
6
+
7
+ #
8
+ # Usage:
9
+ # ./show_csv_table.rb data.csv
10
+ # cat data.csv | ./show_csv_table.rb
11
+ # cat data.csv | ./show_csv_table.rb -
12
+ #
13
+ #
14
+ # Reads a CSV from $stdin if no argument given, or argument is '-'
15
+ # otherwise interprets first cmdline argument as the CSV filename
16
+ #
17
+ use_stdin = ARGV[0].nil? || (ARGV[0] == '-')
18
+ io_object = use_stdin ? $stdin : File.open(ARGV[0], 'r')
19
+ csv = CSV.new(io_object)
20
+
21
+ #
22
+ # Convert to an array for use w/ terminal-table
23
+ # The assumption is that this is a pretty small spreadsheet.
24
+ #
25
+ csv_array = csv.to_a
26
+
27
+ user_table = Terminal::Table.new do |v|
28
+ v.style = { :border => :unicode_round } # >= v3.0.0
29
+ v.title = "Some Title"
30
+ v.headings = csv_array[0]
31
+ v.rows = csv_array[1..-1]
32
+ end
33
+
34
+ puts user_table
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ require_relative "../lib/terminal-table"
3
+
4
+ #
5
+ # An example of how to manually add separators with non-default
6
+ # border_type to enable a footer row.
7
+ #
8
+ table = Terminal::Table.new do |t|
9
+ # set the style
10
+ t.style = { border: :unicode_thick_edge }
11
+
12
+ # header row
13
+ t.headings = ['fruit', 'count']
14
+
15
+ # some row data
16
+ t.add_row ['apples', 7]
17
+ t.add_row ['bananas', 19]
18
+ t.add_separator border_type: :strong
19
+ # footer row
20
+ t.add_row ['total', 26]
21
+ end
22
+
23
+ puts table.render
@@ -57,7 +57,7 @@ module Terminal
57
57
  def render(line = 0)
58
58
  left = " " * @table.style.padding_left
59
59
  right = " " * @table.style.padding_right
60
- display_width = Unicode::DisplayWidth.of(escape(lines[line]))
60
+ display_width = Unicode::DisplayWidth.of(Util::ansi_escape(lines[line]))
61
61
  render_width = lines[line].to_s.size - display_width + width
62
62
  align("#{left}#{lines[line]}#{right}", alignment, render_width + @table.cell_padding)
63
63
  end
@@ -68,7 +68,7 @@ module Terminal
68
68
  # removes all ANSI escape sequences (e.g. color)
69
69
 
70
70
  def value_for_column_width_recalc
71
- lines.map{ |s| escape(s) }.max_by{ |s| Unicode::DisplayWidth.of(s) }
71
+ lines.map{ |s| Util::ansi_escape(s) }.max_by{ |s| Unicode::DisplayWidth.of(s) }
72
72
  end
73
73
 
74
74
  ##
@@ -82,12 +82,12 @@ module Terminal
82
82
  inner_width + padding
83
83
  end
84
84
 
85
- ##
86
- # removes all ANSI escape sequences (e.g. color)
87
- def escape(line)
88
- line.to_s.gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/, '').
89
- gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/, '').
90
- gsub(/(\x03|\x1a)/, '')
85
+ def inspect
86
+ fields = %i[alignment colspan index value width].map do |name|
87
+ val = self.instance_variable_get('@'+name.to_s)
88
+ "@#{name}=#{val.inspect}"
89
+ end.join(', ')
90
+ return "#<#{self.class} #{fields}>"
91
91
  end
92
92
  end
93
93
  end
@@ -12,7 +12,7 @@ module Terminal
12
12
  ##
13
13
  # Initialize with _width_ and _options_.
14
14
 
15
- def initialize table, array = []
15
+ def initialize table, array = [], **_kwargs
16
16
  @cell_index = 0
17
17
  @table = table
18
18
  @cells = []
@@ -36,17 +36,31 @@ module Terminal
36
36
  end
37
37
 
38
38
  def render
39
- y = @table.style.border_y
39
+ vleft, vcenter, vright = @table.style.vertical
40
40
  (0...height).to_a.map do |line|
41
- y + cells.map do |cell|
41
+ vleft + cells.map do |cell|
42
42
  cell.render(line)
43
- end.join(y) + y
43
+ end.join(vcenter) + vright
44
44
  end.join("\n")
45
45
  end
46
46
 
47
47
  def number_of_columns
48
48
  @cells.collect(&:colspan).inject(0, &:+)
49
49
  end
50
+
51
+ # used to find indices where we have table '+' crossings.
52
+ # in cases where the colspan > 1, then we will skip over some numbers
53
+ # if colspan is always 1, then the list should be incrementing by 1.
54
+ #
55
+ # skip 0 entry, because it's the left side.
56
+ # skip last entry, because it's the right side.
57
+ # we only care about "+/T" style crossings.
58
+ def crossings
59
+ idx = 0
60
+ @cells[0...-1].map { |c| idx += c.colspan }
61
+ end
62
+
50
63
  end
64
+
51
65
  end
52
66
  end
@@ -2,13 +2,65 @@ module Terminal
2
2
  class Table
3
3
  class Separator < Row
4
4
 
5
+ ##
6
+ # `prevrow`, `nextrow` contain references to adjacent rows.
7
+ #
8
+ # `border_type` is a symbol used to control which type of border is used
9
+ # on the separator (:top for top-edge, :bot for bottom-edge,
10
+ # :div for interior, and :strong for emphasized-interior)
11
+ #
12
+ # `implicit` is false for user-added separators, and true for
13
+ # implicit/auto-generated separators.
14
+
15
+ def initialize(*args, border_type: :div, implicit: false)
16
+ super
17
+ @prevrow, @nextrow = nil, nil
18
+ @border_type = border_type
19
+ @implicit = implicit
20
+ end
21
+
22
+ attr_accessor :border_type
23
+ attr_reader :implicit
24
+
5
25
  def render
6
- arr_x = (0...@table.number_of_columns).to_a.map do |i|
7
- @table.style.border_x * (@table.column_width(i) + @table.cell_padding)
26
+ left_edge, ctrflat, ctrud, right_edge, ctrdn, ctrup = @table.style.horizontal(border_type)
27
+
28
+ prev_crossings = @prevrow.respond_to?(:crossings) ? @prevrow.crossings : []
29
+ next_crossings = @nextrow.respond_to?(:crossings) ? @nextrow.crossings : []
30
+ rval = [left_edge]
31
+ numcols = @table.number_of_columns
32
+ (0...numcols).each do |idx|
33
+ rval << ctrflat * (@table.column_width(idx) + @table.cell_padding)
34
+ pcinc = prev_crossings.include?(idx+1)
35
+ ncinc = next_crossings.include?(idx+1)
36
+ border_center = if pcinc && ncinc
37
+ ctrud
38
+ elsif pcinc
39
+ ctrup
40
+ elsif ncinc
41
+ ctrdn
42
+ elsif !ctrud.empty?
43
+ # special case if the center-up-down intersection is empty
44
+ # which happens when verticals/intersections are removed. in that case
45
+ # we do not want to replace with a flat element so return empty-string in else block
46
+ ctrflat
47
+ else
48
+ ''
49
+ end
50
+ rval << border_center if idx < numcols-1
8
51
  end
9
- border_i = @table.style.border_i
10
- border_i + arr_x.join(border_i) + border_i
52
+
53
+ rval << right_edge
54
+ rval.join
55
+ end
56
+
57
+ # Save off neighboring rows, so that we can use them later in determining
58
+ # which types of table edges to use.
59
+ def save_adjacent_rows(prevrow, nextrow)
60
+ @prevrow = prevrow
61
+ @nextrow = nextrow
11
62
  end
63
+
12
64
  end
13
65
  end
14
66
  end
@@ -1,5 +1,171 @@
1
+ # coding: utf-8
2
+ require 'forwardable'
3
+
1
4
  module Terminal
2
5
  class Table
6
+
7
+ class Border
8
+
9
+ attr_accessor :data, :top, :bottom, :left, :right
10
+ def initialize
11
+ @top, @bottom, @left, @right = true, true, true, true
12
+ end
13
+ def []=(key, val)
14
+ @data[key] = val
15
+ end
16
+ def [](key)
17
+ @data[key]
18
+ end
19
+ def initialize_dup(other)
20
+ super
21
+ @data = other.data.dup
22
+ end
23
+ def remove_verticals
24
+ self.class.const_get("VERTICALS").each { |key| @data[key] = "" }
25
+ self.class.const_get("INTERSECTIONS").each { |key| @data[key] = "" }
26
+ end
27
+ def remove_horizontals
28
+ self.class.const_get("HORIZONTALS").each { |key| @data[key] = "" }
29
+ end
30
+
31
+ # If @left, return the edge else empty-string.
32
+ def maybeleft(key) ; @left ? @data[key] : '' ; end
33
+
34
+ # If @right, return the edge else empty-string.
35
+ def mayberight(key) ; @right ? @data[key] : '' ; end
36
+
37
+ end
38
+
39
+ class AsciiBorder < Border
40
+ HORIZONTALS = %i[x]
41
+ VERTICALS = %i[y]
42
+ INTERSECTIONS = %i[i]
43
+
44
+ def initialize
45
+ super
46
+ @data = { x: "-", y: "|", i: "+" }
47
+ end
48
+
49
+ # Get vertical border elements
50
+ # @return [Array] 3-element list of [left, center, right]
51
+ def vertical
52
+ [maybeleft(:y), @data[:y], mayberight(:y)] # left, center, right
53
+ end
54
+
55
+ # Get horizontal border elements
56
+ # @return [Array] a 6 element list of: [i-left, horizontal-bar, i-up/down, i-right, i-down, i-up]
57
+ def horizontal(_type)
58
+ x, i = @data[:x], @data[:i]
59
+ [maybeleft(:i), x, i, mayberight(:i), i, i]
60
+ end
61
+ end
62
+
63
+ class MarkdownBorder < AsciiBorder
64
+ def initialize
65
+ super
66
+ @top, @bottom = false, false
67
+ @data = { x: "-", y: "|", i: "|" }
68
+ end
69
+ end
70
+
71
+ class UnicodeBorder < Border
72
+
73
+ ALLOWED_SEPARATOR_BORDER_STYLES = %i[
74
+ top bot
75
+ div dash dot3 dot4
76
+ thick thick_dash thick_dot3 thick_dot4
77
+ heavy heavy_dash heavy_dot3 heavy_dot4
78
+ bold bold_dash bold_dot3 bold_dot4
79
+ double
80
+ ]
81
+
82
+ HORIZONTALS = %i[x sx ax bx nx bx_dot3 bx_dot4 bx_dash x_dot3 x_dot4 x_dash]
83
+ VERTICALS = %i[y yw ye]
84
+ INTERSECTIONS = %i[nw n ne nd
85
+ aw ai ae ad au
86
+ bw bi be bd bu
87
+ w i e dn up
88
+ sw s se su]
89
+ def initialize
90
+ super
91
+ @data = {
92
+ nil => nil,
93
+ nw: "┌", nx: "─", n: "┬", ne: "┐",
94
+ yw: "│", y: "│", ye: "│",
95
+ aw: "╞", ax: "═", ai: "╪", ae: "╡", ad: '╤', au: "╧", # double
96
+ bw: "┝", bx: "━", bi: "┿", be: "┥", bd: '┯', bu: "┷", # heavy/bold/thick
97
+ w: "├", x: "─", i: "┼", e: "┤", dn: "┬", up: "┴", # normal div
98
+ sw: "└", sx: "─", s: "┴", se: "┘",
99
+ # alternative dots/dashes
100
+ x_dot4: '┈', x_dot3: '┄', x_dash: '╌',
101
+ bx_dot4: '┉', bx_dot3: '┅', bx_dash: '╍',
102
+ }
103
+ end
104
+ # Get vertical border elements
105
+ # @return [Array] 3-element list of [left, center, right]
106
+ def vertical
107
+ [maybeleft(:yw), @data[:y], mayberight(:ye)]
108
+ end
109
+
110
+ # Get horizontal border elements
111
+ # @return [Array] a 6 element list of: [i-left, horizontal-bar, i-up/down, i-right, i-down, i-up]
112
+ def horizontal(type)
113
+ raise ArgumentError, "Border type is #{type.inspect}, must be one of #{ALLOWED_SEPARATOR_BORDER_STYLES.inspect}" unless ALLOWED_SEPARATOR_BORDER_STYLES.include?(type)
114
+ lookup = case type
115
+ when :top
116
+ [:nw, :nx, :n, :ne, :n, nil]
117
+ when :bot
118
+ [:sw, :sx, :s, :se, nil, :s]
119
+ when :double
120
+ # typically used for the separator below the heading row or above a footer row)
121
+ [:aw, :ax, :ai, :ae, :ad, :au]
122
+ when :thick, :thick_dash, :thick_dot3, :thick_dot4,
123
+ :heavy, :heavy_dash, :heavy_dot3, :heavy_dot4,
124
+ :bold, :bold_dash, :bold_dot3, :bold_dot4
125
+ # alternate thick/bold border
126
+ xref = type.to_s.sub(/^(thick|heavy|bold)/,'bx').to_sym
127
+ [:bw, xref, :bi, :be, :bd, :bu]
128
+ when :dash, :dot3, :dot4
129
+ # alternate thin dividers
130
+ xref = "x_#{type}".to_sym
131
+ [:w, xref, :i, :e, :dn, :up]
132
+ else # :div (center, non-emphasized)
133
+ [:w, :x, :i, :e, :dn, :up]
134
+ end
135
+ rval = lookup.map { |key| @data.fetch(key) }
136
+ rval[0] = '' unless @left
137
+ rval[3] = '' unless @right
138
+ rval
139
+ end
140
+ end
141
+
142
+ # Unicode Border With rounded edges
143
+ class UnicodeRoundBorder < UnicodeBorder
144
+ def initialize
145
+ super
146
+ @data.merge!({nw: '╭', ne: '╮', sw: '╰', se: '╯'})
147
+ end
148
+ end
149
+
150
+ # Unicode Border with thick outer edges
151
+ class UnicodeThickEdgeBorder < UnicodeBorder
152
+ def initialize
153
+ super
154
+ @data = {
155
+ nil => nil,
156
+ nw: "┏", nx: "━", n: "┯", ne: "┓", nd: nil,
157
+ yw: "┃", y: "│", ye: "┃",
158
+ aw: "┣", ax: "═", ai: "╪", ae: "┫", ad: '╤', au: "╧", # double
159
+ bw: "┣", bx: "━", bi: "┿", be: "┫", bd: '┯', bu: "┷", # heavy/bold/thick
160
+ w: "┠", x: "─", i: "┼", e: "┨", dn: "┬", up: "┴", # normal div
161
+ sw: "┗", sx: "━", s: "┷", se: "┛", su: nil,
162
+ # alternative dots/dashes
163
+ x_dot4: '┈', x_dot3: '┄', x_dash: '╌',
164
+ bx_dot4: '┉', bx_dot3: '┅', bx_dash: '╍',
165
+ }
166
+ end
167
+ end
168
+
3
169
  # A Style object holds all the formatting information for a Table object
4
170
  #
5
171
  # To create a table with a certain style, use either the constructor
@@ -22,20 +188,51 @@ module Terminal
22
188
  # Terminal::Table::Style.defaults = {:width => 80}
23
189
  #
24
190
  class Style
191
+ extend Forwardable
192
+ def_delegators :@border, :vertical, :horizontal, :remove_verticals, :remove_horizontals
193
+
25
194
  @@defaults = {
26
- :border_x => "-", :border_y => "|", :border_i => "+",
27
- :border_top => true, :border_bottom => true,
195
+ :border => AsciiBorder.new,
28
196
  :padding_left => 1, :padding_right => 1,
29
197
  :margin_left => '',
30
198
  :width => nil, :alignment => nil,
31
- :all_separators => false
199
+ :all_separators => false,
32
200
  }
33
201
 
34
- attr_accessor :border_x
35
- attr_accessor :border_y
36
- attr_accessor :border_i
37
- attr_accessor :border_top
38
- attr_accessor :border_bottom
202
+ ## settors/gettor for legacy ascii borders
203
+ def border_x=(val) ; @border[:x] = val ; end
204
+ def border_y=(val) ; @border[:y] = val ; end
205
+ def border_i=(val) ; @border[:i] = val ; end
206
+ def border_y ; @border[:y] ; end
207
+ def border_y_width ; Util::ansi_escape(@border[:y]).length ; end
208
+
209
+ # Accessor for instance of Border
210
+ attr_reader :border
211
+ def border=(val)
212
+ if val.is_a? Symbol
213
+ # convert symbol name like :foo_bar to get class FooBarBorder
214
+ klass_str = val.to_s.split('_').collect(&:capitalize).join + "Border"
215
+ begin
216
+ klass = Terminal::Table::const_get(klass_str)
217
+ @border = klass.new
218
+ rescue NameError
219
+ raise "Cannot lookup class Terminal::Table::#{klass_str} from symbol #{val.inspect}"
220
+ end
221
+ else
222
+ @border = val
223
+ end
224
+ end
225
+
226
+ def border_top=(val) ; @border.top = val ; end
227
+ def border_bottom=(val) ; @border.bottom = val ; end
228
+ def border_left=(val) ; @border.left = val ; end
229
+ def border_right=(val) ; @border.right = val ; end
230
+
231
+ def border_top ; @border.top ; end
232
+ def border_bottom ; @border.bottom ; end
233
+ def border_left ; @border.left ; end
234
+ def border_right ; @border.right ; end
235
+
39
236
 
40
237
  attr_accessor :padding_left
41
238
  attr_accessor :padding_right
@@ -47,23 +244,30 @@ module Terminal
47
244
 
48
245
  attr_accessor :all_separators
49
246
 
50
-
247
+
51
248
  def initialize options = {}
52
249
  apply self.class.defaults.merge(options)
53
250
  end
54
251
 
55
252
  def apply options
56
- options.each { |m, v| __send__ "#{m}=", v }
253
+ options.each do |m, v|
254
+ __send__ "#{m}=", v
255
+ end
57
256
  end
58
-
257
+
59
258
  class << self
60
259
  def defaults
61
- @@defaults
260
+ klass_defaults = @@defaults.dup
261
+ # border is an object that needs to be duplicated on instantiation,
262
+ # otherwise everything will be referencing the same object-id.
263
+ klass_defaults[:border] = klass_defaults[:border].dup
264
+ klass_defaults
62
265
  end
63
-
266
+
64
267
  def defaults= options
65
268
  @@defaults = defaults.merge(options)
66
269
  end
270
+
67
271
  end
68
272
 
69
273
  def on_change attr
@@ -74,6 +278,7 @@ module Terminal
74
278
  yield attr.to_sym, value
75
279
  end
76
280
  end
281
+
77
282
  end
78
283
  end
79
284
  end
@@ -7,9 +7,10 @@ module Terminal
7
7
  attr_reader :headings
8
8
 
9
9
  ##
10
- # Generates a ASCII table with the given _options_.
10
+ # Generates a ASCII/Unicode table with the given _options_.
11
11
 
12
12
  def initialize options = {}, &block
13
+ @elaborated = false
13
14
  @headings = []
14
15
  @rows = []
15
16
  @column_widths = []
@@ -26,9 +27,8 @@ module Terminal
26
27
  # Align column _n_ to the given _alignment_ of :center, :left, or :right.
27
28
 
28
29
  def align_column n, alignment
29
- r = rows
30
- column(n).each_with_index do |col, i|
31
- cell = r[i][n]
30
+ # nil forces the column method to return the cell itself
31
+ column(n, nil).each do |cell|
32
32
  cell.alignment = alignment unless cell.alignment?
33
33
  end
34
34
  end
@@ -46,12 +46,12 @@ module Terminal
46
46
  ##
47
47
  # Add a separator.
48
48
 
49
- def add_separator
50
- self << :separator
49
+ def add_separator(border_type: :div)
50
+ @rows << Separator.new(self, border_type: border_type)
51
51
  end
52
52
 
53
53
  def cell_spacing
54
- cell_padding + style.border_y.length
54
+ cell_padding + style.border_y_width
55
55
  end
56
56
 
57
57
  def cell_padding
@@ -118,28 +118,57 @@ module Terminal
118
118
  end
119
119
 
120
120
  ##
121
- # Render the table.
121
+ # Elaborate rows to form an Array of Rows and Separators with adjacency properties added.
122
+ #
123
+ # This is separated from the String rendering so that certain features may be tweaked
124
+ # before the String is built.
122
125
 
123
- def render
124
- separator = Separator.new(self)
125
- buffer = style.border_top ? [separator] : []
126
+ def elaborate_rows
127
+
128
+ buffer = style.border_top ? [Separator.new(self, border_type: :top, implicit: true)] : []
126
129
  unless @title.nil?
127
130
  buffer << Row.new(self, [title_cell_options])
128
- buffer << separator
131
+ buffer << Separator.new(self, implicit: true)
129
132
  end
130
133
  @headings.each do |row|
131
134
  unless row.cells.empty?
132
135
  buffer << row
133
- buffer << separator
136
+ buffer << Separator.new(self, border_type: :double, implicit: true)
134
137
  end
135
138
  end
136
139
  if style.all_separators
137
- buffer += @rows.product([separator]).flatten
140
+ @rows.each_with_index do |row, idx|
141
+ # last separator is bottom, others are :div
142
+ border_type = (idx == @rows.size - 1) ? :bot : :div
143
+ buffer << row
144
+ buffer << Separator.new(self, border_type: border_type, implicit: true)
145
+ end
138
146
  else
139
147
  buffer += @rows
140
- buffer << separator if style.border_bottom
148
+ buffer << Separator.new(self, border_type: :bot, implicit: true) if style.border_bottom
149
+ end
150
+
151
+ # After all implicit Separators are inserted we need to save off the
152
+ # adjacent rows so that we can decide what type of intersections to use
153
+ # based on column spans in the adjacent row(s).
154
+ buffer.each_with_index do |r, idx|
155
+ if r.is_a?(Separator)
156
+ prev_row = idx > 0 ? buffer[idx - 1] : nil
157
+ next_row = buffer.fetch(idx + 1, nil)
158
+ r.save_adjacent_rows(prev_row, next_row)
159
+ end
141
160
  end
142
- buffer.map { |r| style.margin_left + r.render.rstrip }.join("\n")
161
+
162
+ @elaborated = true
163
+ @rows = buffer
164
+ end
165
+
166
+ ##
167
+ # Render the table.
168
+
169
+ def render
170
+ elaborate_rows unless @elaborated
171
+ @rows.map { |r| style.margin_left + r.render.rstrip }.join("\n")
143
172
  end
144
173
  alias :to_s :render
145
174
 
@@ -181,7 +210,7 @@ module Terminal
181
210
  private
182
211
 
183
212
  def columns_width
184
- column_widths.inject(0) { |s, i| s + i + cell_spacing } + style.border_y.length
213
+ column_widths.inject(0) { |s, i| s + i + cell_spacing } + style.border_y_width
185
214
  end
186
215
 
187
216
  def recalc_column_widths
@@ -300,7 +329,7 @@ module Terminal
300
329
 
301
330
  full_width = dp[n_cols][0].keys.first
302
331
  unless style.width.nil?
303
- new_width = style.width - space_width - style.border_y.length
332
+ new_width = style.width - space_width - style.border_y_width
304
333
  if new_width < full_width
305
334
  raise "Table width exceeds wanted width " +
306
335
  "of #{style.width} characters."
@@ -0,0 +1,13 @@
1
+ module Terminal
2
+ class Table
3
+ module Util
4
+ # removes all ANSI escape sequences (e.g. color)
5
+ def ansi_escape(line)
6
+ line.to_s.gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/, '').
7
+ gsub(/\x1b(\[|\(|\))[;?0-9]*[0-9A-Za-z]/, '').
8
+ gsub(/(\x03|\x1a)/, '')
9
+ end
10
+ module_function :ansi_escape
11
+ end
12
+ end
13
+ end
@@ -1,5 +1,5 @@
1
1
  module Terminal
2
2
  class Table
3
- VERSION = '1.8.0'
3
+ VERSION = '3.0.2'
4
4
  end
5
5
  end
@@ -21,6 +21,6 @@
21
21
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
22
  #++
23
23
 
24
- %w(cell row separator style table table_helper version).each do |file|
25
- require "terminal-table/#{file}"
24
+ %w(cell row separator style table table_helper util version).each do |file|
25
+ require_relative "./terminal-table/#{file}"
26
26
  end