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 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