terminal-table 2.0.0 → 3.0.0
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.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/Gemfile.lock +14 -13
- data/History.rdoc +36 -0
- data/README.md +391 -0
- data/examples/examples.rb +0 -0
- data/examples/examples_unicode.rb +89 -0
- data/examples/issue100.rb +34 -0
- data/examples/issue111.rb +4 -0
- data/examples/issue95.rb +42 -0
- data/examples/strong_separator.rb +23 -0
- data/lib/terminal-table.rb +2 -2
- data/lib/terminal-table/cell.rb +2 -10
- data/lib/terminal-table/row.rb +17 -3
- data/lib/terminal-table/separator.rb +56 -4
- data/lib/terminal-table/style.rb +218 -13
- data/lib/terminal-table/table.rb +45 -15
- data/lib/terminal-table/util.rb +13 -0
- data/lib/terminal-table/version.rb +1 -1
- metadata +9 -3
- data/README.rdoc +0 -249
data/examples/examples.rb
CHANGED
File without changes
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
$:.unshift File.dirname(__FILE__) + '/../lib'
|
4
|
+
require 'terminal-table/import'
|
5
|
+
|
6
|
+
Terminal::Table::Style.defaults = { :border => :unicode_round }
|
7
|
+
# Terminal::Table::UnicodeThickEdgeBorder.new()
|
8
|
+
|
9
|
+
puts
|
10
|
+
puts table(['a', 'b'], [1, 2], [3, 4])
|
11
|
+
|
12
|
+
puts
|
13
|
+
puts table(['name', 'content'], ['ftp.example.com', '1.1.1.1'], ['www.example.com', '|lalalala|lalala|'])
|
14
|
+
|
15
|
+
puts
|
16
|
+
t = table ['a', 'b']
|
17
|
+
t.style = {:padding_left => 2, :width => 80}
|
18
|
+
t << [1, 2]
|
19
|
+
t << [3, 4]
|
20
|
+
t << :separator
|
21
|
+
t << [4, 6]
|
22
|
+
puts t
|
23
|
+
|
24
|
+
puts
|
25
|
+
user_table = table do |v|
|
26
|
+
v.title = "Contact Information"
|
27
|
+
v.headings = 'First Name', 'Last Name', 'Email'
|
28
|
+
v << %w( TJ Holowaychuk tj@vision-media.ca )
|
29
|
+
v << %w( Bob Someone bob@vision-media.ca )
|
30
|
+
v << %w( Joe Whatever bob@vision-media.ca )
|
31
|
+
end
|
32
|
+
puts user_table
|
33
|
+
|
34
|
+
puts
|
35
|
+
user_table = table do |v|
|
36
|
+
v.style.width = 80
|
37
|
+
v.headings = 'First Name', 'Last Name', 'Email'
|
38
|
+
v << %w( TJ Holowaychuk tj@vision-media.ca )
|
39
|
+
v << %w( Bob Someone bob@vision-media.ca )
|
40
|
+
v << %w( Joe Whatever bob@vision-media.ca )
|
41
|
+
end
|
42
|
+
puts user_table
|
43
|
+
|
44
|
+
puts
|
45
|
+
user_table = table do
|
46
|
+
self.headings = 'First Name', 'Last Name', 'Email'
|
47
|
+
add_row ['TJ', 'Holowaychuk', 'tj@vision-media.ca']
|
48
|
+
add_row ['Bob', 'Someone', 'bob@vision-media.ca']
|
49
|
+
add_row ['Joe', 'Whatever', 'joe@vision-media.ca']
|
50
|
+
add_separator
|
51
|
+
add_row ['Total', { :value => '3', :colspan => 2, :alignment => :right }]
|
52
|
+
align_column 1, :center
|
53
|
+
end
|
54
|
+
puts user_table
|
55
|
+
|
56
|
+
puts
|
57
|
+
user_table = table do
|
58
|
+
self.headings = ['First Name', 'Last Name', {:value => 'Phones', :colspan => 2, :alignment => :center}]
|
59
|
+
#add_row ['Bob', 'Someone', '123', '456']
|
60
|
+
add_row [{:value => "Bob Someone", :colspan => 3, :alignment => :center}, '123456']
|
61
|
+
add_row :separator
|
62
|
+
add_row ['TJ', 'Holowaychuk', {:value => "No phones\navaiable", :colspan => 2, :alignment => :center}]
|
63
|
+
add_row :separator
|
64
|
+
add_row ['Joe', 'Whatever', '4324', '343242']
|
65
|
+
end
|
66
|
+
puts user_table
|
67
|
+
|
68
|
+
rows = []
|
69
|
+
rows << ['Lines', 100]
|
70
|
+
rows << ['Comments', 20]
|
71
|
+
rows << ['Ruby', 70]
|
72
|
+
rows << ['JavaScript', 30]
|
73
|
+
puts table([nil, 'Lines'], *rows)
|
74
|
+
|
75
|
+
rows = []
|
76
|
+
rows << ['Lines', 100]
|
77
|
+
rows << ['Comments', 20]
|
78
|
+
rows << ['Ruby', 70]
|
79
|
+
rows << ['JavaScript', 30]
|
80
|
+
puts table(nil, *rows)
|
81
|
+
|
82
|
+
rows = []
|
83
|
+
rows << ['Lines', 100]
|
84
|
+
rows << ['Comments', 20]
|
85
|
+
rows << ['Ruby', 70]
|
86
|
+
rows << ['JavaScript', 30]
|
87
|
+
table = table([{ :value => 'Stats', :colspan => 2, :alignment => :center }], *rows)
|
88
|
+
table.align_column 1, :right
|
89
|
+
puts table
|
@@ -0,0 +1,34 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
# Methods to suppress left/right borders using border_left & border_right
|
4
|
+
|
5
|
+
require_relative "../lib/terminal-table"
|
6
|
+
table = Terminal::Table.new do |t|
|
7
|
+
t.headings = ['id', 'name']
|
8
|
+
t.rows = [[1, 'One'], [2, 'Two'], [3, 'Three']]
|
9
|
+
t.style = { :border_left => false, :border_top => false, :border_bottom => false }
|
10
|
+
end
|
11
|
+
|
12
|
+
puts table
|
13
|
+
puts
|
14
|
+
|
15
|
+
# no right
|
16
|
+
table.style = {:border_right => false }
|
17
|
+
puts table
|
18
|
+
puts
|
19
|
+
|
20
|
+
# no right
|
21
|
+
table.style = {:border_left => true }
|
22
|
+
puts table
|
23
|
+
puts
|
24
|
+
|
25
|
+
table.style.border = Terminal::Table::UnicodeBorder.new
|
26
|
+
puts table
|
27
|
+
|
28
|
+
|
29
|
+
table.style = {:border_right => false, :border_left => true }
|
30
|
+
puts table
|
31
|
+
|
32
|
+
table.style = {:border_right => true, :border_left => false }
|
33
|
+
puts table
|
34
|
+
|
data/examples/issue95.rb
ADDED
@@ -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,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
|
data/lib/terminal-table.rb
CHANGED
@@ -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
|
-
|
24
|
+
%w(cell row separator style table table_helper util version).each do |file|
|
25
|
+
require_relative "./terminal-table/#{file}"
|
26
26
|
end
|
data/lib/terminal-table/cell.rb
CHANGED
@@ -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(
|
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|
|
71
|
+
lines.map{ |s| Util::ansi_escape(s) }.max_by{ |s| Unicode::DisplayWidth.of(s) }
|
72
72
|
end
|
73
73
|
|
74
74
|
##
|
@@ -81,14 +81,6 @@ module Terminal
|
|
81
81
|
end
|
82
82
|
inner_width + padding
|
83
83
|
end
|
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)/, '')
|
91
|
-
end
|
92
84
|
end
|
93
85
|
end
|
94
86
|
end
|
data/lib/terminal-table/row.rb
CHANGED
@@ -36,17 +36,31 @@ module Terminal
|
|
36
36
|
end
|
37
37
|
|
38
38
|
def render
|
39
|
-
|
39
|
+
vleft, vcenter, vright = @table.style.vertical
|
40
40
|
(0...height).to_a.map do |line|
|
41
|
-
|
41
|
+
vleft + cells.map do |cell|
|
42
42
|
cell.render(line)
|
43
|
-
end.join(
|
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
|
-
|
7
|
-
|
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
|
-
|
10
|
-
|
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
|
data/lib/terminal-table/style.rb
CHANGED
@@ -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
|
-
:
|
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
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
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
|
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
|