terminal-table 1.7.1 → 1.7.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.
- checksums.yaml +4 -4
- data/History.rdoc +5 -0
- data/lib/terminal-table/row.rb +4 -0
- data/lib/terminal-table/style.rb +9 -0
- data/lib/terminal-table/table.rb +138 -34
- data/lib/terminal-table/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6c0927620bf05c372458c73382bfd171be972288
|
4
|
+
data.tar.gz: e7aad54b23b37641a9edf68867d8b741af52563e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 469f18cf16097c03b06e4e39696f04b8fa7547facc206cdfc52ac4fa918b78109d6ef6caeb14366c3bc2d4902ef3e6fd23587d453c90d80fabd7249a94b1c0ec
|
7
|
+
data.tar.gz: d6c9253df10b4bed36b4a494ef20c39dc462e2c388ad3b1cdeb464676bbe31458b718f14283818c99713e813c5c9cd728ddd7ce8f4bd64cebdba8f300633b689
|
data/History.rdoc
CHANGED
data/lib/terminal-table/row.rb
CHANGED
data/lib/terminal-table/style.rb
CHANGED
@@ -62,6 +62,15 @@ module Terminal
|
|
62
62
|
@@defaults = defaults.merge(options)
|
63
63
|
end
|
64
64
|
end
|
65
|
+
|
66
|
+
def on_change attr
|
67
|
+
method_name = :"#{attr}="
|
68
|
+
old_method = method method_name
|
69
|
+
define_singleton_method(method_name) do |value|
|
70
|
+
old_method.call value
|
71
|
+
yield attr.to_sym, value
|
72
|
+
end
|
73
|
+
end
|
65
74
|
end
|
66
75
|
end
|
67
76
|
end
|
data/lib/terminal-table/table.rb
CHANGED
@@ -10,12 +10,16 @@ module Terminal
|
|
10
10
|
# Generates a ASCII table with the given _options_.
|
11
11
|
|
12
12
|
def initialize options = {}, &block
|
13
|
+
@headings = []
|
14
|
+
@rows = []
|
13
15
|
@column_widths = []
|
14
16
|
self.style = options.fetch :style, {}
|
15
17
|
self.headings = options.fetch :headings, []
|
16
18
|
self.rows = options.fetch :rows, []
|
17
19
|
self.title = options.fetch :title, nil
|
18
20
|
yield_or_eval(&block) if block
|
21
|
+
|
22
|
+
style.on_change(:width) { require_column_widths_recalc }
|
19
23
|
end
|
20
24
|
|
21
25
|
##
|
@@ -35,7 +39,7 @@ module Terminal
|
|
35
39
|
def add_row array
|
36
40
|
row = array == :separator ? Separator.new(self) : Row.new(self, array)
|
37
41
|
@rows << row
|
38
|
-
|
42
|
+
require_column_widths_recalc unless row.is_a?(Separator)
|
39
43
|
end
|
40
44
|
alias :<< :add_row
|
41
45
|
|
@@ -90,8 +94,7 @@ module Terminal
|
|
90
94
|
# Return length of column _n_.
|
91
95
|
|
92
96
|
def column_width n
|
93
|
-
width =
|
94
|
-
width + additional_column_widths[n].to_i
|
97
|
+
width = column_widths[n] || 0
|
95
98
|
end
|
96
99
|
alias length_of_column column_width # for legacy support
|
97
100
|
|
@@ -99,7 +102,7 @@ module Terminal
|
|
99
102
|
# Return total number of columns available.
|
100
103
|
|
101
104
|
def number_of_columns
|
102
|
-
headings_with_rows.map { |r| r.
|
105
|
+
headings_with_rows.map { |r| r.number_of_columns }.max || 0
|
103
106
|
end
|
104
107
|
|
105
108
|
##
|
@@ -109,7 +112,7 @@ module Terminal
|
|
109
112
|
arrays = [arrays] unless arrays.first.is_a?(Array)
|
110
113
|
@headings = arrays.map do |array|
|
111
114
|
row = Row.new(self, array)
|
112
|
-
|
115
|
+
require_column_widths_recalc
|
113
116
|
row
|
114
117
|
end
|
115
118
|
end
|
@@ -162,7 +165,7 @@ module Terminal
|
|
162
165
|
|
163
166
|
def title=(title)
|
164
167
|
@title = title
|
165
|
-
|
168
|
+
require_column_widths_recalc
|
166
169
|
end
|
167
170
|
|
168
171
|
##
|
@@ -178,42 +181,134 @@ module Terminal
|
|
178
181
|
private
|
179
182
|
|
180
183
|
def columns_width
|
181
|
-
|
184
|
+
column_widths.inject(0) { |s, i| s + i + cell_spacing } + style.border_y.length
|
182
185
|
end
|
183
186
|
|
184
|
-
def
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
187
|
+
def recalc_column_widths
|
188
|
+
@require_column_widths_recalc = false
|
189
|
+
n_cols = number_of_columns
|
190
|
+
space_width = cell_spacing
|
191
|
+
return if n_cols == 0
|
192
|
+
|
193
|
+
# prepare rows
|
194
|
+
all_rows = headings_with_rows
|
195
|
+
all_rows << Row.new(self, [title_cell_options]) unless @title.nil?
|
196
|
+
|
197
|
+
# DP states, dp[colspan][index][split_offset] => column_width.
|
198
|
+
dp = []
|
199
|
+
|
200
|
+
# prepare initial value for DP.
|
201
|
+
all_rows.each do |row|
|
202
|
+
index = 0
|
203
|
+
row.cells.each do |cell|
|
204
|
+
cell_value = cell.value_for_column_width_recalc
|
205
|
+
cell_width = Unicode::DisplayWidth.of(cell_value.to_s)
|
206
|
+
colspan = cell.colspan
|
207
|
+
|
208
|
+
# find column width from each single cell.
|
209
|
+
dp[colspan] ||= []
|
210
|
+
dp[colspan][index] ||= [0] # add a fake cell with length 0.
|
211
|
+
dp[colspan][index][colspan] ||= 0 # initialize column length to 0.
|
212
|
+
|
213
|
+
# the last index `colspan` means width of the single column (split
|
214
|
+
# at end of each column), not a width made up of multiple columns.
|
215
|
+
single_column_length = [cell_width, dp[colspan][index][colspan]].max
|
216
|
+
dp[colspan][index][colspan] = single_column_length
|
217
|
+
|
218
|
+
index += colspan
|
219
|
+
end
|
195
220
|
end
|
196
|
-
end
|
197
221
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
222
|
+
# run DP.
|
223
|
+
(1..n_cols).each do |colspan|
|
224
|
+
dp[colspan] ||= []
|
225
|
+
(0..n_cols-colspan).each do |index|
|
226
|
+
dp[colspan][index] ||= [1]
|
227
|
+
(1...colspan).each do |offset|
|
228
|
+
# processed level became reverse map from width => [offset, ...].
|
229
|
+
left_colspan = offset
|
230
|
+
left_index = index
|
231
|
+
left_width = dp[left_colspan][left_index].keys.first
|
232
|
+
|
233
|
+
right_colspan = colspan - left_colspan
|
234
|
+
right_index = index + offset
|
235
|
+
right_width = dp[right_colspan][right_index].keys.first
|
236
|
+
|
237
|
+
dp[colspan][index][offset] = left_width + right_width + space_width
|
210
238
|
end
|
211
|
-
|
212
|
-
|
239
|
+
|
240
|
+
# reverse map it for resolution (max width and short offset first).
|
241
|
+
rmap = {}
|
242
|
+
dp[colspan][index].each_with_index do |width, offset|
|
243
|
+
rmap[width] ||= []
|
244
|
+
rmap[width] << offset
|
213
245
|
end
|
214
|
-
|
246
|
+
|
247
|
+
# sort reversely and store it back.
|
248
|
+
dp[colspan][index] = rmap.sort.reverse.to_h
|
215
249
|
end
|
216
250
|
end
|
251
|
+
|
252
|
+
resolve = -> (colspan, full_width, index = 0) do
|
253
|
+
# stop if reaches the bottom level.
|
254
|
+
return @column_widths[index] = full_width if colspan == 1
|
255
|
+
|
256
|
+
# choose best split offset for partition, or second best result
|
257
|
+
# if first one is not dividable.
|
258
|
+
candidate_offsets = dp[colspan][index].collect(&:last).flatten
|
259
|
+
offset = candidate_offsets[0]
|
260
|
+
offset = candidate_offsets[1] if offset == colspan
|
261
|
+
|
262
|
+
# prepare for next round.
|
263
|
+
left_colspan = offset
|
264
|
+
left_index = index
|
265
|
+
left_width = dp[left_colspan][left_index].keys.first
|
266
|
+
|
267
|
+
right_colspan = colspan - left_colspan
|
268
|
+
right_index = index + offset
|
269
|
+
right_width = dp[right_colspan][right_index].keys.first
|
270
|
+
|
271
|
+
# calculate reference column width, give remaining spaces to left.
|
272
|
+
total_non_space_width = full_width - (colspan - 1) * space_width
|
273
|
+
ref_column_width = total_non_space_width / colspan
|
274
|
+
remainder = total_non_space_width % colspan
|
275
|
+
rem_left_width = [remainder, left_colspan].min
|
276
|
+
rem_right_width = remainder - rem_left_width
|
277
|
+
ref_left_width = ref_column_width * left_colspan +
|
278
|
+
(left_colspan - 1) * space_width + rem_left_width
|
279
|
+
ref_right_width = ref_column_width * right_colspan +
|
280
|
+
(right_colspan - 1) * space_width + rem_right_width
|
281
|
+
|
282
|
+
# at most one width can be greater than the reference width.
|
283
|
+
if left_width <= ref_left_width and right_width <= ref_right_width
|
284
|
+
# use refernce width (evenly partition).
|
285
|
+
left_width = ref_left_width
|
286
|
+
right_width = ref_right_width
|
287
|
+
else
|
288
|
+
# the wider one takes its value, shorter one takes the rest.
|
289
|
+
if left_width > ref_left_width
|
290
|
+
right_width = full_width - left_width - space_width
|
291
|
+
else
|
292
|
+
left_width = full_width - right_width - space_width
|
293
|
+
end
|
294
|
+
end
|
295
|
+
|
296
|
+
# run next round.
|
297
|
+
resolve.call(left_colspan, left_width, left_index)
|
298
|
+
resolve.call(right_colspan, right_width, right_index)
|
299
|
+
end
|
300
|
+
|
301
|
+
full_width = dp[n_cols][0].keys.first
|
302
|
+
unless style.width.nil?
|
303
|
+
new_width = style.width - space_width - style.border_y.length
|
304
|
+
if new_width < full_width
|
305
|
+
raise "Table width exceeds wanted width " +
|
306
|
+
"of #{style.width} characters."
|
307
|
+
end
|
308
|
+
full_width = new_width
|
309
|
+
end
|
310
|
+
|
311
|
+
resolve.call(n_cols, full_width)
|
217
312
|
end
|
218
313
|
|
219
314
|
##
|
@@ -235,5 +330,14 @@ module Terminal
|
|
235
330
|
def title_cell_options
|
236
331
|
{:value => @title, :alignment => :center, :colspan => number_of_columns}
|
237
332
|
end
|
333
|
+
|
334
|
+
def require_column_widths_recalc
|
335
|
+
@require_column_widths_recalc = true
|
336
|
+
end
|
337
|
+
|
338
|
+
def column_widths
|
339
|
+
recalc_column_widths if @require_column_widths_recalc
|
340
|
+
@column_widths
|
341
|
+
end
|
238
342
|
end
|
239
343
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: terminal-table
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.7.
|
4
|
+
version: 1.7.2
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- TJ Holowaychuk
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2016-09-
|
12
|
+
date: 2016-09-09 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: bundler
|