tabulo 0.2.2 → 0.3.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/TODO.md +0 -5
- data/lib/tabulo/column.rb +8 -45
- data/lib/tabulo/row.rb +11 -13
- data/lib/tabulo/table.rb +67 -98
- data/lib/tabulo/version.rb +1 -1
- data/tabulo.gemspec +2 -0
- metadata +29 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9b63d694608052e887a021c0c0e0eb4c9e77512a
|
4
|
+
data.tar.gz: e2781dc44f766676c25fa2148a867e14cf49795f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 33b5af849750ab1ba36c4212b835193d50592f524f7055c3236043f81dcce5b1bffb56c0770651fd9ca5e6c89df935073e4018cbe3029ac1215f7efd6e805e4f
|
7
|
+
data.tar.gz: f9563b27c2a150ea1544e3705c5fbac6c77163e2f23d9187f50310c71ac66a13b2066d04223907707cef698fa3d024112a981edc25245e6f372d2dfc29ab8c2f
|
data/CHANGELOG.md
CHANGED
data/TODO.md
CHANGED
@@ -1,13 +1,8 @@
|
|
1
1
|
# TODO
|
2
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
3
|
* Consider incorporating a linter / static analysis tool into the build.
|
7
4
|
* Raise an ArgumentError for disallowed arguments and options (this is
|
8
5
|
a library!)
|
9
6
|
* Document :formatter option in README.
|
10
7
|
* 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
8
|
* Column#initialize should have the same signature as Table#add_column.
|
data/lib/tabulo/column.rb
CHANGED
@@ -1,48 +1,11 @@
|
|
1
1
|
module Tabulo
|
2
2
|
|
3
|
+
# @!visibility private
|
3
4
|
class Column
|
4
5
|
|
5
6
|
attr_reader :label, :width
|
6
7
|
|
7
|
-
#
|
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.
|
8
|
+
# @!visibility private
|
46
9
|
def initialize(options)
|
47
10
|
@label, @header = options[:label], options[:header]
|
48
11
|
@align_header = options[:align_header] || :center
|
@@ -52,17 +15,17 @@ module Tabulo
|
|
52
15
|
@width = options[:width] || Table::DEFAULT_COLUMN_WIDTH
|
53
16
|
end
|
54
17
|
|
55
|
-
#
|
18
|
+
# @!visibility private
|
56
19
|
def header_cell
|
57
20
|
align_cell_content(@header, @align_header)
|
58
21
|
end
|
59
22
|
|
60
|
-
#
|
23
|
+
# @!visibility private
|
61
24
|
def horizontal_rule
|
62
25
|
Table::HORIZONTAL_RULE_CHARACTER * @width
|
63
26
|
end
|
64
27
|
|
65
|
-
#
|
28
|
+
# @!visibility private
|
66
29
|
def body_cell(source)
|
67
30
|
cell_datum = body_cell_value(source)
|
68
31
|
formatted_cell_content = @formatter.call(cell_datum)
|
@@ -70,14 +33,14 @@ module Tabulo
|
|
70
33
|
align_cell_content(formatted_cell_content, real_alignment)
|
71
34
|
end
|
72
35
|
|
73
|
-
#
|
36
|
+
# @!visibility private
|
74
37
|
def body_cell_value(source)
|
75
38
|
@extractor.call(source)
|
76
39
|
end
|
77
40
|
|
78
41
|
private
|
79
42
|
|
80
|
-
#
|
43
|
+
# @!visibility private
|
81
44
|
def align_cell_content(content, real_alignment)
|
82
45
|
padding = [@width - content.length, 0].max
|
83
46
|
left_padding, right_padding =
|
@@ -94,7 +57,7 @@ module Tabulo
|
|
94
57
|
"#{' ' * left_padding}#{content}#{' ' * right_padding}"
|
95
58
|
end
|
96
59
|
|
97
|
-
#
|
60
|
+
# @!visibility private
|
98
61
|
def infer_alignment(cell_datum)
|
99
62
|
case cell_datum
|
100
63
|
when Numeric
|
data/lib/tabulo/row.rb
CHANGED
@@ -3,19 +3,18 @@ module Tabulo
|
|
3
3
|
class Row
|
4
4
|
include Enumerable
|
5
5
|
|
6
|
-
#
|
6
|
+
# @!visibility private
|
7
7
|
def initialize(table, source, options = { with_header: true })
|
8
8
|
@table = table
|
9
9
|
@source = source
|
10
10
|
@with_header = options[:with_header]
|
11
11
|
end
|
12
12
|
|
13
|
-
#
|
14
|
-
# Each "cell" is just the calculated value for its column (pre-formatting) for this Row's
|
13
|
+
# 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
15
|
# source item.
|
16
16
|
#
|
17
|
-
#
|
18
|
-
#
|
17
|
+
# @example
|
19
18
|
# table = Tabulo::Table.new([1, 10], columns: %i(itself even?))
|
20
19
|
# row = table.first
|
21
20
|
# row.each do |cell|
|
@@ -28,21 +27,20 @@ module Tabulo
|
|
28
27
|
end
|
29
28
|
end
|
30
29
|
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
30
|
+
# @return a String being an "ASCII" graphical representation of the {Row}, including
|
31
|
+
# any column headers that appear just above it in the {Table} (depending on where this Row is
|
32
|
+
# in the {Table} and how the {Table} was configured with respect to header frequency).
|
34
33
|
def to_s
|
35
34
|
@table.formatted_body_row(@source, with_header: @with_header)
|
36
35
|
end
|
37
36
|
|
38
|
-
#
|
39
|
-
#
|
40
|
-
#
|
41
|
-
# Examples
|
37
|
+
# @return a Hash representation of the {Row}, with column labels acting
|
38
|
+
# as keys and the calculated cell values (before formatting) providing the values.
|
42
39
|
#
|
40
|
+
# @example
|
43
41
|
# table = Tabulo::Table.new([1, 10], columns: %i(itself even?))
|
44
42
|
# row = table.first
|
45
|
-
# row.to_h #
|
43
|
+
# row.to_h # => { :itself => 1, :even? => false }
|
46
44
|
#
|
47
45
|
def to_h
|
48
46
|
@table.columns.map(&:label).zip(to_a).to_h
|
data/lib/tabulo/table.rb
CHANGED
@@ -2,7 +2,7 @@ module Tabulo
|
|
2
2
|
|
3
3
|
# Represents a table primarily intended for "pretty-printing" in a fixed-width font.
|
4
4
|
#
|
5
|
-
# A Table is also an Enumerable, of which each element is a
|
5
|
+
# A Table is also an Enumerable, of which each element is a {Row}.
|
6
6
|
class Table
|
7
7
|
include Enumerable
|
8
8
|
|
@@ -11,45 +11,29 @@ module Tabulo
|
|
11
11
|
HORIZONTAL_RULE_CHARACTER = "-"
|
12
12
|
CORNER_CHARACTER = "+"
|
13
13
|
|
14
|
+
# @!visibility private
|
14
15
|
attr_reader :columns
|
15
16
|
|
16
|
-
#
|
17
|
-
#
|
18
|
-
#
|
19
|
-
#
|
20
|
-
#
|
21
|
-
#
|
22
|
-
#
|
23
|
-
#
|
24
|
-
#
|
25
|
-
#
|
26
|
-
#
|
27
|
-
#
|
28
|
-
#
|
29
|
-
#
|
30
|
-
#
|
31
|
-
#
|
32
|
-
#
|
33
|
-
#
|
34
|
-
#
|
35
|
-
#
|
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
|
17
|
+
# @param [Enumerable] sources the underlying Enumerable from which the table will derive its data
|
18
|
+
# @param [Hash] options
|
19
|
+
# @option options [Array[Symbol]] :columns ([]) Specifies the initial columns.
|
20
|
+
# Each element of the Array will be used to create a column whose content is
|
21
|
+
# created by calling the corresponding method on each element of sources. Note
|
22
|
+
# the {#add_column} method is a much more flexible way to set up columns on the table.
|
23
|
+
# @option options [:start, nil, Fixnum] :header_frequency (:start) Controls the display of column headers.
|
24
|
+
# If passed <tt>:start</tt>, headers will be shown at the top of the table only. If passed <tt>nil</tt>,
|
25
|
+
# headers will not be shown. If passed a Fixnum N (> 0), headers will be shown at the top of the table,
|
26
|
+
# then repeated every N rows.
|
27
|
+
# @option options [nil, Fixnum] :wrap_header_cells_to (nil) Controls wrapping behaviour for header
|
28
|
+
# cells if the content thereof is longer than the column's fixed width. If passed <tt>nil</tt> (default),
|
29
|
+
# content will be wrapped for as many rows as required to accommodate it. If passed a Fixnum N (> 0),
|
30
|
+
# content will be wrapped up to N rows and then truncated thereafter.
|
31
|
+
# @option options [nil, Fixnum] :wrap_body_cells_to (nil) Controls wrapping behaviour for table cells (excluding
|
32
|
+
# headers), if their content is longer than the column's fixed width. If passed <tt>nil</tt>, content will
|
33
|
+
# be wrapped for as many rows as required to accommodate it. If passed a Fixnum N (> 0), content will be
|
34
|
+
# wrapped up to N rows and then truncated thereafter.
|
35
|
+
#
|
36
|
+
# @return [Table] a new Table
|
53
37
|
def initialize(sources, options = { })
|
54
38
|
opts = {
|
55
39
|
columns: [],
|
@@ -73,62 +57,50 @@ module Tabulo
|
|
73
57
|
yield self if block_given?
|
74
58
|
end
|
75
59
|
|
76
|
-
#
|
77
|
-
#
|
78
|
-
#
|
79
|
-
#
|
80
|
-
#
|
81
|
-
#
|
82
|
-
#
|
83
|
-
#
|
84
|
-
#
|
85
|
-
#
|
86
|
-
#
|
87
|
-
#
|
88
|
-
#
|
89
|
-
#
|
90
|
-
#
|
91
|
-
#
|
92
|
-
#
|
93
|
-
#
|
94
|
-
#
|
95
|
-
#
|
96
|
-
#
|
97
|
-
#
|
98
|
-
#
|
99
|
-
#
|
100
|
-
#
|
101
|
-
#
|
102
|
-
#
|
103
|
-
#
|
104
|
-
#
|
105
|
-
#
|
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.
|
60
|
+
# Adds a column to the Table.
|
61
|
+
#
|
62
|
+
# @param [Symbol, String] label A unique identifier for this column, which by default will
|
63
|
+
# also be used as the column header text (see also the header option). If the
|
64
|
+
# extractor argument is not also provided, then the label argument should correspond to
|
65
|
+
# a method to be called on each item in the table sources to provide the content
|
66
|
+
# for this column.
|
67
|
+
#
|
68
|
+
# @param [Hash] options
|
69
|
+
# @option options [String] :header Text to be displayed in the column header. By default the column
|
70
|
+
# label will also be used as its header text.
|
71
|
+
# @option options [:left, :center, :right] :align_header (:center) Specifies how the header text
|
72
|
+
# should be aligned.
|
73
|
+
# @option options [:left, :center, :right, nil] :align_body (nil) Specifies how the cell body contents
|
74
|
+
# should be aligned. Possible If <tt>nil</tt> is passed, then the alignment is determined
|
75
|
+
# by the type of the cell value, with numbers aligned right, booleans center-aligned, and
|
76
|
+
# other values left-aligned. Note header text alignment is configured separately using the
|
77
|
+
# :align_header option.
|
78
|
+
# @option options [Fixnum] :width (8) Specifies the width of the
|
79
|
+
# column, excluding padding.
|
80
|
+
# @option options [#to_proc] :formatter (:to_s.to_proc) A lambda or other callable object that
|
81
|
+
# will be passed the calculated value of each cell to determine how it should be displayed. This
|
82
|
+
# is distinct from the extractor (see below). For example, if the extractor for this column
|
83
|
+
# generates a Date, then the formatter might format that Date in a particular way.
|
84
|
+
# If no formatter is provided, then <tt>.to_s</tt> will be called on
|
85
|
+
# the extracted value of each cell to determine its displayed content.
|
86
|
+
# @param [#to_proc] extractor A block or other callable
|
87
|
+
# that will be passed each of the Table sources to determine the value in each cell of this
|
88
|
+
# column. If this is not provided, then the column label will be treated as a method to be
|
89
|
+
# called on each source item to determine each cell's value.
|
117
90
|
#
|
118
91
|
def add_column(label, options = { }, &extractor)
|
119
92
|
@columns << make_column(label, extractor: extractor)
|
120
93
|
end
|
121
94
|
|
122
|
-
#
|
123
|
-
#
|
95
|
+
# @return [String] a graphical "ASCII" representation of the Table, suitable for
|
96
|
+
# display in a fixed-width font.
|
124
97
|
def to_s
|
125
98
|
join_lines(map(&:to_s))
|
126
99
|
end
|
127
100
|
|
128
|
-
#
|
129
|
-
#
|
130
|
-
# Examples
|
101
|
+
# Calls the given block once for each {Row} in the Table, passing that {Row} as parameter.
|
131
102
|
#
|
103
|
+
# @example
|
132
104
|
# table.each do |row|
|
133
105
|
# puts row
|
134
106
|
# end
|
@@ -150,18 +122,15 @@ module Tabulo
|
|
150
122
|
end
|
151
123
|
end
|
152
124
|
|
153
|
-
#
|
154
|
-
|
155
|
-
def header_row
|
125
|
+
# @return [String] an "ASCII" graphical representation of the Table column headers.
|
126
|
+
def formatted_header
|
156
127
|
format_row(true, &:header_cell)
|
157
128
|
end
|
158
129
|
|
159
|
-
#
|
160
|
-
#
|
161
|
-
#
|
162
|
-
# Examples
|
130
|
+
# @return [String] an "ASCII" graphical representation of a horizontal
|
131
|
+
# dividing line suitable for printing at any point in the table.
|
163
132
|
#
|
164
|
-
#
|
133
|
+
# @example Print a horizontal divider after every row:
|
165
134
|
# table.each do |row|
|
166
135
|
# puts row
|
167
136
|
# puts table.horizontal_rule
|
@@ -171,11 +140,11 @@ module Tabulo
|
|
171
140
|
format_row(false, HORIZONTAL_RULE_CHARACTER, CORNER_CHARACTER, &:horizontal_rule)
|
172
141
|
end
|
173
142
|
|
174
|
-
#
|
143
|
+
# @!visibility private
|
175
144
|
def formatted_body_row(source, options = { with_header: false })
|
176
145
|
inner = format_row { |column| column.body_cell(source) }
|
177
146
|
if options[:with_header]
|
178
|
-
join_lines([horizontal_rule,
|
147
|
+
join_lines([horizontal_rule, formatted_header, horizontal_rule, inner])
|
179
148
|
else
|
180
149
|
inner
|
181
150
|
end
|
@@ -183,12 +152,12 @@ module Tabulo
|
|
183
152
|
|
184
153
|
private
|
185
154
|
|
186
|
-
#
|
155
|
+
# @!visibility private
|
187
156
|
def body_row(source, options = { with_header: false })
|
188
157
|
Row.new(self, source, options)
|
189
158
|
end
|
190
159
|
|
191
|
-
#
|
160
|
+
# @!visibility private
|
192
161
|
def format_row(header = false, padder = @padding_character, joiner = @joiner)
|
193
162
|
# TODO Tidy this up -- or at least comment it.
|
194
163
|
cell_stacks = @columns.map do |column|
|
@@ -219,12 +188,12 @@ module Tabulo
|
|
219
188
|
join_lines(subrows.map { |subrow| "#{joiner}#{subrow.join(joiner)}#{joiner}" })
|
220
189
|
end
|
221
190
|
|
222
|
-
#
|
191
|
+
# @!visibility private
|
223
192
|
def join_lines(lines)
|
224
193
|
lines.join($/) # join strings with cross-platform newline
|
225
194
|
end
|
226
195
|
|
227
|
-
#
|
196
|
+
# @!visibility private
|
228
197
|
def make_column(item, options = { })
|
229
198
|
case item
|
230
199
|
when Column
|
data/lib/tabulo/version.rb
CHANGED
data/tabulo.gemspec
CHANGED
@@ -28,4 +28,6 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency "rspec", "~> 3.0"
|
29
29
|
spec.add_development_dependency "simplecov"
|
30
30
|
spec.add_development_dependency "coveralls"
|
31
|
+
spec.add_development_dependency "yard"
|
32
|
+
spec.add_development_dependency "yard-tomdoc"
|
31
33
|
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tabulo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Matthew Harvey
|
@@ -80,6 +80,34 @@ dependencies:
|
|
80
80
|
- - ">="
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: yard
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: yard-tomdoc
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
83
111
|
description: Enumerable ASCII table
|
84
112
|
email:
|
85
113
|
- software@matthewharvey.net
|