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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 1dc99325b75930d06ef7865ccf9cf88149040598
4
- data.tar.gz: 1fbcea2102de94f56ba29d7d763db7b4e164fd10
3
+ metadata.gz: 758e3d9a0c11ce15ef23bcfc38c6e1e5dcf1e818
4
+ data.tar.gz: 5ffb67d92e38efec2b4eec90beea8ea1a047fb3c
5
5
  SHA512:
6
- metadata.gz: b106d3d9c33e003bba7ad38065c54ba25a7f348d58bd20b5508dd512d6fb0a0600f89ba7c4a5f8239736ff2add5a490ae0d7f6bf5952a21e2fc8a80176ea2091
7
- data.tar.gz: f50e7092a449944c3bff02fe8ee5a477bb94b3b5ef80232f12aa1ec4a397ed43e47011b8cc45856d847a33616c00dd0ed6e371092479d48ae95808f0a9838843
6
+ metadata.gz: e6ea3bb9c620c39e784949174afe15d028892af72a148159a6cfc1282f07aaf858c265d70fa41ee516c04f55fe1b34e3b21f23b684196adcb488dcf02a6f4335
7
+ data.tar.gz: f68ca83f4647a7d8f21976ef838248bbbcbd6b4aba21ec6c81087c521e07dc3b8d9f0c4aee59c45c5935107ff4740d72c6c3f70287e94d27d57c3ecb94008305
@@ -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:
@@ -1,5 +1,9 @@
1
1
  # Changelog
2
2
 
3
+ ## v0.2.2
4
+
5
+ * Write documentation
6
+ * Create a TODO file
3
7
 
4
8
  ## v0.2.1
5
9
 
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 used of `.find_each`: we can start printing the table without having to load the entire
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.
@@ -2,8 +2,3 @@ require "tabulo/version"
2
2
  require "tabulo/table"
3
3
  require "tabulo/row"
4
4
  require "tabulo/column"
5
-
6
- # TODO Document the methods.
7
- # TODO Tidy the code.
8
- # TODO Handle newline in output.
9
- # TODO Allow the option of a horizontal rule between rows.
@@ -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
@@ -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
@@ -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
- def add_column(label, options = {}, &extractor)
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
@@ -1,3 +1,3 @@
1
1
  module Tabulo
2
- VERSION = "0.2.1"
2
+ VERSION = "0.2.2"
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.2.1
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-23 00:00:00.000000000 Z
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