terminal-table 1.7.2 → 3.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.github/workflows/ci.yml +28 -0
- data/.gitignore +5 -1
- data/Gemfile +2 -0
- data/Gemfile.lock +49 -0
- data/History.rdoc +66 -0
- data/LICENSE.txt +21 -0
- data/README.md +417 -0
- data/Rakefile +10 -4
- data/examples/data.csv +4 -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/issue118.rb +36 -0
- data/examples/issue95.rb +42 -0
- data/examples/show_csv_table.rb +34 -0
- data/examples/strong_separator.rb +23 -0
- data/lib/terminal-table.rb +2 -2
- data/lib/terminal-table/cell.rb +8 -8
- data/lib/terminal-table/row.rb +18 -4
- data/lib/terminal-table/separator.rb +56 -4
- data/lib/terminal-table/style.rb +218 -10
- data/lib/terminal-table/table.rb +49 -18
- data/lib/terminal-table/util.rb +13 -0
- data/lib/terminal-table/version.rb +1 -1
- data/terminal-table.gemspec +3 -3
- metadata +32 -15
- data/README.rdoc +0 -238
data/Rakefile
CHANGED
@@ -1,8 +1,14 @@
|
|
1
|
-
require
|
1
|
+
require 'bundler'
|
2
|
+
Bundler.setup
|
3
|
+
Bundler::GemHelper.install_tasks
|
2
4
|
|
3
|
-
|
4
|
-
|
5
|
-
|
5
|
+
require 'rake'
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
desc "Run all examples"
|
9
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
10
|
+
t.ruby_opts = %w[-w]
|
11
|
+
t.rspec_opts = %w[--color]
|
6
12
|
end
|
7
13
|
|
8
14
|
desc "Default: Run specs"
|
data/examples/data.csv
ADDED
data/examples/examples.rb
CHANGED
File without changes
|
@@ -0,0 +1,89 @@
|
|
1
|
+
#!/usr/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
|
+
|
@@ -0,0 +1,36 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require_relative '../lib/terminal-table'
|
4
|
+
|
5
|
+
puts Terminal::Table.new(headings: ['a', 'b', 'c', 'd'], style: { border: :unicode })
|
6
|
+
|
7
|
+
puts
|
8
|
+
|
9
|
+
tbl = Terminal::Table.new do |t|
|
10
|
+
t.style = { border: :unicode }
|
11
|
+
t.add_separator
|
12
|
+
t.add_separator
|
13
|
+
t.add_row ['x','y','z']
|
14
|
+
t.add_separator
|
15
|
+
t.add_separator
|
16
|
+
end
|
17
|
+
puts tbl
|
18
|
+
|
19
|
+
puts
|
20
|
+
|
21
|
+
puts Terminal::Table.new(headings: [['a', 'b', 'c', 'd'], ['cat','dog','frog','mouse']], style: { border: :unicode })
|
22
|
+
|
23
|
+
puts
|
24
|
+
|
25
|
+
puts Terminal::Table.new(headings: ['a', 'b', 'c', 'd'])
|
26
|
+
|
27
|
+
puts
|
28
|
+
|
29
|
+
tbl = Terminal::Table.new do |t|
|
30
|
+
t.add_separator
|
31
|
+
t.add_separator
|
32
|
+
t.add_row ['x','y','z']
|
33
|
+
t.add_separator
|
34
|
+
t.add_separator
|
35
|
+
end
|
36
|
+
puts tbl
|
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,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
|
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
|
##
|
@@ -82,12 +82,12 @@ module Terminal
|
|
82
82
|
inner_width + padding
|
83
83
|
end
|
84
84
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
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
|
data/lib/terminal-table/row.rb
CHANGED
@@ -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
|
-
|
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
|