tabulo 0.5.1 → 0.6.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 +18 -14
- data/README.md +23 -16
- data/TODO.md +1 -7
- data/lib/tabulo/column.rb +25 -12
- data/lib/tabulo/row.rb +2 -2
- data/lib/tabulo/table.rb +96 -73
- data/lib/tabulo/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: 84dadcb8679194ba436e2e213defc55800771628
|
4
|
+
data.tar.gz: aa8d2182569ba3a439bce0b82ef8ceeeb36a4b81
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 91d583322688d1db9f7c0dd21111f40d039da50fc767c78eecda2d640b75e42bae6478bc73a88b2c0810e1ce20fe35b61c7ad550a00b5c8a261fb2bf9e7c4b34
|
7
|
+
data.tar.gz: e0cee253d0513f05158b84bacd7c3e40ad0c546e5765b28c726ecab9936d7c67fa5893d032925bb43c28a96bc2002533c218105bf1ac0fdf43de07559b1106ad
|
data/CHANGELOG.md
CHANGED
@@ -1,16 +1,21 @@
|
|
1
1
|
# Changelog
|
2
2
|
|
3
|
-
|
3
|
+
### v0.6.0
|
4
4
|
|
5
|
-
*
|
5
|
+
* Correctly handle newlines in cell content.
|
6
|
+
* Use keyword arguments instead of option hashes.
|
7
|
+
* Write remaining pending specs.
|
6
8
|
|
7
|
-
|
9
|
+
### v0.5.1
|
10
|
+
|
11
|
+
* Unsuccessful attempt to fix broken appearance of http://www.rubydoc.info/gems/tabulo/0.5.1
|
12
|
+
|
13
|
+
### v0.5.0
|
8
14
|
|
9
15
|
* Add Table#shrinkwrap! method to automate column widths so they "just fit".
|
10
16
|
* Improve documentation.
|
11
|
-
* Minor tidy-ups.
|
12
17
|
|
13
|
-
|
18
|
+
### v0.4.2
|
14
19
|
|
15
20
|
* Improve README.
|
16
21
|
* Fix error when printing a Table, or a Row thereof, when the Table doesn't
|
@@ -18,44 +23,43 @@
|
|
18
23
|
* Remove unused development dependency on yard-tomdoc.
|
19
24
|
* Write more specs.
|
20
25
|
|
21
|
-
|
26
|
+
### v0.4.1
|
22
27
|
|
23
28
|
* Update README to reflect default column width of 12.
|
24
29
|
|
25
|
-
|
30
|
+
### v0.4.0
|
26
31
|
|
27
32
|
* Increase default column width from 8 to 12
|
28
33
|
* Allow default column width to be configured when initializing a Table
|
29
34
|
* Minor code tidy-ups, including removal of undocumented ability for
|
30
35
|
Table#add_column to accept a Column instance directly.
|
31
36
|
|
32
|
-
|
37
|
+
### v0.3.1
|
33
38
|
|
34
39
|
* Fix width and other options ignored by Table#add_column.
|
35
40
|
|
36
|
-
|
41
|
+
### v0.3.0
|
37
42
|
|
38
43
|
* Rename Table#header_row to Table#formatted_header
|
39
44
|
* Improve documentation, and use Yardoc instead of Tomdoc
|
40
45
|
* Remove Tabulo::Column from the publicly documented API.
|
41
46
|
|
42
|
-
|
47
|
+
### v0.2.2
|
43
48
|
|
44
49
|
* Write documentation
|
45
|
-
* Create a TODO file
|
46
50
|
|
47
|
-
|
51
|
+
### v0.2.1
|
48
52
|
|
49
53
|
* Code tidy-ups
|
50
54
|
* Tidy-ups and improvements to README, including adding badges for test coverage etc..
|
51
55
|
|
52
|
-
|
56
|
+
### v0.2.0
|
53
57
|
|
54
58
|
* Allow columns to be initialized with `columns` option in `Table` initializer
|
55
59
|
* Removed redundant `truncate` option.
|
56
60
|
* Rename `wrap_cells_to` to `wrap_body_cells_to`.
|
57
61
|
* Improve README.
|
58
62
|
|
59
|
-
|
63
|
+
### v0.1.0
|
60
64
|
|
61
65
|
Initial release.
|
data/README.md
CHANGED
@@ -4,6 +4,7 @@
|
|
4
4
|
[![Build Status][BS img]][Build Status]
|
5
5
|
[![Dependency Status][DS img]][Dependency Status]
|
6
6
|
[![Coverage Status][CS img]][Coverage Status]
|
7
|
+
[![Code Climate][CC img]][Code Climate]
|
7
8
|
|
8
9
|
## Overview
|
9
10
|
|
@@ -26,28 +27,30 @@ end
|
|
26
27
|
| 5000000 | 10000000 |
|
27
28
|
```
|
28
29
|
|
29
|
-
|
30
|
+
## Features
|
30
31
|
|
31
|
-
* Fix individual column widths, then either [wrap](#
|
32
|
-
[truncate](#
|
32
|
+
* [Fix](#fixed-column-widths) individual column widths, then either [wrap](#overflow-handling) or
|
33
|
+
[truncate](#overflow-handling) the overflow as you prefer.
|
33
34
|
* Alternatively, [shrinkwrap](#shrinkwrap) the table so that each column is just wide enough for
|
34
35
|
its contents.
|
35
36
|
* You can cap total table width when shrinkwrapping, to [stop it overflowing your terminal](#max-table-width)
|
36
37
|
horizontally and becoming an unreadable mess.
|
37
38
|
* Cell content alignment is [configurable](#cell-alignment), but with useful defaults, with numbers
|
38
39
|
aligned right and strings left.
|
39
|
-
* Headers
|
40
|
+
* Headers are [repeatable](#repeating-headers)
|
41
|
+
* Newlines within cell content are correctly handled.
|
40
42
|
* A `Tabulo::Table` is an `Enumerable`, so you can [step through it](#enumerator) one row at a time,
|
41
43
|
without having to wait for the entire underlying collection to load.
|
42
|
-
* Each `Tabulo::Row` is also an `Enumerable
|
44
|
+
* Each `Tabulo::Row` is also an `Enumerable`:
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
end
|
50
|
-
|
46
|
+
>
|
47
|
+
```ruby
|
48
|
+
table.each do |row|
|
49
|
+
row.each do |cell|
|
50
|
+
# cell => 1, 2 ... 2, 4 ... etc.
|
51
|
+
end
|
52
|
+
end
|
53
|
+
```
|
51
54
|
|
52
55
|
## Installation
|
53
56
|
|
@@ -139,9 +142,11 @@ the `align_header` or `align_body` options of `add_column`, e.g.:
|
|
139
142
|
table.add_column("Doubled", align_header: :left, align_body: :left) { |n| n * 2 }
|
140
143
|
```
|
141
144
|
|
142
|
-
<a name="width-wrapping-truncation"></a>
|
143
145
|
### Column width, wrapping and truncation
|
144
146
|
|
147
|
+
<a name="fixed-column-widths"></a>
|
148
|
+
#### Configuring fixed widths
|
149
|
+
|
145
150
|
By default, column width is fixed at 12 characters, plus 1 character of padding on either side.
|
146
151
|
This can be adjusted on a column-by-column basis using the `width` option of `add_column`:
|
147
152
|
|
@@ -180,7 +185,7 @@ table = Tabulo::Table.new([1, 2], columns: %i(itself even?), column_width: 6)
|
|
180
185
|
Widths set for individual columns always override the default column width for the table.
|
181
186
|
|
182
187
|
<a name="shrinkwrap"></a>
|
183
|
-
|
188
|
+
#### Automating column widths
|
184
189
|
|
185
190
|
Instead of setting column widths "manually", you can tell the table to sort out the widths
|
186
191
|
itself, so that each column is just wide enough for its header and contents (plus a character
|
@@ -222,7 +227,7 @@ puts Tabulo::Table.new([1, 2], columns: %i(itself even?)).shrinkwrap!(max_table_
|
|
222
227
|
| 2 | true |
|
223
228
|
```
|
224
229
|
|
225
|
-
If the table cannot be fit within `
|
230
|
+
If the table cannot be fit within `max_table_width`, column widths are reduced as required, with
|
226
231
|
wrapping or truncation then occuring as necessary (see [Overflow handling](#overflow-handling)).
|
227
232
|
Under the hood, a character of width is deducted column by column—the widest column being
|
228
233
|
targetted each time—until the table will fit. This is very useful when you want to ensure the
|
@@ -233,7 +238,7 @@ the maximum cell width needs to be calculated for each column. You may not want
|
|
233
238
|
if the collection is very large.
|
234
239
|
|
235
240
|
<a name="overflow-handling"></a>
|
236
|
-
|
241
|
+
#### Overflow handling
|
237
242
|
|
238
243
|
By default, if cell contents exceed their column width, they are wrapped for as many rows as
|
239
244
|
required:
|
@@ -394,8 +399,10 @@ License](http://opensource.org/licenses/MIT).
|
|
394
399
|
[Build Status]: https://travis-ci.org/matt-harvey/tabulo
|
395
400
|
[Dependency Status]: https://gemnasium.com/matt-harvey/tabulo
|
396
401
|
[Coverage Status]: https://coveralls.io/r/matt-harvey/tabulo
|
402
|
+
[Code Climate]: https://codeclimate.com/github/matt-harvey/tabulo
|
397
403
|
|
398
404
|
[GV img]: https://img.shields.io/gem/v/tabulo.svg
|
399
405
|
[BS img]: https://img.shields.io/travis/matt-harvey/tabulo.svg
|
400
406
|
[DS img]: https://img.shields.io/gemnasium/matt-harvey/tabulo.svg
|
401
407
|
[CS img]: https://img.shields.io/coveralls/matt-harvey/tabulo.svg
|
408
|
+
[CC img]: https://img.shields.io/codeclimate/github/matt-harvey/tabulo.svg
|
data/TODO.md
CHANGED
@@ -1,9 +1,3 @@
|
|
1
1
|
# TODO
|
2
2
|
|
3
|
-
*
|
4
|
-
* Raise an ArgumentError for disallowed arguments and options (this is
|
5
|
-
a library!)
|
6
|
-
* Column#initialize should have the same signature as Table#add_column.
|
7
|
-
* Handle multiline cell content (i.e. when the calculated cell value
|
8
|
-
itself contains a newline).
|
9
|
-
* Pending specs.
|
3
|
+
* Fix broken appearance of http://www.rubydoc.info/gems/tabulo/<version> .
|
data/lib/tabulo/column.rb
CHANGED
@@ -7,31 +7,34 @@ module Tabulo
|
|
7
7
|
attr_reader :header, :label
|
8
8
|
|
9
9
|
# @!visibility private
|
10
|
-
def initialize(
|
11
|
-
|
12
|
-
|
13
|
-
@
|
14
|
-
@
|
15
|
-
@
|
16
|
-
@
|
10
|
+
def initialize(label:, header:, width:, align_header:, align_body:,
|
11
|
+
formatter:, extractor:)
|
12
|
+
|
13
|
+
@label = label
|
14
|
+
@header = header
|
15
|
+
@width = width
|
16
|
+
@align_header = align_header
|
17
|
+
@align_body = align_body
|
18
|
+
@formatter = formatter
|
19
|
+
@extractor = extractor
|
17
20
|
end
|
18
21
|
|
19
22
|
# @!visibility private
|
20
|
-
def
|
21
|
-
|
23
|
+
def header_subcells
|
24
|
+
infilled_subcells(@header, @align_header)
|
22
25
|
end
|
23
26
|
|
24
27
|
# @!visibility private
|
25
28
|
def horizontal_rule
|
26
|
-
Table::HORIZONTAL_RULE_CHARACTER *
|
29
|
+
Table::HORIZONTAL_RULE_CHARACTER * width
|
27
30
|
end
|
28
31
|
|
29
32
|
# @!visibility private
|
30
|
-
def
|
33
|
+
def body_subcells(source)
|
31
34
|
cell_datum = body_cell_value(source)
|
32
35
|
formatted_content = @formatter.call(cell_datum)
|
33
36
|
real_alignment = (@align_body || infer_alignment(cell_datum))
|
34
|
-
|
37
|
+
infilled_subcells(formatted_content, real_alignment)
|
35
38
|
end
|
36
39
|
|
37
40
|
# @!visibility private
|
@@ -46,6 +49,16 @@ module Tabulo
|
|
46
49
|
|
47
50
|
private
|
48
51
|
|
52
|
+
# @!visibility private
|
53
|
+
def infilled_subcells(str, real_alignment)
|
54
|
+
str.split($/, -1).flat_map do |substr|
|
55
|
+
num_subsubcells = [1, (substr.length.to_f / width).ceil].max
|
56
|
+
(0...num_subsubcells).map do |i|
|
57
|
+
align_cell_content(substr.slice(i * width, width), real_alignment)
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
49
62
|
# @!visibility private
|
50
63
|
def align_cell_content(content, real_alignment)
|
51
64
|
padding = [@width - content.length, 0].max
|
data/lib/tabulo/row.rb
CHANGED
@@ -4,10 +4,10 @@ module Tabulo
|
|
4
4
|
include Enumerable
|
5
5
|
|
6
6
|
# @!visibility private
|
7
|
-
def initialize(table, source,
|
7
|
+
def initialize(table, source, with_header: true)
|
8
8
|
@table = table
|
9
9
|
@source = source
|
10
|
-
@with_header =
|
10
|
+
@with_header = with_header
|
11
11
|
end
|
12
12
|
|
13
13
|
# Calls the given block once for each cell in the {Row}, passing that cell as parameter.
|
data/lib/tabulo/table.rb
CHANGED
@@ -15,73 +15,67 @@ module Tabulo
|
|
15
15
|
attr_reader :columns
|
16
16
|
|
17
17
|
# @param [Enumerable] sources the underlying Enumerable from which the table will derive its data
|
18
|
-
# @param [
|
19
|
-
# @option options [Array[Symbol]] :columns ([]) Specifies the initial columns.
|
18
|
+
# @param [Array[Symbol]] columns Specifies the initial columns.
|
20
19
|
# Each element of the Array will be used to create a column whose content is
|
21
20
|
# created by calling the corresponding method on each element of sources. Note
|
22
21
|
# the {#add_column} method is a much more flexible way to set up columns on the table.
|
23
|
-
# @
|
22
|
+
# @param [Fixnum, nil] column_width The default column width for columns in this
|
24
23
|
# table, not excluding padding. If nil, then DEFAULT_COLUMN_WIDTH will be used.
|
25
|
-
# @
|
24
|
+
# @param [:start, nil, Fixnum] header_frequency Controls the display of column headers.
|
26
25
|
# If passed <tt>:start</tt>, headers will be shown at the top of the table only. If passed <tt>nil</tt>,
|
27
26
|
# headers will not be shown. If passed a Fixnum N (> 0), headers will be shown at the top of the table,
|
28
27
|
# then repeated every N rows.
|
29
|
-
# @
|
28
|
+
# @param [nil, Fixnum] wrap_header_cells_to Controls wrapping behaviour for header
|
30
29
|
# cells if the content thereof is longer than the column's fixed width. If passed <tt>nil</tt> (default),
|
31
30
|
# content will be wrapped for as many rows as required to accommodate it. If passed a Fixnum N (> 0),
|
32
31
|
# content will be wrapped up to N rows and then truncated thereafter.
|
33
|
-
# @
|
32
|
+
# @param [nil, Fixnum] wrap_body_cells_to Controls wrapping behaviour for table cells (excluding
|
34
33
|
# headers), if their content is longer than the column's fixed width. If passed <tt>nil</tt>, content will
|
35
34
|
# be wrapped for as many rows as required to accommodate it. If passed a Fixnum N (> 0), content will be
|
36
35
|
# wrapped up to N rows and then truncated thereafter.
|
37
36
|
#
|
38
37
|
# @return [Table] a new Table
|
39
|
-
def initialize(sources,
|
40
|
-
|
41
|
-
columns: [],
|
42
|
-
column_width: DEFAULT_COLUMN_WIDTH,
|
43
|
-
header_frequency: :start,
|
38
|
+
def initialize(sources, columns: [], column_width: nil, header_frequency: :start,
|
39
|
+
wrap_header_cells_to: nil, wrap_body_cells_to: nil)
|
44
40
|
|
45
|
-
|
46
|
-
|
47
|
-
|
41
|
+
@sources = sources
|
42
|
+
@header_frequency = header_frequency
|
43
|
+
@wrap_header_cells_to = wrap_header_cells_to
|
44
|
+
@wrap_body_cells_to = wrap_body_cells_to
|
48
45
|
|
49
|
-
|
46
|
+
@default_column_width = (column_width || DEFAULT_COLUMN_WIDTH)
|
50
47
|
|
51
|
-
@header_frequency = opts[:header_frequency]
|
52
|
-
@wrap_header_cells_to = opts[:wrap_header_cells_to]
|
53
|
-
@wrap_body_cells_to = opts[:wrap_body_cells_to]
|
54
|
-
@sources = sources
|
55
48
|
@joiner = "|"
|
56
49
|
@truncation_indicator = "~"
|
57
50
|
@padding_character = " "
|
58
|
-
|
59
|
-
@columns =
|
51
|
+
|
52
|
+
@columns = []
|
53
|
+
columns.each { |item| add_column(item) }
|
54
|
+
|
60
55
|
yield self if block_given?
|
61
56
|
end
|
62
57
|
|
63
58
|
# Adds a column to the Table.
|
64
59
|
#
|
65
60
|
# @param [Symbol, String] label A unique identifier for this column, which by default will
|
66
|
-
# also be used as the column header text (see also the header
|
61
|
+
# also be used as the column header text (see also the header param). If the
|
67
62
|
# extractor argument is not also provided, then the label argument should correspond to
|
68
63
|
# a method to be called on each item in the table sources to provide the content
|
69
64
|
# for this column.
|
70
65
|
#
|
71
|
-
# @param [
|
72
|
-
#
|
73
|
-
#
|
74
|
-
# @option options [:left, :center, :right] :align_header (:center) Specifies how the header text
|
66
|
+
# @param [nil, #to_s] header (nil) Text to be displayed in the column header. If passed nil,
|
67
|
+
# the column's label will also be used as its header text.
|
68
|
+
# @param [:left, :center, :right] align_header (:center) Specifies how the header text
|
75
69
|
# should be aligned.
|
76
|
-
# @
|
70
|
+
# @param [:left, :center, :right, nil] align_body (nil) Specifies how the cell body contents
|
77
71
|
# should be aligned. Possible If <tt>nil</tt> is passed, then the alignment is determined
|
78
72
|
# by the type of the cell value, with numbers aligned right, booleans center-aligned, and
|
79
73
|
# other values left-aligned. Note header text alignment is configured separately using the
|
80
|
-
# :align_header
|
81
|
-
# @
|
82
|
-
# nil, then the column will take the width provided by the `column_width`
|
74
|
+
# :align_header param.
|
75
|
+
# @param [Fixnum] width (nil) Specifies the width of the column, excluding padding. If
|
76
|
+
# nil, then the column will take the width provided by the `column_width` param
|
83
77
|
# with which the Table was initialized.
|
84
|
-
# @
|
78
|
+
# @param [#to_proc] formatter (:to_s.to_proc) A lambda or other callable object that
|
85
79
|
# will be passed the calculated value of each cell to determine how it should be displayed. This
|
86
80
|
# is distinct from the extractor (see below). For example, if the extractor for this column
|
87
81
|
# generates a Date, then the formatter might format that Date in a particular way.
|
@@ -92,8 +86,18 @@ module Tabulo
|
|
92
86
|
# column. If this is not provided, then the column label will be treated as a method to be
|
93
87
|
# called on each source item to determine each cell's value.
|
94
88
|
#
|
95
|
-
def add_column(label,
|
96
|
-
|
89
|
+
def add_column(label, header: nil, align_header: :center, align_body: nil,
|
90
|
+
width: nil, formatter: :to_s.to_proc, &extractor)
|
91
|
+
|
92
|
+
@columns << Column.new(
|
93
|
+
label: label.to_sym,
|
94
|
+
header: (header || label).to_s,
|
95
|
+
align_header: align_header,
|
96
|
+
align_body: align_body,
|
97
|
+
width: (width || @default_column_width),
|
98
|
+
formatter: formatter,
|
99
|
+
extractor: (extractor || label.to_proc)
|
100
|
+
)
|
97
101
|
end
|
98
102
|
|
99
103
|
# @return [String] a graphical "ASCII" representation of the Table, suitable for
|
@@ -132,7 +136,7 @@ module Tabulo
|
|
132
136
|
|
133
137
|
# @return [String] an "ASCII" graphical representation of the Table column headers.
|
134
138
|
def formatted_header
|
135
|
-
format_row(
|
139
|
+
format_row(@wrap_header_cells_to, &:header_subcells)
|
136
140
|
end
|
137
141
|
|
138
142
|
# @return [String] an "ASCII" graphical representation of a horizontal
|
@@ -145,7 +149,8 @@ module Tabulo
|
|
145
149
|
# end
|
146
150
|
#
|
147
151
|
def horizontal_rule
|
148
|
-
|
152
|
+
inner = @columns.map { |column| surround(column.horizontal_rule, HORIZONTAL_RULE_CHARACTER) }
|
153
|
+
surround_join(inner, CORNER_CHARACTER)
|
149
154
|
end
|
150
155
|
|
151
156
|
# Reset all the column widths so that each column is *just* wide enough to accommodate
|
@@ -157,23 +162,28 @@ module Tabulo
|
|
157
162
|
# be traversed and all the column extractors and formatters to be applied in order
|
158
163
|
# to calculate the required widths.
|
159
164
|
#
|
160
|
-
# @param [
|
161
|
-
# @option options [String] :max_table_width (nil) If provided, stops the total table
|
165
|
+
# @param [nil, Numeric] max_table_width (nil) If provided, stops the total table
|
162
166
|
# width (including padding and borders) from expanding beyond this number of characters.
|
163
167
|
# Width is deducted from columns if required to achieve this, with one character progressively
|
164
168
|
# deducted from the width of the widest column until the target is reached. When the
|
165
169
|
# table is printed, wrapping or truncation will then occur in these columns as required
|
166
|
-
# (depending on how they were configured).
|
170
|
+
# (depending on how they were configured). Note that regardless of the value passed to
|
171
|
+
# max_table_width, the table will always be left wide enough to accommodate at least
|
172
|
+
# 1 character's width of content, 1 character of left padding and 1 character of right padding
|
173
|
+
# in each column, together with border characters (1 on each side of the table and 1 between
|
174
|
+
# adjacent columns). I.e. there is a certain width below width the Table will refuse to
|
175
|
+
# shrink itself.
|
167
176
|
#
|
168
177
|
# @return [Table] the Table itself
|
169
|
-
def shrinkwrap!(
|
178
|
+
def shrinkwrap!(max_table_width: nil)
|
170
179
|
return self if columns.none?
|
171
|
-
max_table_width = options[:max_table_width]
|
172
180
|
|
173
181
|
header_widths = columns.map { |c| c.header.length }
|
174
182
|
|
175
183
|
column_widths = @sources.inject(header_widths) do |widths, source|
|
176
|
-
columns.map
|
184
|
+
columns.map do |c|
|
185
|
+
c.formatted_cell_content(source).split($/, -1).map(&:length).max || 1
|
186
|
+
end.zip(widths).map(&:max)
|
177
187
|
end
|
178
188
|
|
179
189
|
columns.zip(column_widths).each do |column, width|
|
@@ -188,7 +198,6 @@ module Tabulo
|
|
188
198
|
|
189
199
|
# Ensure max table width is at least wide enough to accommodate table borders and padding
|
190
200
|
# and one character of content.
|
191
|
-
# TODO Document this behaviour.
|
192
201
|
min_table_width = total_padding + total_borders + columns.count
|
193
202
|
max_table_width = min_table_width if min_table_width > max_table_width
|
194
203
|
|
@@ -207,9 +216,9 @@ module Tabulo
|
|
207
216
|
end
|
208
217
|
|
209
218
|
# @!visibility private
|
210
|
-
def formatted_body_row(source,
|
211
|
-
inner = format_row { |column| column.
|
212
|
-
if
|
219
|
+
def formatted_body_row(source, with_header: false)
|
220
|
+
inner = format_row(@wrap_body_cells_to) { |column| column.body_subcells(source) }
|
221
|
+
if with_header
|
213
222
|
join_lines([horizontal_rule, formatted_header, horizontal_rule, inner])
|
214
223
|
else
|
215
224
|
inner
|
@@ -219,56 +228,70 @@ module Tabulo
|
|
219
228
|
private
|
220
229
|
|
221
230
|
# @!visibility private
|
222
|
-
def body_row(source,
|
223
|
-
Row.new(self, source,
|
231
|
+
def body_row(source, with_header: false)
|
232
|
+
Row.new(self, source, with_header: with_header)
|
224
233
|
end
|
225
234
|
|
226
235
|
# @!visibility private
|
227
|
-
|
228
|
-
|
236
|
+
#
|
237
|
+
# Yields each column to passed block, then wraps and joins the results to form
|
238
|
+
# a formatted row.
|
239
|
+
def format_row(wrap_cells_to)
|
240
|
+
|
241
|
+
# Create an array of "cell stacks", each of which is an array of strings that
|
242
|
+
# will be stacked on top of each other to form a wrapped cell.
|
229
243
|
cell_stacks = @columns.map do |column|
|
230
|
-
raw = yield column
|
231
|
-
wrap = (header ? @wrap_header_cells_to : @wrap_body_cells_to)
|
232
244
|
column_width = column.width
|
233
|
-
|
234
|
-
truncated
|
235
|
-
|
236
|
-
|
237
|
-
(
|
238
|
-
|
239
|
-
|
240
|
-
|
245
|
+
|
246
|
+
# Get the raw, non-wrapped, non-truncated content of the cell.
|
247
|
+
raw_subcells = yield column
|
248
|
+
|
249
|
+
truncated = (wrap_cells_to && (raw_subcells.size > wrap_cells_to))
|
250
|
+
subcells = (wrap_cells_to ? raw_subcells[0...wrap_cells_to] : raw_subcells)
|
251
|
+
|
252
|
+
subcells.map.with_index do |subcell, i|
|
253
|
+
lpad = @padding_character
|
254
|
+
rpad = (truncated && (i == subcells.size - 1) ? @truncation_indicator : @padding_character)
|
255
|
+
"#{lpad}#{subcell}#{rpad}"
|
241
256
|
end
|
242
257
|
end
|
243
258
|
|
244
|
-
|
259
|
+
max_cell_stack_height = cell_stacks.map(&:size).max || 1
|
260
|
+
|
261
|
+
# A subrow is a string representing a single horizontal slice of this row that's
|
262
|
+
# strictly one character high.
|
263
|
+
subrows = (0...max_cell_stack_height).map do |subrow_index|
|
245
264
|
cell_stacks.map.with_index do |cell_stack, column_index|
|
246
265
|
if subrow_index < cell_stack.size
|
266
|
+
# This cell stack is at least as "deep" as the subrow we're on. So just
|
267
|
+
# grab the subcell for this subrow from this cell stack.
|
247
268
|
cell_stack[subrow_index]
|
248
269
|
else
|
249
|
-
|
270
|
+
# This cell stack is not "deep" enough. So we make an empty subcell to
|
271
|
+
# add to this subrow for this column
|
272
|
+
surround(' ' * @columns[column_index].width, @padding_character)
|
250
273
|
end
|
251
274
|
end
|
252
275
|
end
|
253
276
|
|
254
|
-
|
277
|
+
# Join each subrow with border characters, then join these with newlines, to form
|
278
|
+
# the wrapped, formatted row as a single string.
|
279
|
+
join_lines(subrows.map { |subrow| surround_join(subrow, @joiner) })
|
255
280
|
end
|
256
281
|
|
257
282
|
# @!visibility private
|
258
|
-
def
|
259
|
-
|
283
|
+
def surround(str, ch0)
|
284
|
+
"#{ch0}#{str}#{ch0}"
|
285
|
+
end
|
286
|
+
|
287
|
+
# @!visibility private
|
288
|
+
def surround_join(arr, ch)
|
289
|
+
surround(arr.join(ch), ch)
|
260
290
|
end
|
261
291
|
|
262
292
|
# @!visibility private
|
263
|
-
def
|
264
|
-
|
265
|
-
label: item.to_sym,
|
266
|
-
header: item.to_s,
|
267
|
-
align_header: :center,
|
268
|
-
width: @default_column_width,
|
269
|
-
formatter: :to_s.to_proc
|
270
|
-
|
271
|
-
}.merge(options))
|
293
|
+
def join_lines(lines)
|
294
|
+
lines.join($/) # join strings with cross-platform newline
|
272
295
|
end
|
273
296
|
end
|
274
297
|
end
|
data/lib/tabulo/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tabulo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.6.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Harvey
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2017-
|
11
|
+
date: 2017-05-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|