tabulo 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 +12 -0
- data/README.md +171 -25
- data/lib/tabulo.rb +1 -0
- data/lib/tabulo/column.rb +11 -6
- data/lib/tabulo/table.rb +24 -8
- data/lib/tabulo/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 02a658d45fe5df2a6b02a39ff1ef8b85b9406a5d
|
4
|
+
data.tar.gz: 1edee8575e0098a1d5b383f596ff8ef77e3916a0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2d76f4fd33ede6de1a466affd190c6377f8e0a29b2c3986c7c4c83c0ac8001b285f880589d5a74668b572e8219c570f3aaa391b0dd8839f89c478f58b9bbc5f2
|
7
|
+
data.tar.gz: c4766b9abff559fd30f65356731e18311984b459bd67e11b7dc308bf93c92a2fab4902c6ea0c13bab81ffe5459df134074d93b2beec3ec26af8d8b5a4f4899df
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
# Changelog
|
2
|
+
|
3
|
+
## v0.2.0
|
4
|
+
|
5
|
+
* Allow columns to be initialized with `columns` option in `Table` initializer
|
6
|
+
* Removed redundant `truncate` option.
|
7
|
+
* Rename `wrap_cells_to` to `wrap_body_cells_to`.
|
8
|
+
* Improve README.
|
9
|
+
|
10
|
+
## v0.1.0
|
11
|
+
|
12
|
+
Initial release.
|
data/README.md
CHANGED
@@ -2,9 +2,9 @@
|
|
2
2
|
|
3
3
|
## Overview
|
4
4
|
|
5
|
-
Tabulo generates ASCII tables
|
5
|
+
Tabulo generates ASCII tables.
|
6
6
|
|
7
|
-
A `Tabulo::Table` can be printed:
|
7
|
+
A `Tabulo::Table` can, of course, be printed:
|
8
8
|
|
9
9
|
```
|
10
10
|
> puts table
|
@@ -16,7 +16,7 @@ A `Tabulo::Table` can be printed:
|
|
16
16
|
| 50000000 | 10000000 |
|
17
17
|
```
|
18
18
|
|
19
|
-
But it is also `Enumerable`, so you can process
|
19
|
+
But it is also `Enumerable`, so you can process one row at a time:
|
20
20
|
|
21
21
|
```ruby
|
22
22
|
table.each do |row|
|
@@ -25,6 +25,17 @@ table.each do |row|
|
|
25
25
|
end
|
26
26
|
```
|
27
27
|
|
28
|
+
And rows are themselves `Enumerable`, providing access to the underlying cell values:
|
29
|
+
|
30
|
+
```ruby
|
31
|
+
table.each do |row|
|
32
|
+
row.each do |cell|
|
33
|
+
# 1, 2, 50000000...
|
34
|
+
puts cell.class # Fixnum
|
35
|
+
end
|
36
|
+
end
|
37
|
+
```
|
38
|
+
|
28
39
|
## Installation
|
29
40
|
|
30
41
|
Add this line to your application's Gemfile:
|
@@ -37,23 +48,25 @@ And then execute:
|
|
37
48
|
|
38
49
|
$ bundle
|
39
50
|
|
40
|
-
Or install it yourself
|
51
|
+
Or install it yourself:
|
41
52
|
|
42
53
|
$ gem install tabulo
|
43
54
|
|
44
|
-
##
|
55
|
+
## Detailed usage
|
45
56
|
|
46
|
-
|
57
|
+
### Requiring the gem
|
47
58
|
|
48
59
|
```ruby
|
49
60
|
require 'tabulo'
|
50
61
|
```
|
51
62
|
|
52
|
-
|
63
|
+
### Configuring columns
|
64
|
+
|
65
|
+
You instantiate a `Tabulo::Table` by passing it an underlying `Enumerable` and then telling it
|
53
66
|
the columns you want to generate.
|
54
67
|
|
55
68
|
A simple case involves initializing columns from symbols corresponding to methods on members of the
|
56
|
-
`Enumerable`. In this case the symbol also provides the header for each column:
|
69
|
+
underlying `Enumerable`. In this case the symbol also provides the header for each column:
|
57
70
|
|
58
71
|
```ruby
|
59
72
|
table = Tabulo::Table.new([1, 2, 5]) do |t|
|
@@ -61,36 +74,169 @@ table = Tabulo::Table.new([1, 2, 5]) do |t|
|
|
61
74
|
t.add_column(:even?)
|
62
75
|
t.add_column(:odd?)
|
63
76
|
end
|
77
|
+
```
|
78
|
+
|
79
|
+
Or equivalently:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Tabulo::Table.new([1, 2, 5], columns: %i(itself even odd))
|
83
|
+
```
|
84
|
+
|
85
|
+
The resulting table looks like this:
|
64
86
|
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
87
|
+
```
|
88
|
+
> puts table
|
89
|
+
+----------+----------+----------+
|
90
|
+
| itself | even? | odd? |
|
91
|
+
+----------+----------+----------+
|
92
|
+
| 1 | false | true |
|
93
|
+
| 2 | true | false |
|
94
|
+
| 5 | false | true |
|
72
95
|
```
|
73
96
|
|
74
|
-
Columns can also be initialized using
|
75
|
-
the first argument
|
97
|
+
Columns can also be initialized using a callable to which each object will be passed to determine
|
98
|
+
the value to be displayed in the table. In this case, the first argument to `add_column` provides
|
99
|
+
the header text:
|
76
100
|
|
77
101
|
```ruby
|
78
102
|
table = Tabulo::Table.new([1, 2, 5]) do |t|
|
79
103
|
t.add_column("N", &:itself)
|
80
104
|
t.add_column("Doubled") { |n| n * 2 }
|
105
|
+
t.add_column(:odd?) # we can mix and match
|
81
106
|
end
|
107
|
+
```
|
108
|
+
|
109
|
+
```
|
110
|
+
> puts table
|
111
|
+
+----------+----------+----------+
|
112
|
+
| N | Doubled | odd? |
|
113
|
+
+----------+----------+----------+
|
114
|
+
| 1 | 2 | true |
|
115
|
+
| 2 | 4 | false |
|
116
|
+
| 5 | 10 | true |
|
117
|
+
```
|
118
|
+
|
119
|
+
### Cell alignment
|
120
|
+
|
121
|
+
By default, column header text is center-aligned, while the content of each body cell is aligned
|
122
|
+
according to its data type. Numbers are right-aligned, text is left-aligned, and booleans (`false`
|
123
|
+
and `true`) are center-aligned. This can be customized by passing `:center`, `:left` or `:right` to
|
124
|
+
the `align_header` or `align_body` options of `add_column`, e.g.:
|
125
|
+
|
126
|
+
```ruby
|
127
|
+
table.add_column("Doubled", align_header: :left, align_body: :left) { |n| n * 2 }
|
128
|
+
```
|
129
|
+
|
130
|
+
### Column width, wrapping and truncation
|
131
|
+
|
132
|
+
By default, column width is fixed at 8 characters, plus 1 character of padding on either side.
|
133
|
+
This can be customized using the `width` option of `add_column`:
|
134
|
+
|
135
|
+
```ruby
|
136
|
+
table.add_column(:even?, width: 5)
|
137
|
+
```
|
138
|
+
|
139
|
+
### Overflow handling
|
140
|
+
|
141
|
+
By default, if cell contents exceed their column width, they are wrapped for as many rows as
|
142
|
+
required:
|
143
|
+
|
144
|
+
```ruby
|
145
|
+
table = Tabulo::Table.new(["hello", "abcdefghijklmnopqrstuvwxyz"], columns: %i(itself length))
|
146
|
+
```
|
147
|
+
|
148
|
+
```
|
149
|
+
> puts table
|
150
|
+
+----------+----------+
|
151
|
+
| itself | length |
|
152
|
+
+----------+----------+
|
153
|
+
| hello | 5 |
|
154
|
+
| abcdefgh | 26 |
|
155
|
+
| ijklmnop | |
|
156
|
+
| qrstuvwx | |
|
157
|
+
| yz | |
|
158
|
+
```
|
159
|
+
|
160
|
+
Wrapping behaviour is configured for the table as a whole using the `wrap_header_cells_to` option
|
161
|
+
for header cells and `wrap_body_cells_to` for body cells, both of which default to `nil`, meaning
|
162
|
+
that cells are wrapped to as many rows as required. Passing a `Fixnum` limits wrapping to the given
|
163
|
+
number of rows, with content truncated from that point on. The `~` character is appended to the
|
164
|
+
outputted cell content to show that truncation has occurred:
|
165
|
+
|
166
|
+
```ruby
|
167
|
+
table = Tabulo::Table.new(["hello", "abcdefghijklmnopqrstuvwxyz"], wrap_body_cells_to: 1, columns: %i(itself length))
|
168
|
+
```
|
169
|
+
|
170
|
+
```
|
171
|
+
> puts table
|
172
|
+
+----------+----------+
|
173
|
+
| itself | length |
|
174
|
+
+----------+----------+
|
175
|
+
| hello | 5 |
|
176
|
+
| abcdefgh~| 26 |
|
177
|
+
```
|
82
178
|
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
179
|
+
### Repeating headers
|
180
|
+
|
181
|
+
By default, headers are only shown once, at the top of the table (`header_frequency: :start`). If
|
182
|
+
`header_frequency` is passed `nil`, headers are not shown at all; or, if passed a `Fixnum` N,
|
183
|
+
headers are shown at the top and then repeated every N rows. This can be handy when you're looking
|
184
|
+
at table that's taller than your terminal.
|
185
|
+
|
186
|
+
E.g.:
|
187
|
+
|
188
|
+
```ruby
|
189
|
+
table = Tabulo::Table.new(1..10, columns: %i(itself even?), header_frequency: 5)
|
90
190
|
```
|
91
191
|
|
92
|
-
|
192
|
+
```
|
193
|
+
> puts table
|
194
|
+
+----------+----------+
|
195
|
+
| itself | even? |
|
196
|
+
+----------+----------+
|
197
|
+
| 1 | false |
|
198
|
+
| 2 | true |
|
199
|
+
| 3 | false |
|
200
|
+
| 4 | true |
|
201
|
+
| 5 | false |
|
202
|
+
+----------+----------+
|
203
|
+
| itself | even? |
|
204
|
+
+----------+----------+
|
205
|
+
| 6 | true |
|
206
|
+
| 7 | false |
|
207
|
+
| 8 | true |
|
208
|
+
| 9 | false |
|
209
|
+
| 10 | true |
|
210
|
+
```
|
211
|
+
|
212
|
+
TODO: Write rdocs, and link to them here "for more".
|
213
|
+
|
214
|
+
### Using a Table Enumerator
|
215
|
+
|
216
|
+
Because it's an `Enumerable`, a `Tabulo::Table` can also give you an `Enumerator`,
|
217
|
+
which is useful when you want to step through rows one at a time. In a Rails console,
|
218
|
+
for example, you might do this:
|
219
|
+
|
220
|
+
```
|
221
|
+
> e = Tabulo::Table.new(User.find_each) do |t|
|
222
|
+
t.add_column(:id)
|
223
|
+
t.add_column(:email, width: 25)
|
224
|
+
end.to_enum # <-- make an Enumerator
|
225
|
+
...
|
226
|
+
> puts e.next
|
227
|
+
+----------+--------------------------+
|
228
|
+
| id | email |
|
229
|
+
+----------+--------------------------+
|
230
|
+
| 1 | jane@example.com |
|
231
|
+
=> nil
|
232
|
+
> puts e.next
|
233
|
+
| 2 | betty@example.net |
|
234
|
+
=> nil
|
235
|
+
```
|
93
236
|
|
237
|
+
Note the used of `.find_each`: we can start printing the table without having to load the entire
|
238
|
+
underlying collection. (The cost of supporting this behaviour is that Tabulo requires us to set
|
239
|
+
column widths up front, rather than adapting to the width of the widest value.)
|
94
240
|
|
95
241
|
## Development
|
96
242
|
|
data/lib/tabulo.rb
CHANGED
data/lib/tabulo/column.rb
CHANGED
@@ -2,15 +2,20 @@ module Tabulo
|
|
2
2
|
|
3
3
|
class Column
|
4
4
|
|
5
|
-
attr_reader :label, :
|
5
|
+
attr_reader :label, :width
|
6
6
|
|
7
7
|
def initialize(options)
|
8
8
|
@label, @header = options[:label], options[:header]
|
9
|
-
@
|
10
|
-
@
|
11
|
-
@extractor
|
12
|
-
@
|
13
|
-
|
9
|
+
@align_header = options[:align_header] || :center
|
10
|
+
@align_body = options[:align_body] || nil
|
11
|
+
@extractor = options[:extractor] || @label.to_proc
|
12
|
+
@formatter = options[:formatter] || :to_s.to_proc
|
13
|
+
|
14
|
+
# TODO Should be able to set these default on a Table-by-Table basis.
|
15
|
+
@width = options[:width] || Table::DEFAULT_COLUMN_WIDTH
|
16
|
+
|
17
|
+
@horizontal_rule_character =
|
18
|
+
options[:horizontal_rule_character] || Table::DEFAULT_HORIZONTAL_RULE_CHARACTER
|
14
19
|
end
|
15
20
|
|
16
21
|
def header_cell
|
data/lib/tabulo/table.rb
CHANGED
@@ -3,29 +3,47 @@ module Tabulo
|
|
3
3
|
class Table
|
4
4
|
include Enumerable
|
5
5
|
|
6
|
+
DEFAULT_COLUMN_WIDTH = 8
|
7
|
+
DEFAULT_HORIZONTAL_RULE_CHARACTER = "-"
|
8
|
+
|
6
9
|
attr_reader :columns
|
7
10
|
|
8
11
|
def initialize(sources, options = { })
|
9
12
|
opts = {
|
13
|
+
columns: [],
|
10
14
|
header_frequency: :start,
|
11
15
|
|
12
16
|
# nil to wrap to no max, 1 to wrap to 1 row then truncate, etc..
|
13
17
|
wrap_header_cells_to: nil,
|
14
|
-
|
18
|
+
wrap_body_cells_to: nil
|
15
19
|
|
16
20
|
}.merge(options)
|
17
21
|
|
18
22
|
@header_frequency = opts[:header_frequency]
|
19
23
|
@wrap_header_cells_to = opts[:wrap_header_cells_to]
|
20
|
-
@
|
24
|
+
@wrap_body_cells_to = opts[:wrap_body_cells_to]
|
21
25
|
@sources = sources
|
22
26
|
@joiner = "|"
|
23
27
|
@corner_character = "+"
|
24
28
|
@horizontal_rule_character = "-"
|
25
29
|
@truncation_indicator = "~"
|
26
30
|
@padding_character = " "
|
27
|
-
@
|
28
|
-
@
|
31
|
+
@default_column_width = DEFAULT_COLUMN_WIDTH
|
32
|
+
@columns = opts[:columns].map do |item|
|
33
|
+
case item
|
34
|
+
when Column
|
35
|
+
item
|
36
|
+
else
|
37
|
+
Column.new({
|
38
|
+
label: item.to_sym,
|
39
|
+
header: item.to_s,
|
40
|
+
align_header: :center,
|
41
|
+
horizontal_rule_character: @horizontal_rule_character,
|
42
|
+
width: @default_column_width,
|
43
|
+
formatter: :to_s.to_proc
|
44
|
+
})
|
45
|
+
end
|
46
|
+
end
|
29
47
|
yield self if block_given?
|
30
48
|
end
|
31
49
|
|
@@ -35,7 +53,6 @@ module Tabulo
|
|
35
53
|
header: label.to_s,
|
36
54
|
truncate: true,
|
37
55
|
align_header: :center,
|
38
|
-
align_body: nil,
|
39
56
|
horizontal_rule_character: @horizontal_rule_character,
|
40
57
|
width: @default_column_width,
|
41
58
|
extractor: extractor || (label.respond_to?(:to_proc) ? label.to_proc : proc { nil }),
|
@@ -89,10 +106,9 @@ module Tabulo
|
|
89
106
|
def format_row(header = false, padder = @padding_character, joiner = @joiner)
|
90
107
|
cell_stacks = @columns.map do |column|
|
91
108
|
raw = yield column
|
92
|
-
wrap = (header ? @wrap_header_cells_to : @
|
93
|
-
truncate = (column.truncate && wrap)
|
109
|
+
wrap = (header ? @wrap_header_cells_to : @wrap_body_cells_to)
|
94
110
|
column_width = column.width
|
95
|
-
cell_body_length = (
|
111
|
+
cell_body_length = (wrap ? column_width * wrap : raw.length)
|
96
112
|
truncated = (cell_body_length < raw.length)
|
97
113
|
cell_body = raw[0...cell_body_length]
|
98
114
|
num_subcells = (cell_body_length.to_f / column_width).ceil
|
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.2.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-04-
|
11
|
+
date: 2017-04-22 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -62,6 +62,7 @@ files:
|
|
62
62
|
- ".gitignore"
|
63
63
|
- ".rspec"
|
64
64
|
- ".travis.yml"
|
65
|
+
- CHANGELOG.md
|
65
66
|
- Gemfile
|
66
67
|
- LICENSE.txt
|
67
68
|
- README.md
|