tabulo 0.4.2 → 0.5.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 +6 -0
- data/README.md +79 -17
- data/lib/tabulo/column.rb +10 -4
- data/lib/tabulo/table.rb +58 -0
- data/lib/tabulo/version.rb +1 -1
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 452523797b11a532c291705852d73cc00c7aa93b
|
4
|
+
data.tar.gz: 889621678407822d354bbc5aab7a086aaefdf1b4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b5311c3013bdba6ff2e7c6a8f0a31d0373d5167c9f34aa45caf2ca1cc5d49c8fbb5c058f166daa6b0d5da41d9d516ee87fd256893d7ce6496277bac9746f0e71
|
7
|
+
data.tar.gz: 8b515f7eca75f4ba532b482d81699b711387e822668f71b9dce86a52f7e71ff27dcdc7bda955525e4d1974346272c49d28422b5c5eb85f4a981962feaedd1961
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -26,21 +26,25 @@ end
|
|
26
26
|
| 5000000 | 10000000 |
|
27
27
|
```
|
28
28
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
29
|
+
Tabulo is flexible:
|
30
|
+
|
31
|
+
* Fix individual column widths, then either [wrap](#width-wrapping-truncation) or
|
32
|
+
[truncate](#width-wrapping-truncation) the overflow as you prefer.
|
33
|
+
* Alternatively, [shrinkwrap](#shrinkwrap) the table so that each column is just wide enough for
|
34
|
+
its contents.
|
35
|
+
* You can cap total table width when shrinkwrapping, to [stop it overflowing your terminal](#max-table-width)
|
36
|
+
horizontally and becoming an unreadable mess.
|
37
|
+
* Cell content [alignment](#cell-alignment) is configurable, but with useful defaults, with numbers
|
38
|
+
aligned right and strings left.
|
39
|
+
* Headers can be [repeated](#repeating-headers) as desired.
|
40
|
+
* A `Tabulo::Table` is an `Enumerable`, so you can [step through it](#enumerator) one row at a time,
|
41
|
+
without having to wait for the entire underlying collection to load.
|
42
|
+
* Each `Tabulo::Row` is also an `Enumerable`.
|
39
43
|
|
40
44
|
```ruby
|
41
45
|
table.each do |row|
|
42
46
|
row.each do |cell|
|
43
|
-
# cell => 1, 2... 2, 4... etc.
|
47
|
+
# cell => 1, 2 ... 2, 4 ... etc.
|
44
48
|
end
|
45
49
|
end
|
46
50
|
```
|
@@ -123,6 +127,7 @@ end
|
|
123
127
|
| 5 | 10 | true |
|
124
128
|
```
|
125
129
|
|
130
|
+
<a name="cell-alignment"></a>
|
126
131
|
### Cell alignment
|
127
132
|
|
128
133
|
By default, column header text is center-aligned, while the content of each body cell is aligned
|
@@ -131,19 +136,20 @@ and `true`) are center-aligned. This can be customized by passing `:center`, `:l
|
|
131
136
|
the `align_header` or `align_body` options of `add_column`, e.g.:
|
132
137
|
|
133
138
|
```ruby
|
134
|
-
|
139
|
+
table.add_column("Doubled", align_header: :left, align_body: :left) { |n| n * 2 }
|
135
140
|
```
|
136
141
|
|
142
|
+
<a name="width-wrapping-truncation"></a>
|
137
143
|
### Column width, wrapping and truncation
|
138
144
|
|
139
145
|
By default, column width is fixed at 12 characters, plus 1 character of padding on either side.
|
140
146
|
This can be adjusted on a column-by-column basis using the `width` option of `add_column`:
|
141
147
|
|
142
148
|
```ruby
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
149
|
+
table = Tabulo::Table.new([1, 2]) do |t|
|
150
|
+
t.add_column(:itself, width: 6)
|
151
|
+
t.add_column(:even?, width: 9)
|
152
|
+
end
|
147
153
|
```
|
148
154
|
|
149
155
|
```
|
@@ -159,7 +165,7 @@ If you want to set the default column width for all columns of the table to some
|
|
159
165
|
than 12, use the `column_width` option when initializing the table:
|
160
166
|
|
161
167
|
```ruby
|
162
|
-
|
168
|
+
table = Tabulo::Table.new([1, 2], columns: %i(itself even?), column_width: 6)
|
163
169
|
```
|
164
170
|
|
165
171
|
```
|
@@ -173,6 +179,60 @@ than 12, use the `column_width` option when initializing the table:
|
|
173
179
|
|
174
180
|
Widths set for individual columns always override the default column width for the table.
|
175
181
|
|
182
|
+
<a name="shrinkwrap"></a>
|
183
|
+
### Automating column widths
|
184
|
+
|
185
|
+
Instead of setting column widths "manually", you can tell the table to sort out the widths
|
186
|
+
itself, so that each column is just wide enough for its header and contents (plus a character
|
187
|
+
of padding):
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
table = Tabulo::Table.new([1, 2], columns: %i(itself even?))
|
191
|
+
table.shrinkwrap!
|
192
|
+
```
|
193
|
+
|
194
|
+
```
|
195
|
+
> puts table
|
196
|
+
+--------+-------+
|
197
|
+
| itself | even? |
|
198
|
+
+--------+-------+
|
199
|
+
| 1 | false |
|
200
|
+
| 2 | true |
|
201
|
+
```
|
202
|
+
|
203
|
+
The `shrinkwrap!` method returns the table itself, so you can "wrap-and-print" in one go:
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
puts Tabulo::Table.new([1, 2], columns: %i(itself even?)).shrinkwrap!
|
207
|
+
```
|
208
|
+
|
209
|
+
<a name="max-table-width"></a>
|
210
|
+
You can place an upper limit on the total width of the table when shrinkwrapping:
|
211
|
+
|
212
|
+
```ruby
|
213
|
+
puts Tabulo::Table.new([1, 2], columns: %i(itself even?)).shrinkwrap!(max_table_width: 17)
|
214
|
+
```
|
215
|
+
|
216
|
+
```
|
217
|
+
+-------+-------+
|
218
|
+
| itsel | even? |
|
219
|
+
| f | |
|
220
|
+
+-------+-------+
|
221
|
+
| 1 | false |
|
222
|
+
| 2 | true |
|
223
|
+
```
|
224
|
+
|
225
|
+
If the table cannot be fit within `max_column_width`, column widths are reduced as required, with
|
226
|
+
wrapping or truncation then occuring as necessary (see [Overflow handling](#overflow-handling)).
|
227
|
+
Under the hood, a character of width is deducted column by column—the widest column being
|
228
|
+
targetted each time—until the table will fit. This is very useful when you want to ensure the
|
229
|
+
table will not overflow your terminal horizontally.
|
230
|
+
|
231
|
+
Note that shrinkwrapping necessarily involves traversing the entire collection up front as
|
232
|
+
the maximum cell width needs to be calculated for each column. You may not want to do this
|
233
|
+
if the collection is very large.
|
234
|
+
|
235
|
+
<a name="overflow-handling"></a>
|
176
236
|
### Overflow handling
|
177
237
|
|
178
238
|
By default, if cell contents exceed their column width, they are wrapped for as many rows as
|
@@ -253,6 +313,7 @@ of the underlying cell value, not the way it is formatted. This is usually the d
|
|
253
313
|
Note also that the item yielded to `.each` for each cell when enumerating over a `Tabulo::Row` is
|
254
314
|
the underlying value of that cell, not its formatted value.
|
255
315
|
|
316
|
+
<a name="repeating-headers"></a>
|
256
317
|
### Repeating headers
|
257
318
|
|
258
319
|
By default, headers are only shown once, at the top of the table (`header_frequency: :start`). If
|
@@ -286,6 +347,7 @@ table = Tabulo::Table.new(1..10, columns: %i(itself even?), header_frequency: 5)
|
|
286
347
|
| 10 | true |
|
287
348
|
```
|
288
349
|
|
350
|
+
<a name="enumerator"></a>
|
289
351
|
### Using a Table Enumerator
|
290
352
|
|
291
353
|
Because it's an `Enumerable`, a `Tabulo::Table` can also give you an `Enumerator`,
|
data/lib/tabulo/column.rb
CHANGED
@@ -3,7 +3,8 @@ module Tabulo
|
|
3
3
|
# @!visibility private
|
4
4
|
class Column
|
5
5
|
|
6
|
-
|
6
|
+
attr_accessor :width
|
7
|
+
attr_reader :header, :label
|
7
8
|
|
8
9
|
# @!visibility private
|
9
10
|
def initialize(options)
|
@@ -28,9 +29,14 @@ module Tabulo
|
|
28
29
|
# @!visibility private
|
29
30
|
def body_cell(source)
|
30
31
|
cell_datum = body_cell_value(source)
|
31
|
-
|
32
|
-
real_alignment = @align_body || infer_alignment(cell_datum)
|
33
|
-
align_cell_content(
|
32
|
+
formatted_content = @formatter.call(cell_datum)
|
33
|
+
real_alignment = (@align_body || infer_alignment(cell_datum))
|
34
|
+
align_cell_content(formatted_content, real_alignment)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @!visibility private
|
38
|
+
def formatted_cell_content(source)
|
39
|
+
@formatter.call(body_cell_value(source))
|
34
40
|
end
|
35
41
|
|
36
42
|
# @!visibility private
|
data/lib/tabulo/table.rb
CHANGED
@@ -148,6 +148,64 @@ module Tabulo
|
|
148
148
|
format_row(false, HORIZONTAL_RULE_CHARACTER, CORNER_CHARACTER, &:horizontal_rule)
|
149
149
|
end
|
150
150
|
|
151
|
+
# Reset all the column widths so that each column is *just* wide enough to accommodate
|
152
|
+
# its header text as well as the formatted content of each its cells for the entire
|
153
|
+
# collection, together with a single character of padding on either side of the column,
|
154
|
+
# without any wrapping.
|
155
|
+
#
|
156
|
+
# Note that calling this method will cause the entire source Enumerable to
|
157
|
+
# be traversed and all the column extractors and formatters to be applied in order
|
158
|
+
# to calculate the required widths.
|
159
|
+
#
|
160
|
+
# @param [Hash] options
|
161
|
+
# @option options [String] :max_table_width (nil) If provided, stops the total table
|
162
|
+
# width (including padding and borders) from expanding beyond this number of characters.
|
163
|
+
# Width is deducted from columns if required to achieve this, with one character progressively
|
164
|
+
# deducted from the width of the widest column until the target is reached. When the
|
165
|
+
# table is printed, wrapping or truncation will then occur in these columns as required
|
166
|
+
# (depending on how they were configured).
|
167
|
+
#
|
168
|
+
# @return [Table] the Table itself
|
169
|
+
def shrinkwrap!(options = { })
|
170
|
+
return self if columns.none?
|
171
|
+
max_table_width = options[:max_table_width]
|
172
|
+
|
173
|
+
header_widths = columns.map { |c| c.header.length }
|
174
|
+
|
175
|
+
column_widths = @sources.inject(header_widths) do |widths, source|
|
176
|
+
columns.map { |c| c.formatted_cell_content(source).length }.zip(widths).map(&:max)
|
177
|
+
end
|
178
|
+
|
179
|
+
columns.zip(column_widths).each do |column, width|
|
180
|
+
column.width = width
|
181
|
+
end
|
182
|
+
|
183
|
+
if max_table_width
|
184
|
+
total_columns_width = columns.inject(0) { |sum, column| sum + column.width }
|
185
|
+
total_padding = columns.count * 2
|
186
|
+
total_borders = columns.count + 1
|
187
|
+
unadjusted_table_width = total_columns_width + total_padding + total_borders
|
188
|
+
|
189
|
+
# Ensure max table width is at least wide enough to accommodate table borders and padding
|
190
|
+
# and one character of content.
|
191
|
+
# TODO Document this behaviour.
|
192
|
+
min_table_width = total_padding + total_borders + columns.count
|
193
|
+
max_table_width = min_table_width if min_table_width > max_table_width
|
194
|
+
|
195
|
+
required_reduction = [unadjusted_table_width - max_table_width, 0].max
|
196
|
+
|
197
|
+
required_reduction.times do
|
198
|
+
widest_column = columns.inject(columns.first) do |widest, column|
|
199
|
+
column.width >= widest.width ? column : widest
|
200
|
+
end
|
201
|
+
|
202
|
+
widest_column.width -= 1
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
self
|
207
|
+
end
|
208
|
+
|
151
209
|
# @!visibility private
|
152
210
|
def formatted_body_row(source, options = { with_header: false })
|
153
211
|
inner = format_row { |column| column.body_cell(source) }
|
data/lib/tabulo/version.rb
CHANGED