tabulo 0.2.1 → 0.2.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rdoc_options +23 -0
- data/CHANGELOG.md +4 -0
- data/README.md +1 -3
- data/TODO.md +13 -0
- data/lib/tabulo.rb +0 -5
- data/lib/tabulo/column.rb +45 -2
- data/lib/tabulo/row.rb +25 -0
- data/lib/tabulo/table.rb +115 -1
- data/lib/tabulo/version.rb +1 -1
- metadata +4 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 758e3d9a0c11ce15ef23bcfc38c6e1e5dcf1e818
|
4
|
+
data.tar.gz: 5ffb67d92e38efec2b4eec90beea8ea1a047fb3c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: e6ea3bb9c620c39e784949174afe15d028892af72a148159a6cfc1282f07aaf858c265d70fa41ee516c04f55fe1b34e3b21f23b684196adcb488dcf02a6f4335
|
7
|
+
data.tar.gz: f68ca83f4647a7d8f21976ef838248bbbcbd6b4aba21ec6c81087c521e07dc3b8d9f0c4aee59c45c5935107ff4740d72c6c3f70287e94d27d57c3ecb94008305
|
data/.rdoc_options
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
--- !ruby/object:RDoc::Options
|
2
|
+
encoding: UTF-8
|
3
|
+
static_path: []
|
4
|
+
rdoc_include:
|
5
|
+
- "."
|
6
|
+
- "/Users/matthew/Workbench/versioned/linode/tabulo"
|
7
|
+
charset: UTF-8
|
8
|
+
exclude:
|
9
|
+
hyperlink_all: false
|
10
|
+
line_numbers: false
|
11
|
+
locale:
|
12
|
+
locale_dir: locale
|
13
|
+
locale_name:
|
14
|
+
main_page:
|
15
|
+
markup: tomdoc
|
16
|
+
output_decoration: true
|
17
|
+
page_dir:
|
18
|
+
show_hash: false
|
19
|
+
tab_width: 8
|
20
|
+
template_stylesheets: []
|
21
|
+
title:
|
22
|
+
visibility: :protected
|
23
|
+
webcvs:
|
data/CHANGELOG.md
CHANGED
data/README.md
CHANGED
@@ -217,8 +217,6 @@ table = Tabulo::Table.new(1..10, columns: %i(itself even?), header_frequency: 5)
|
|
217
217
|
| 10 | true |
|
218
218
|
```
|
219
219
|
|
220
|
-
TODO: Write rdocs, and link to them here "for more".
|
221
|
-
|
222
220
|
### Using a Table Enumerator
|
223
221
|
|
224
222
|
Because it's an `Enumerable`, a `Tabulo::Table` can also give you an `Enumerator`,
|
@@ -242,7 +240,7 @@ end.to_enum # <-- make an Enumerator
|
|
242
240
|
=> nil
|
243
241
|
```
|
244
242
|
|
245
|
-
Note the
|
243
|
+
Note the use of `.find_each`: we can start printing the table without having to load the entire
|
246
244
|
underlying collection. (The cost of supporting this behaviour is that Tabulo requires us to set
|
247
245
|
column widths up front, rather than adapting to the width of the widest value.)
|
248
246
|
|
data/TODO.md
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# TODO
|
2
|
+
|
3
|
+
* Finish Tomdoc documentation. Link to it at rubydocs from the README. In particular,
|
4
|
+
make it clear which methods are part of the public API and which are internal.
|
5
|
+
* Allow the option of a horizontal rule between each row?
|
6
|
+
* Consider incorporating a linter / static analysis tool into the build.
|
7
|
+
* Raise an ArgumentError for disallowed arguments and options (this is
|
8
|
+
a library!)
|
9
|
+
* Document :formatter option in README.
|
10
|
+
* Allow default column width to be configured at level of Table.
|
11
|
+
* Rename Table#header_row to Table#header to avoid confusion as it does not
|
12
|
+
return a Row.
|
13
|
+
* Column#initialize should have the same signature as Table#add_column.
|
data/lib/tabulo.rb
CHANGED
data/lib/tabulo/column.rb
CHANGED
@@ -4,25 +4,65 @@ module Tabulo
|
|
4
4
|
|
5
5
|
attr_reader :label, :width
|
6
6
|
|
7
|
+
# Public: Initializes and returns a new Column.
|
8
|
+
#
|
9
|
+
# options - A Hash of options:
|
10
|
+
#
|
11
|
+
# :label - A Symbol or String being a unique identifier for this Column.
|
12
|
+
# If the :extractor option is not also provided, then the :label option
|
13
|
+
# should correspond to a method to be called on each item in the table sources
|
14
|
+
# to provide the content for this column.
|
15
|
+
#
|
16
|
+
# :header - The text to be displayed in the header for this Column.
|
17
|
+
#
|
18
|
+
# :align_header - Specifies the alignment of the header text. Possible values are
|
19
|
+
# <tt>:left</tt>, <tt>:center</tt> (the default) and <tt>right</tt>
|
20
|
+
#
|
21
|
+
# :align_body - Specifies how the cell body contents will be aligned. Possible
|
22
|
+
# values are <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>
|
23
|
+
# and <tt>nil</tt>. If <tt>nil</tt> is passed (the default), then
|
24
|
+
# the alignment is determined by the type of the cell value,
|
25
|
+
# with numbers aligned right, booleans center-aligned, and
|
26
|
+
# other values left-aligned. Note header text alignment is configured
|
27
|
+
# separately using the :align_header option.
|
28
|
+
#
|
29
|
+
# :extractor - A callable, e.g. a block or lambda, that will be passed each of the
|
30
|
+
# Table sources to determine the value in each cell of this Column. If
|
31
|
+
# this is not provided, then the Column label will be treated as a
|
32
|
+
# method to be called on each source item to determine each cell's
|
33
|
+
# value.
|
34
|
+
#
|
35
|
+
# :formatter - A callable (e.g. a lambda) that will be passed the calculated
|
36
|
+
# value of each cell to determine how it should be displayed. This
|
37
|
+
# is distinct from the extractor (see below). For
|
38
|
+
# example, if the extractor for this column generates a Date, then
|
39
|
+
# the formatter might format that Date in a particular way.
|
40
|
+
# If no formatter is provided, then <tt>.to_s</tt> will be called on
|
41
|
+
# the extracted value of each cell to determine its displayed
|
42
|
+
# content.
|
43
|
+
#
|
44
|
+
# :width - Specifies the width of the column, not including the single character
|
45
|
+
# of padding. The default is given by Table::DEFAULT_COLUMN_WIDTH.
|
7
46
|
def initialize(options)
|
8
47
|
@label, @header = options[:label], options[:header]
|
9
48
|
@align_header = options[:align_header] || :center
|
10
49
|
@align_body = options[:align_body] || nil
|
11
50
|
@extractor = options[:extractor] || @label.to_proc
|
12
51
|
@formatter = options[:formatter] || :to_s.to_proc
|
13
|
-
|
14
|
-
# TODO Should be able to set these default on a Table-by-Table basis.
|
15
52
|
@width = options[:width] || Table::DEFAULT_COLUMN_WIDTH
|
16
53
|
end
|
17
54
|
|
55
|
+
# Internal
|
18
56
|
def header_cell
|
19
57
|
align_cell_content(@header, @align_header)
|
20
58
|
end
|
21
59
|
|
60
|
+
# Internal
|
22
61
|
def horizontal_rule
|
23
62
|
Table::HORIZONTAL_RULE_CHARACTER * @width
|
24
63
|
end
|
25
64
|
|
65
|
+
# Internal
|
26
66
|
def body_cell(source)
|
27
67
|
cell_datum = body_cell_value(source)
|
28
68
|
formatted_cell_content = @formatter.call(cell_datum)
|
@@ -30,12 +70,14 @@ module Tabulo
|
|
30
70
|
align_cell_content(formatted_cell_content, real_alignment)
|
31
71
|
end
|
32
72
|
|
73
|
+
# Internal
|
33
74
|
def body_cell_value(source)
|
34
75
|
@extractor.call(source)
|
35
76
|
end
|
36
77
|
|
37
78
|
private
|
38
79
|
|
80
|
+
# Internal
|
39
81
|
def align_cell_content(content, real_alignment)
|
40
82
|
padding = [@width - content.length, 0].max
|
41
83
|
left_padding, right_padding =
|
@@ -52,6 +94,7 @@ module Tabulo
|
|
52
94
|
"#{' ' * left_padding}#{content}#{' ' * right_padding}"
|
53
95
|
end
|
54
96
|
|
97
|
+
# Internal
|
55
98
|
def infer_alignment(cell_datum)
|
56
99
|
case cell_datum
|
57
100
|
when Numeric
|
data/lib/tabulo/row.rb
CHANGED
@@ -3,22 +3,47 @@ module Tabulo
|
|
3
3
|
class Row
|
4
4
|
include Enumerable
|
5
5
|
|
6
|
+
# Internal
|
6
7
|
def initialize(table, source, options = { with_header: true })
|
7
8
|
@table = table
|
8
9
|
@source = source
|
9
10
|
@with_header = options[:with_header]
|
10
11
|
end
|
11
12
|
|
13
|
+
# Public: Calls the given block once for each cell in the Row, passing that cell as parameter.
|
14
|
+
# Each "cell" is just the calculated value for its column (pre-formatting) for this Row's
|
15
|
+
# source item.
|
16
|
+
#
|
17
|
+
# Examples
|
18
|
+
#
|
19
|
+
# table = Tabulo::Table.new([1, 10], columns: %i(itself even?))
|
20
|
+
# row = table.first
|
21
|
+
# row.each do |cell|
|
22
|
+
# cell # => 1, => false
|
23
|
+
# cell.class # => Fixnum, => FalseClass
|
24
|
+
# end
|
12
25
|
def each
|
13
26
|
@table.columns.each do |column|
|
14
27
|
yield column.body_cell_value(@source)
|
15
28
|
end
|
16
29
|
end
|
17
30
|
|
31
|
+
# Public: Returns a String being an "ASCII" graphical representation of the Row, including
|
32
|
+
# any column headers that appear just above it in the Table (depending on where this Row is
|
33
|
+
# in the Table and how the Table was configured with respect to header frequency).
|
18
34
|
def to_s
|
19
35
|
@table.formatted_body_row(@source, with_header: @with_header)
|
20
36
|
end
|
21
37
|
|
38
|
+
# Public: Returns a Hash representation of the Row, with Column labels acting
|
39
|
+
# as keys and the calculated cell values (before formatting) providing the values.
|
40
|
+
#
|
41
|
+
# Examples
|
42
|
+
#
|
43
|
+
# table = Tabulo::Table.new([1, 10], columns: %i(itself even?))
|
44
|
+
# row = table.first
|
45
|
+
# row.to_h # -> { :itself => 1, :even? => false }
|
46
|
+
#
|
22
47
|
def to_h
|
23
48
|
@table.columns.map(&:label).zip(to_a).to_h
|
24
49
|
end
|
data/lib/tabulo/table.rb
CHANGED
@@ -1,14 +1,55 @@
|
|
1
1
|
module Tabulo
|
2
2
|
|
3
|
+
# Represents a table primarily intended for "pretty-printing" in a fixed-width font.
|
4
|
+
#
|
5
|
+
# A Table is also an Enumerable, of which each element is a Tabulo::Row.
|
3
6
|
class Table
|
4
7
|
include Enumerable
|
5
8
|
|
6
9
|
DEFAULT_COLUMN_WIDTH = 8
|
10
|
+
|
7
11
|
HORIZONTAL_RULE_CHARACTER = "-"
|
8
12
|
CORNER_CHARACTER = "+"
|
9
13
|
|
10
14
|
attr_reader :columns
|
11
15
|
|
16
|
+
# Public: Initializes and returns a new Table.
|
17
|
+
#
|
18
|
+
# sources - the underlying Enumerable from which the table will derive its data
|
19
|
+
# options - a Hash of options providing for customization of the Table:
|
20
|
+
#
|
21
|
+
# :columns - An Array (default: []) specifying the initial columns (note more can be
|
22
|
+
# added later using #add_column). Each element of the Array
|
23
|
+
# should be either a Symbol or a Column. If it's a Symbol,
|
24
|
+
# it will be used to initialize a Column whose content is
|
25
|
+
# created by calling the corresponding method on each
|
26
|
+
# element of sources.
|
27
|
+
#
|
28
|
+
# :header_frequency - Controls the display of Column headers. Possible values:
|
29
|
+
#
|
30
|
+
# <tt>:start</tt> (default) - show column headers at top of table only
|
31
|
+
#
|
32
|
+
# <tt>nil</tt> - do not show column headers.
|
33
|
+
#
|
34
|
+
# N (a Fixnum > 0) - show column headers at start, then repeated
|
35
|
+
# every N rows.
|
36
|
+
#
|
37
|
+
# :wrap_header_cells_to - Controls wrapping behaviour for header cells if the content
|
38
|
+
# thereof is longer than the Column's fixed width. Possible
|
39
|
+
# values:
|
40
|
+
#
|
41
|
+
# <tt>nil</tt> - wrap content for as many rows as necessary
|
42
|
+
#
|
43
|
+
# N (a Fixnum > 0) - wrap content for up to N rows and
|
44
|
+
# truncate thereafter
|
45
|
+
#
|
46
|
+
# :wrap_body_cells_to - Controls wrapping behaviour for table cells (excluding
|
47
|
+
# headers). Possible values:
|
48
|
+
#
|
49
|
+
# <tt>nil</tt> - wrap content for as many rows as necessary
|
50
|
+
#
|
51
|
+
# N (a `Fixnum` > 0) - wrap content for up to N rows and
|
52
|
+
# truncate thereafter
|
12
53
|
def initialize(sources, options = { })
|
13
54
|
opts = {
|
14
55
|
columns: [],
|
@@ -32,14 +73,68 @@ module Tabulo
|
|
32
73
|
yield self if block_given?
|
33
74
|
end
|
34
75
|
|
35
|
-
|
76
|
+
# Public: Initializes a Column and adds it to the Table.
|
77
|
+
#
|
78
|
+
# label - A Symbol or String being a unique identifier for this column, which by default will
|
79
|
+
# also be used as the column header text (see also the header option). If the
|
80
|
+
# extractor argument is not also provided, then the label argument should correspond to
|
81
|
+
# a method to be called on each item in the table sources to provide the content
|
82
|
+
# for this column.
|
83
|
+
#
|
84
|
+
# options - A Hash of options providing for customization of the column:
|
85
|
+
#
|
86
|
+
# :header - Text to be displayed in the column header. By default the column
|
87
|
+
# label will also be used as its header text.
|
88
|
+
#
|
89
|
+
# :align_header - Specifies how the header text should be aligned. Possible values
|
90
|
+
# are <tt>:left</tt>, <tt>:center</tt> and <tt>:right</tt>.
|
91
|
+
#
|
92
|
+
# :align_body - Specifies how the cell body contents will be aligned. Possible
|
93
|
+
# values are <tt>:left</tt>, <tt>:center</tt>, <tt>:right</tt>
|
94
|
+
# and <tt>nil</tt>. If <tt>nil</tt> is passed (the default), then
|
95
|
+
# the alignment is determined by the type of the cell value,
|
96
|
+
# with numbers aligned right, booleans center-aligned, and
|
97
|
+
# other values left-aligned. Note header text alignment is
|
98
|
+
# configured separately using the :align_header option.
|
99
|
+
#
|
100
|
+
# :width - Specifies the width of the column, not including the single
|
101
|
+
# character of padding. The default is given by
|
102
|
+
# Table::DEFAULT_COLUMN_WIDTH.
|
103
|
+
#
|
104
|
+
# :formatter - A callable (e.g. a lambda) that will be passed the calculated
|
105
|
+
# value of each cell to determine how it should be displayed. This
|
106
|
+
# is distinct from the extractor (see below). For
|
107
|
+
# example, if the extractor for this column generates a Date, then
|
108
|
+
# the formatter might format that Date in a particular way.
|
109
|
+
# If no formatter is provided, then <tt>.to_s</tt> will be called on
|
110
|
+
# the extracted value of each cell to determine its displayed
|
111
|
+
# content.
|
112
|
+
#
|
113
|
+
# extractor - A callable, e.g. a block or lambda, that will be passed each of the Table
|
114
|
+
# sources to determine the value in each cell of this column. If this is not
|
115
|
+
# provided, then the column label will be treated as a method to be called on each
|
116
|
+
# source item to determine each cell's value.
|
117
|
+
#
|
118
|
+
def add_column(label, options = { }, &extractor)
|
36
119
|
@columns << make_column(label, extractor: extractor)
|
37
120
|
end
|
38
121
|
|
122
|
+
# Public: Returns a String being a graphical "ASCII" representation of the Table, suitable for
|
123
|
+
# display in a fixed-width font.
|
39
124
|
def to_s
|
40
125
|
join_lines(map(&:to_s))
|
41
126
|
end
|
42
127
|
|
128
|
+
# Public: Calls the given block once for each Row in the Table, passing that Row as parameter.
|
129
|
+
#
|
130
|
+
# Examples
|
131
|
+
#
|
132
|
+
# table.each do |row|
|
133
|
+
# puts row
|
134
|
+
# end
|
135
|
+
#
|
136
|
+
# Note that when printed, the first row will visually include the headers (assuming these
|
137
|
+
# were not disabled when the Table was initialized).
|
43
138
|
def each
|
44
139
|
@sources.each_with_index do |source, index|
|
45
140
|
include_header =
|
@@ -55,14 +150,28 @@ module Tabulo
|
|
55
150
|
end
|
56
151
|
end
|
57
152
|
|
153
|
+
# Public: Returns a String being an "ASCII" graphical representation of the Table column
|
154
|
+
# headers.
|
58
155
|
def header_row
|
59
156
|
format_row(true, &:header_cell)
|
60
157
|
end
|
61
158
|
|
159
|
+
# Public: Returns a String being an "ASCII" graphical representation of a horizontal
|
160
|
+
# dividing line suitable for printing at any point in the table.
|
161
|
+
#
|
162
|
+
# Examples
|
163
|
+
#
|
164
|
+
# # To print a horizontal divider after every row:
|
165
|
+
# table.each do |row|
|
166
|
+
# puts row
|
167
|
+
# puts table.horizontal_rule
|
168
|
+
# end
|
169
|
+
#
|
62
170
|
def horizontal_rule
|
63
171
|
format_row(false, HORIZONTAL_RULE_CHARACTER, CORNER_CHARACTER, &:horizontal_rule)
|
64
172
|
end
|
65
173
|
|
174
|
+
# Internal
|
66
175
|
def formatted_body_row(source, options = { with_header: false })
|
67
176
|
inner = format_row { |column| column.body_cell(source) }
|
68
177
|
if options[:with_header]
|
@@ -74,11 +183,14 @@ module Tabulo
|
|
74
183
|
|
75
184
|
private
|
76
185
|
|
186
|
+
# Internal
|
77
187
|
def body_row(source, options = { with_header: false })
|
78
188
|
Row.new(self, source, options)
|
79
189
|
end
|
80
190
|
|
191
|
+
# Internal
|
81
192
|
def format_row(header = false, padder = @padding_character, joiner = @joiner)
|
193
|
+
# TODO Tidy this up -- or at least comment it.
|
82
194
|
cell_stacks = @columns.map do |column|
|
83
195
|
raw = yield column
|
84
196
|
wrap = (header ? @wrap_header_cells_to : @wrap_body_cells_to)
|
@@ -107,10 +219,12 @@ module Tabulo
|
|
107
219
|
join_lines(subrows.map { |subrow| "#{joiner}#{subrow.join(joiner)}#{joiner}" })
|
108
220
|
end
|
109
221
|
|
222
|
+
# Internal
|
110
223
|
def join_lines(lines)
|
111
224
|
lines.join($/) # join strings with cross-platform newline
|
112
225
|
end
|
113
226
|
|
227
|
+
# Internal
|
114
228
|
def make_column(item, options = { })
|
115
229
|
case item
|
116
230
|
when Column
|
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.2.
|
4
|
+
version: 0.2.2
|
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-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -88,6 +88,7 @@ extensions: []
|
|
88
88
|
extra_rdoc_files: []
|
89
89
|
files:
|
90
90
|
- ".gitignore"
|
91
|
+
- ".rdoc_options"
|
91
92
|
- ".rspec"
|
92
93
|
- ".travis.yml"
|
93
94
|
- CHANGELOG.md
|
@@ -95,6 +96,7 @@ files:
|
|
95
96
|
- LICENSE.txt
|
96
97
|
- README.md
|
97
98
|
- Rakefile
|
99
|
+
- TODO.md
|
98
100
|
- bin/console
|
99
101
|
- bin/setup
|
100
102
|
- lib/tabulo.rb
|