tabulo 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1ac51b57ff0b2dc5ce13ea28612183fe2691ed88
4
- data.tar.gz: f004eedf9ec5fa112a289aba3f8411805d88a9fb
3
+ metadata.gz: 02a658d45fe5df2a6b02a39ff1ef8b85b9406a5d
4
+ data.tar.gz: 1edee8575e0098a1d5b383f596ff8ef77e3916a0
5
5
  SHA512:
6
- metadata.gz: 5aa026d70495b3a06a6d364ef2f58bfdb007911f0f43f770dd7fc66bdc6b7c55321234cfe938d1869661d6f5e5526b1b0eea4bf0c31348ccab4a901151c7347a
7
- data.tar.gz: e05b95a3ee28396e71b4771ddaf2f3803715935c391cfce31e1488c8dbdbb3d5c9e5fc641c7fb8a61ffb24ea241979a637f285b24cabf6c49d54fbd24842b8c1
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 for displaying in a terminal or as preformatted text.
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 it one row at a time:
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 as:
51
+ Or install it yourself:
41
52
 
42
53
  $ gem install tabulo
43
54
 
44
- ## Usage
55
+ ## Detailed usage
45
56
 
46
- Require the gem:
57
+ ### Requiring the gem
47
58
 
48
59
  ```ruby
49
60
  require 'tabulo'
50
61
  ```
51
62
 
52
- Instantiate a `Tabulo::Table` by passing it an underlying `Enumerable` and then telling it
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
- # > puts table
66
- # +----------+----------+----------+
67
- # | itself | even? | odd? |
68
- # +----------+----------+----------+
69
- # | 1 | false | true |
70
- # | 2 | true | false |
71
- # | 5 | false | true |
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 blocks or procs that are called on each object. In this case
75
- the first argument provides the column header:
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
- # > puts table
84
- # +----------+----------+
85
- # | N | Doubled |
86
- # +----------+----------+
87
- # | 1 | 2 |
88
- # | 2 | 4 |
89
- # | 5 | 10 |
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
- TODO: Finish this...
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
@@ -3,6 +3,7 @@ require "tabulo/table"
3
3
  require "tabulo/row"
4
4
  require "tabulo/column"
5
5
 
6
+ # TODO Document the methods.
6
7
  # TODO Tidy the code.
7
8
  # TODO Handle newline in output.
8
9
  # TODO Allow the option of a horizontal rule between rows.
data/lib/tabulo/column.rb CHANGED
@@ -2,15 +2,20 @@ module Tabulo
2
2
 
3
3
  class Column
4
4
 
5
- attr_reader :label, :truncate, :width
5
+ attr_reader :label, :width
6
6
 
7
7
  def initialize(options)
8
8
  @label, @header = options[:label], options[:header]
9
- @truncate = options[:truncate]
10
- @align_header, @align_body = options[:align_header], options[:align_body]
11
- @extractor, @formatter = options[:extractor], options[:formatter]
12
- @width = options[:width]
13
- @horizontal_rule_character = options[:horizontal_rule_character]
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
- wrap_cells_to: nil
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
- @wrap_cells_to = opts[:wrap_cells_to]
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
- @columns = []
28
- @default_column_width = 8
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 : @wrap_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 = (truncate ? column_width * wrap : raw.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
@@ -1,3 +1,3 @@
1
1
  module Tabulo
2
- VERSION = "0.1.0"
2
+ VERSION = "0.2.0"
3
3
  end
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.1.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-21 00:00:00.000000000 Z
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