tty-table 0.1.0 → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +24 -0
- data/README.md +458 -142
- data/lib/tty-table.rb +6 -6
- data/lib/tty/table.rb +34 -34
- data/lib/tty/table/alignment_set.rb +73 -0
- data/lib/tty/table/border.rb +54 -36
- data/lib/tty/table/border/null.rb +4 -4
- data/lib/tty/table/{columns.rb → column_constraint.rb} +30 -32
- data/lib/tty/table/column_set.rb +18 -17
- data/lib/tty/table/field.rb +50 -25
- data/lib/tty/table/header.rb +6 -2
- data/lib/tty/table/indentation.rb +7 -12
- data/lib/tty/table/operation/alignment.rb +59 -0
- data/lib/tty/table/operation/escape.rb +1 -1
- data/lib/tty/table/operation/filter.rb +1 -1
- data/lib/tty/table/operation/padding.rb +12 -61
- data/lib/tty/table/operation/truncation.rb +2 -2
- data/lib/tty/table/operation/wrapped.rb +2 -5
- data/lib/tty/table/operations.rb +35 -17
- data/lib/tty/table/orientation/vertical.rb +4 -4
- data/lib/tty/table/renderer.rb +1 -7
- data/lib/tty/table/renderer/basic.rb +69 -63
- data/lib/tty/table/version.rb +1 -1
- data/spec/spec_helper.rb +3 -4
- data/spec/unit/access_spec.rb +8 -8
- data/spec/unit/{operation/alignment_set → alignment_set}/each_spec.rb +1 -1
- data/spec/unit/{operation/alignment_set → alignment_set}/new_spec.rb +4 -4
- data/spec/unit/{operation/alignment_set → alignment_set}/to_ary_spec.rb +1 -1
- data/spec/unit/alignment_spec.rb +71 -0
- data/spec/unit/border/ascii/rendering_spec.rb +12 -12
- data/spec/unit/border/new_spec.rb +2 -2
- data/spec/unit/border/null/rendering_spec.rb +2 -2
- data/spec/unit/border/unicode/rendering_spec.rb +10 -10
- data/spec/unit/{columns → column_constraint}/enforce_spec.rb +15 -12
- data/spec/unit/{columns → column_constraint}/widths_spec.rb +6 -6
- data/spec/unit/column_set/extract_widths_spec.rb +39 -6
- data/spec/unit/data_spec.rb +4 -6
- data/spec/unit/each_spec.rb +8 -23
- data/spec/unit/each_with_index_spec.rb +27 -33
- data/spec/unit/field/length_spec.rb +23 -9
- data/spec/unit/field/width_spec.rb +1 -1
- data/spec/unit/filter_spec.rb +7 -8
- data/spec/unit/header/new_spec.rb +6 -15
- data/spec/unit/indentation/indent_spec.rb +21 -0
- data/spec/unit/new_spec.rb +73 -0
- data/spec/unit/operation/{alignment_set → alignment}/call_spec.rb +1 -1
- data/spec/unit/operation/escape/call_spec.rb +2 -3
- data/spec/unit/operation/filter/call_spec.rb +2 -3
- data/spec/unit/operation/truncation/call_spec.rb +6 -8
- data/spec/unit/operation/wrapped/call_spec.rb +15 -8
- data/spec/unit/operations/new_spec.rb +1 -1
- data/spec/unit/orientation_spec.rb +6 -6
- data/spec/unit/padding_spec.rb +29 -32
- data/spec/unit/properties_spec.rb +4 -4
- data/spec/unit/render_repeat_spec.rb +42 -0
- data/spec/unit/render_spec.rb +1 -1
- data/spec/unit/render_with_spec.rb +3 -3
- data/spec/unit/renderer/ascii/coloring_spec.rb +70 -0
- data/spec/unit/renderer/ascii/multiline_spec.rb +101 -0
- data/spec/unit/renderer/ascii/padding_spec.rb +37 -10
- data/spec/unit/renderer/ascii/render_spec.rb +4 -4
- data/spec/unit/renderer/ascii/resizing_spec.rb +22 -22
- data/spec/unit/renderer/ascii/separator_spec.rb +1 -1
- data/spec/unit/renderer/basic/alignment_spec.rb +20 -20
- data/spec/unit/renderer/basic/coloring_spec.rb +43 -28
- data/spec/unit/renderer/basic/filter_spec.rb +3 -3
- data/spec/unit/renderer/basic/multiline_spec.rb +74 -0
- data/spec/unit/renderer/basic/options_spec.rb +9 -9
- data/spec/unit/renderer/basic/padding_spec.rb +26 -2
- data/spec/unit/renderer/basic/render_spec.rb +4 -4
- data/spec/unit/renderer/basic/resizing_spec.rb +18 -18
- data/spec/unit/renderer/basic/separator_spec.rb +1 -1
- data/spec/unit/renderer/basic/truncation_spec.rb +6 -6
- data/spec/unit/renderer/basic/wrapping_spec.rb +3 -3
- data/spec/unit/renderer/border_spec.rb +4 -4
- data/spec/unit/renderer/unicode/coloring_spec.rb +70 -0
- data/spec/unit/renderer/unicode/indentation_spec.rb +1 -1
- data/spec/unit/renderer/unicode/padding_spec.rb +26 -26
- data/spec/unit/renderer/unicode/render_spec.rb +4 -4
- data/spec/unit/renderer/unicode/separator_spec.rb +1 -1
- data/spec/unit/to_s_spec.rb +4 -11
- data/spec/unit/utf_spec.rb +33 -0
- data/tty-table.gemspec +2 -1
- metadata +52 -32
- data/lib/tty/table/operation/alignment_set.rb +0 -103
- data/lib/tty/table/padder.rb +0 -180
- data/lib/tty/table/renderer/color.rb +0 -12
- data/spec/unit/indentation/insert_indent_spec.rb +0 -27
- data/spec/unit/initialize_spec.rb +0 -88
- data/spec/unit/padder/parse_spec.rb +0 -45
- data/spec/unit/padder/to_s_spec.rb +0 -14
- data/spec/unit/renderer/basic/multiline_content_spec.rb +0 -135
- data/spec/unit/renderer/style_spec.rb +0 -72
@@ -7,24 +7,21 @@ module TTY
|
|
7
7
|
# Used internally by {Renderer::Basic} to enforce correct column widths.
|
8
8
|
#
|
9
9
|
# @api private
|
10
|
-
class
|
11
|
-
|
12
|
-
attr_reader :table
|
13
|
-
|
14
|
-
attr_reader :renderer
|
15
|
-
|
10
|
+
class ColumnConstraint
|
16
11
|
MIN_WIDTH = 1
|
17
12
|
|
18
13
|
BORDER_WIDTH = 1
|
19
14
|
|
20
15
|
# Initialize a Columns
|
21
16
|
#
|
17
|
+
# @param [TTY::Table] table
|
18
|
+
#
|
22
19
|
# @param [TTY::Table::Renderer] renderer
|
23
20
|
#
|
24
21
|
# @api public
|
25
|
-
def initialize(renderer)
|
22
|
+
def initialize(table, renderer)
|
23
|
+
@table = table
|
26
24
|
@renderer = renderer
|
27
|
-
@table = renderer.table
|
28
25
|
end
|
29
26
|
|
30
27
|
# Estimate outside border size
|
@@ -42,7 +39,17 @@ module TTY
|
|
42
39
|
#
|
43
40
|
# @api public
|
44
41
|
def border_size
|
45
|
-
BORDER_WIDTH * (table.
|
42
|
+
BORDER_WIDTH * (table.columns_size - 1) + outside_border_size
|
43
|
+
end
|
44
|
+
|
45
|
+
# Measure total padding size for a table
|
46
|
+
#
|
47
|
+
# @return [Integer]
|
48
|
+
#
|
49
|
+
# @api public
|
50
|
+
def padding_size
|
51
|
+
padding = renderer.padding
|
52
|
+
(padding.left + padding.right) * (table.columns_size - 1)
|
46
53
|
end
|
47
54
|
|
48
55
|
# Estimate minimum table width to be able to display content
|
@@ -51,7 +58,7 @@ module TTY
|
|
51
58
|
#
|
52
59
|
# @api public
|
53
60
|
def minimum_width
|
54
|
-
table.
|
61
|
+
table.columns_size * MIN_WIDTH + border_size
|
55
62
|
end
|
56
63
|
|
57
64
|
# Return column's natural unconstrained widths
|
@@ -60,7 +67,7 @@ module TTY
|
|
60
67
|
#
|
61
68
|
# @api public
|
62
69
|
def natural_width
|
63
|
-
renderer.column_widths.inject(0, &:+) + border_size
|
70
|
+
renderer.column_widths.inject(0, &:+) + border_size + padding_size
|
64
71
|
end
|
65
72
|
|
66
73
|
# Return the constrained column widths.
|
@@ -72,33 +79,22 @@ module TTY
|
|
72
79
|
def enforce
|
73
80
|
assert_minimum_width
|
74
81
|
|
75
|
-
unless renderer.padding.empty?
|
76
|
-
renderer.column_widths = adjust_padding
|
77
|
-
end
|
78
|
-
|
79
82
|
if natural_width <= renderer.width
|
80
|
-
renderer.
|
83
|
+
renderer.resize ? expand : renderer.column_widths
|
81
84
|
else
|
82
85
|
if renderer.resize
|
83
|
-
|
86
|
+
shrink
|
84
87
|
else
|
85
88
|
rotate
|
86
|
-
renderer.column_widths = ColumnSet.widths_from(table)
|
87
89
|
end
|
88
90
|
end
|
89
91
|
end
|
90
92
|
|
91
|
-
|
92
|
-
#
|
93
|
-
# @api private
|
94
|
-
def adjust_padding
|
95
|
-
padding = renderer.padding
|
96
|
-
column_size = table.column_size
|
93
|
+
private
|
97
94
|
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
end
|
95
|
+
attr_reader :table
|
96
|
+
|
97
|
+
attr_reader :renderer
|
102
98
|
|
103
99
|
# Rotate table to vertical orientation and print information to stdout
|
104
100
|
#
|
@@ -109,13 +105,14 @@ module TTY
|
|
109
105
|
'orientation.'
|
110
106
|
table.orientation = :vertical
|
111
107
|
table.rotate
|
108
|
+
ColumnSet.widths_from(table)
|
112
109
|
end
|
113
110
|
|
114
111
|
# Expand column widths to match the requested width
|
115
112
|
#
|
116
113
|
# @api private
|
117
114
|
def expand
|
118
|
-
column_size = table.
|
115
|
+
column_size = table.columns_size
|
119
116
|
ratio = ((renderer.width - natural_width) / column_size.to_f).floor
|
120
117
|
|
121
118
|
widths = (0...column_size).reduce([]) do |lengths, col|
|
@@ -128,7 +125,7 @@ module TTY
|
|
128
125
|
#
|
129
126
|
# @api private
|
130
127
|
def shrink
|
131
|
-
column_size = table.
|
128
|
+
column_size = table.columns_size
|
132
129
|
ratio = ((natural_width - renderer.width) / column_size.to_f).ceil
|
133
130
|
|
134
131
|
widths = (0...column_size).reduce([]) do |lengths, col|
|
@@ -155,7 +152,8 @@ module TTY
|
|
155
152
|
#
|
156
153
|
# @api private
|
157
154
|
def distribute_extra_width(widths)
|
158
|
-
column_size = table.
|
155
|
+
column_size = table.columns_size
|
156
|
+
# TODO - add padding size to fully check extra width
|
159
157
|
extra_width = renderer.width - (widths.reduce(:+) + border_size)
|
160
158
|
per_field_width = extra_width / column_size
|
161
159
|
remaining_width = extra_width % column_size
|
@@ -165,6 +163,6 @@ module TTY
|
|
165
163
|
width + per_field_width + extra[index]
|
166
164
|
end
|
167
165
|
end
|
168
|
-
end #
|
166
|
+
end # ColumnConstraint
|
169
167
|
end # Table
|
170
168
|
end # TTY
|
data/lib/tty/table/column_set.rb
CHANGED
@@ -10,13 +10,13 @@ module TTY
|
|
10
10
|
class ColumnSet
|
11
11
|
include Equatable
|
12
12
|
|
13
|
-
attr_reader :table
|
14
|
-
|
15
13
|
# Initialize a ColumnSet
|
16
14
|
#
|
15
|
+
# @param [Array[Array[Object]]] data
|
16
|
+
#
|
17
17
|
# @api public
|
18
18
|
def initialize(table)
|
19
|
-
@
|
19
|
+
@data = table.data
|
20
20
|
end
|
21
21
|
|
22
22
|
# Calculate total table width
|
@@ -34,10 +34,8 @@ module TTY
|
|
34
34
|
#
|
35
35
|
# @api private
|
36
36
|
def extract_widths
|
37
|
-
data = table.data
|
38
37
|
colcount = data.max { |row_a, row_b| row_a.size <=> row_b.size }.size
|
39
|
-
|
40
|
-
self.class.find_maximas(colcount, data)
|
38
|
+
find_maximas(colcount)
|
41
39
|
end
|
42
40
|
|
43
41
|
# Assert data integrity for column widths
|
@@ -72,10 +70,10 @@ module TTY
|
|
72
70
|
def self.widths_from(table, column_widths = nil)
|
73
71
|
case column_widths
|
74
72
|
when Array
|
75
|
-
assert_widths(column_widths, table.
|
73
|
+
assert_widths(column_widths, table.columns_size)
|
76
74
|
Array(column_widths).map(&:to_i)
|
77
75
|
when Numeric
|
78
|
-
Array.new(table.
|
76
|
+
Array.new(table.columns_size, column_widths)
|
79
77
|
when NilClass
|
80
78
|
new(table).extract_widths
|
81
79
|
else
|
@@ -85,20 +83,22 @@ module TTY
|
|
85
83
|
|
86
84
|
private
|
87
85
|
|
86
|
+
attr_reader :data
|
87
|
+
|
88
88
|
# Find maximum widths for each row and header if present.
|
89
89
|
#
|
90
90
|
# @param [Integer] colcount
|
91
91
|
# number of columns
|
92
|
-
#
|
93
|
-
#
|
92
|
+
#
|
93
|
+
# @return [Array[Integer]]
|
94
94
|
#
|
95
95
|
# @api private
|
96
|
-
def
|
96
|
+
def find_maximas(colcount)
|
97
97
|
maximas = []
|
98
98
|
start = 0
|
99
99
|
|
100
100
|
start.upto(colcount - 1) do |col_index|
|
101
|
-
maximas << find_maximum(
|
101
|
+
maximas << find_maximum(col_index)
|
102
102
|
end
|
103
103
|
maximas
|
104
104
|
end
|
@@ -106,15 +106,16 @@ module TTY
|
|
106
106
|
# Find a maximum column width. The calculation takes into account
|
107
107
|
# wether the content is escaped or not.
|
108
108
|
#
|
109
|
-
# @param [Array] data
|
110
|
-
# the table data
|
111
|
-
#
|
112
109
|
# @param [Integer] index
|
113
110
|
# the column index
|
114
111
|
#
|
112
|
+
# @return [Integer]
|
113
|
+
#
|
115
114
|
# @api private
|
116
|
-
def
|
117
|
-
data.map
|
115
|
+
def find_maximum(index)
|
116
|
+
data.map do |row|
|
117
|
+
(field = row.call(index)) ? field.length : 0
|
118
|
+
end.max
|
118
119
|
end
|
119
120
|
end # ColumnSet
|
120
121
|
end # Table
|
data/lib/tty/table/field.rb
CHANGED
@@ -4,7 +4,8 @@ module TTY
|
|
4
4
|
class Table
|
5
5
|
# A class that represents a unique element in a table.
|
6
6
|
#
|
7
|
-
# Used internally by {Table::Row} to
|
7
|
+
# Used internally by {Table::Header} and {Table::Row} to
|
8
|
+
# define internal structure.
|
8
9
|
#
|
9
10
|
# @api private
|
10
11
|
class Field
|
@@ -15,28 +16,40 @@ module TTY
|
|
15
16
|
# @api public
|
16
17
|
attr_reader :value
|
17
18
|
|
19
|
+
# The formatted value inside the field used for display
|
20
|
+
#
|
21
|
+
# @api public
|
22
|
+
attr_reader :content
|
23
|
+
|
18
24
|
# The name for the value
|
19
25
|
#
|
20
26
|
# @api public
|
21
27
|
attr_reader :name
|
22
28
|
|
23
|
-
#
|
29
|
+
# The actual value
|
30
|
+
#
|
31
|
+
# @api public
|
24
32
|
attr_writer :value
|
25
33
|
|
26
|
-
# The
|
34
|
+
# The formatted string
|
27
35
|
#
|
28
36
|
# @api public
|
29
|
-
|
37
|
+
attr_writer :content
|
30
38
|
|
31
39
|
# Number of columns this field spans. Defaults to 1.
|
32
40
|
#
|
41
|
+
# @api public
|
33
42
|
attr_reader :colspan
|
34
43
|
|
35
44
|
# Number of rows this field spans. Defaults to 1.
|
36
45
|
#
|
46
|
+
# @api public
|
37
47
|
attr_reader :rowspan
|
38
48
|
|
39
|
-
|
49
|
+
# The field alignment
|
50
|
+
#
|
51
|
+
# @api public
|
52
|
+
attr_reader :alignment
|
40
53
|
|
41
54
|
# Initialize a Field
|
42
55
|
#
|
@@ -49,15 +62,16 @@ module TTY
|
|
49
62
|
# field.value # => a1
|
50
63
|
#
|
51
64
|
# @example
|
52
|
-
# field = TTY::Table::Field.new value: 'a1',
|
53
|
-
# field.value
|
54
|
-
# field.
|
65
|
+
# field = TTY::Table::Field.new value: 'a1', alignment: :center
|
66
|
+
# field.value # => a1
|
67
|
+
# field.alignment # => :center
|
55
68
|
#
|
56
69
|
# @api private
|
57
70
|
def initialize(value)
|
58
71
|
options = extract_options(value)
|
59
|
-
@
|
60
|
-
@
|
72
|
+
@content = @value.to_s
|
73
|
+
@width = options[:width]
|
74
|
+
@alignment = options.fetch(:alignment) { nil }
|
61
75
|
@colspan = options.fetch(:colspan) { 1 }
|
62
76
|
@rowspan = options.fetch(:rowspan) { 1 }
|
63
77
|
end
|
@@ -76,15 +90,18 @@ module TTY
|
|
76
90
|
options
|
77
91
|
end
|
78
92
|
|
79
|
-
#
|
93
|
+
# Reset to original value
|
80
94
|
#
|
81
95
|
# @api public
|
82
|
-
def
|
83
|
-
@
|
96
|
+
def reset!
|
97
|
+
@content = @value.to_s
|
84
98
|
end
|
85
99
|
|
86
|
-
|
87
|
-
|
100
|
+
# The content width
|
101
|
+
#
|
102
|
+
# @api public
|
103
|
+
def width
|
104
|
+
@width || UnicodeUtils.display_width(@content)
|
88
105
|
end
|
89
106
|
|
90
107
|
# Return number of lines this value spans.
|
@@ -95,8 +112,8 @@ module TTY
|
|
95
112
|
#
|
96
113
|
# @api public
|
97
114
|
def lines
|
98
|
-
escaped =
|
99
|
-
escaped.empty? ?
|
115
|
+
escaped = content.scan(/(\\n|\\t|\\r)/)
|
116
|
+
escaped.empty? ? content.split(/\n/, -1) : [content]
|
100
117
|
end
|
101
118
|
|
102
119
|
# If the string contains unescaped new lines then the longest token
|
@@ -106,7 +123,9 @@ module TTY
|
|
106
123
|
#
|
107
124
|
# @api public
|
108
125
|
def length
|
109
|
-
(lines.
|
126
|
+
(lines.map do |line|
|
127
|
+
display_width(self.class.color.strip(line))
|
128
|
+
end << 0).max
|
110
129
|
end
|
111
130
|
|
112
131
|
# Extract the number of lines this value spans
|
@@ -119,20 +138,26 @@ module TTY
|
|
119
138
|
end
|
120
139
|
|
121
140
|
def chars
|
122
|
-
|
141
|
+
content.chars
|
123
142
|
end
|
124
143
|
|
125
|
-
#
|
144
|
+
# Return field content
|
145
|
+
#
|
146
|
+
# @return [String]
|
126
147
|
#
|
127
148
|
# @api public
|
128
|
-
def
|
149
|
+
def to_s
|
150
|
+
content
|
129
151
|
end
|
130
152
|
|
131
|
-
# Return field value
|
132
|
-
#
|
133
153
|
# @api public
|
134
|
-
def
|
135
|
-
|
154
|
+
def self.color
|
155
|
+
@color ||= Pastel.new(enabled: true)
|
156
|
+
end
|
157
|
+
|
158
|
+
# @api public
|
159
|
+
def display_width(string)
|
160
|
+
UnicodeUtils.display_width(string)
|
136
161
|
end
|
137
162
|
end # Field
|
138
163
|
end # Table
|
data/lib/tty/table/header.rb
CHANGED
@@ -39,8 +39,8 @@ module TTY
|
|
39
39
|
# Iterate over each element in the vector
|
40
40
|
#
|
41
41
|
# @example
|
42
|
-
#
|
43
|
-
#
|
42
|
+
# header = TTY::Table::Header.new [1,2,3]
|
43
|
+
# header.each { |element| ... }
|
44
44
|
#
|
45
45
|
# @return [self]
|
46
46
|
#
|
@@ -158,6 +158,10 @@ module TTY
|
|
158
158
|
def to_hash
|
159
159
|
to_a.hash
|
160
160
|
end
|
161
|
+
|
162
|
+
def inspect
|
163
|
+
"#<#{self.class.name} fields=#{to_a}>"
|
164
|
+
end
|
161
165
|
end # Header
|
162
166
|
end # Table
|
163
167
|
end # TTY
|
@@ -4,21 +4,16 @@ module TTY
|
|
4
4
|
class Table
|
5
5
|
# A class responsible for indenting table representation
|
6
6
|
class Indentation
|
7
|
-
|
8
|
-
attr_reader :renderer
|
9
|
-
|
10
|
-
# Initialize an Indentation
|
7
|
+
# The amount of indentation
|
11
8
|
#
|
12
9
|
# @api public
|
13
|
-
|
14
|
-
@renderer = renderer
|
15
|
-
end
|
10
|
+
attr_accessor :indentation
|
16
11
|
|
17
|
-
#
|
12
|
+
# Initialize an Indentation
|
18
13
|
#
|
19
14
|
# @api public
|
20
|
-
def indentation
|
21
|
-
|
15
|
+
def initialize(indentation)
|
16
|
+
@indentation = indentation
|
22
17
|
end
|
23
18
|
|
24
19
|
# Return a table part with indentation inserted
|
@@ -27,7 +22,7 @@ module TTY
|
|
27
22
|
# the rendered table part
|
28
23
|
#
|
29
24
|
# @api public
|
30
|
-
def
|
25
|
+
def indent(part)
|
31
26
|
if part.respond_to?(:to_a)
|
32
27
|
part.map { |line| insert_indentation(line) }
|
33
28
|
else
|
@@ -45,7 +40,7 @@ module TTY
|
|
45
40
|
# @api public
|
46
41
|
def insert_indentation(line)
|
47
42
|
line = line.is_a?(Array) ? line[0] : line
|
48
|
-
line.insert(0, indentation) if line
|
43
|
+
line.insert(0, ' ' * indentation) if line
|
49
44
|
end
|
50
45
|
end # Indentation
|
51
46
|
end # Table
|