fat_table 0.4.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.org CHANGED
@@ -1,5 +1,19 @@
1
- #+OPTIONS: :toc
1
+ #+TITLE: FatTable User Guide
2
+ #+OPTIONS: toc:4
2
3
  #+LATEX_HEADER: \usepackage[margin=0.75in]{geometry}
4
+ #+PROPERTY: header-args:ruby :colnames no :session readme :hlines yes :exports both
5
+ #+PROPERTY: header-args:sh :exports code
6
+ #+STARTUP: inlineimages
7
+
8
+ #+begin_comment
9
+ Notes on producing this README.
10
+
11
+ 1. Result blocks won't be rendered on Github if the #+RESULTS: tag is left
12
+ over the results block, so manually delete them.
13
+
14
+ 2. Make sure that the current version of the gem is geting loaded when running
15
+ the code blocks. rbenv-use-corresponding helps here.
16
+ #+end_comment
3
17
 
4
18
  #+BEGIN_COMMENT
5
19
  This is for markdown output:
@@ -11,6 +25,16 @@ The following is for org.
11
25
 
12
26
  [[https://travis-ci.org/ddoherty03/fat_table.svg?branch=master]]
13
27
 
28
+ * Version
29
+ #+begin_src ruby :wrap EXAMPLE
30
+ require 'fat_table'
31
+ "Current version is: #{FatTable::VERSION}"
32
+ #+end_src
33
+
34
+ #+begin_EXAMPLE
35
+ Current version is: 0.5.3
36
+ #+end_EXAMPLE
37
+
14
38
  * Introduction
15
39
 
16
40
  ~FatTable~ is a gem that treats tables as a data type. It provides methods for
@@ -33,37 +57,141 @@ they makes sense for the output medium and treats other formatting directives as
33
57
  no-ops.
34
58
 
35
59
  ~FatTable~ can be used to perform operations on data that are naturally best
36
- conceived of as tables, which in my experience is quite often. It can also serve
37
- as a foundation for providing reporting functions where flexibility about the
38
- output medium can be useful. Finally ~FatTable~ can be used within Emacs
39
- ~org-mode~ files in code blocks targeting the Ruby language. Org mode tables are
40
- presented to a ruby code block as an array of arrays, so ~FatTable~ can read
41
- them in with its ~.from_aoa~ constructor. A ~FatTable~ table output as an array
42
- of arrays with its ~.to_aoa~ output function will be rendered in an org-mode
43
- buffer as an org-table, ready for processing by other code blocks.
60
+ conceived of as tables, which in my experience is quite often. It can also
61
+ serve as a foundation for providing reporting functions where flexibility
62
+ about the output medium can be useful. Finally ~FatTable~ can be used within
63
+ Emacs ~org-mode~ files in code blocks targeting the Ruby language. Org mode
64
+ tables are presented to a ruby code block as an array of arrays, so ~FatTable~
65
+ can read them in with its ~.from_aoa~ constructor. A ~FatTable~ table output as an
66
+ array of arrays with its ~.to_aoa~ output function will be rendered in an
67
+ org-mode buffer as an org-table, ready for processing by other code blocks.
68
+
69
+ * Table of Contents :toc:noexport:
70
+ - [[#version][Version]]
71
+ - [[#introduction][Introduction]]
72
+ - [[#installation][Installation]]
73
+ - [[#using-in-a-gem][Using in a gem]]
74
+ - [[#manually-install][Manually install]]
75
+ - [[#require][Require]]
76
+ - [[#usage][Usage]]
77
+ - [[#quick-start][Quick Start]]
78
+ - [[#a-word-about-the-examples][A Word About the Examples]]
79
+ - [[#anatomy-of-a-table][Anatomy of a Table]]
80
+ - [[#columns][Columns]]
81
+ - [[#headers][Headers]]
82
+ - [[#groups][Groups]]
83
+ - [[#constructing-tables][Constructing Tables]]
84
+ - [[#empty-tables][Empty Tables]]
85
+ - [[#without-headers][Without Headers]]
86
+ - [[#with-headers][With Headers]]
87
+ - [[#forcing-string-type][Forcing String Type]]
88
+ - [[#designating-tolerant-columns][Designating "Tolerant" Columns]]
89
+ - [[#from-csv-or-org-mode-files-or-strings][From CSV or Org Mode files or strings]]
90
+ - [[#from-arrays-of-arrays][From Arrays of Arrays]]
91
+ - [[#in-ruby-code][In Ruby Code]]
92
+ - [[#in-emacs-org-files][In Emacs Org Files]]
93
+ - [[#from-arrays-of-hashes][From Arrays of Hashes]]
94
+ - [[#from-sql-queries][From SQL queries]]
95
+ - [[#marking-groups-in-input][Marking Groups in Input]]
96
+ - [[#manually][Manually]]
97
+ - [[#when-reading-in-tables][When Reading in Tables]]
98
+ - [[#accessing-parts-of-tables][Accessing Parts of Tables]]
99
+ - [[#rows][Rows]]
100
+ - [[#columns-1][Columns]]
101
+ - [[#cells][Cells]]
102
+ - [[#other-table-attributes][Other table attributes]]
103
+ - [[#operations-on-tables][Operations on Tables]]
104
+ - [[#example-input-tables][Example Input Tables]]
105
+ - [[#select][Select]]
106
+ - [[#selecting-existing-columns-also-of-omni][Selecting Existing Columns (Also of :omni)]]
107
+ - [[#copying-and-renaming-existing-columns][Copying and Renaming Existing Columns]]
108
+ - [[#adding-new-columns][Adding New Columns]]
109
+ - [[#custom-instance-variables-and-hooks][Custom Instance Variables and Hooks]]
110
+ - [[#argument-order-and-boundaries][Argument Order and Boundaries]]
111
+ - [[#where][Where]]
112
+ - [[#order_by][Order_by]]
113
+ - [[#order_with][Order_with]]
114
+ - [[#group_by][Group_by]]
115
+ - [[#join][Join]]
116
+ - [[#join-types][Join Types]]
117
+ - [[#join-expressions][Join Expressions]]
118
+ - [[#join-examples][Join Examples]]
119
+ - [[#inner-joins][Inner Joins]]
120
+ - [[#left-and-right-joins][Left and Right Joins]]
121
+ - [[#full-join][Full Join]]
122
+ - [[#cross-join][Cross Join]]
123
+ - [[#set-operations][Set Operations]]
124
+ - [[#unions][Unions]]
125
+ - [[#intersections][Intersections]]
126
+ - [[#set-differences-with-except][Set Differences with Except]]
127
+ - [[#uniq-aka-distinct][Uniq (aka Distinct)]]
128
+ - [[#remove-groups-with-degroup][Remove groups with degroup!]]
129
+ - [[#formatting-tables][Formatting Tables]]
130
+ - [[#available-formatter-output-targets][Available Formatter Output Targets]]
131
+ - [[#output-media][Output Media]]
132
+ - [[#examples][Examples]]
133
+ - [[#to-text][To Text]]
134
+ - [[#to-org][To Org]]
135
+ - [[#to-term][To Term]]
136
+ - [[#to-latex][To LaTeX]]
137
+ - [[#to-aoa-array-of-arrays][To AoA (Array of Arrays)]]
138
+ - [[#to-aoh-array-of-hashes][To AoH (Array of Hashes)]]
139
+ - [[#formatting-directives][Formatting Directives]]
140
+ - [[#string][String]]
141
+ - [[#numeric][Numeric]]
142
+ - [[#datetime][DateTime]]
143
+ - [[#boolean][Boolean]]
144
+ - [[#nilclass][NilClass]]
145
+ - [[#the-format-and-format_for-methods][The ~format~ and ~format_for~ methods]]
146
+ - [[#table-locations][Table Locations]]
147
+ - [[#location-priority][Location priority]]
148
+ - [[#type-and-column-priority][Type and Column priority]]
149
+ - [[#footers][Footers]]
150
+ - [[#adding-footers][Adding Footers]]
151
+ - [[#aggregators][Aggregators]]
152
+ - [[#footer-objects][Footer objects]]
153
+ - [[#footer-examples][Footer Examples]]
154
+ - [[#built-in-aggregators][Built-in Aggregators]]
155
+ - [[#string-aggregators][String Aggregators]]
156
+ - [[#ruby-objects][Ruby Objects]]
157
+ - [[#lambdas][Lambdas]]
158
+ - [[#invoking-formatters][Invoking Formatters]]
159
+ - [[#by-instantiating-a-formatter][By Instantiating a Formatter]]
160
+ - [[#by-using-fattable-module-level-method-calls][By Using ~FatTable~ module-level method calls]]
161
+ - [[#by-calling-methods-on-table-objects][By Calling Methods on Table Objects]]
162
+ - [[#development][Development]]
163
+ - [[#contributing][Contributing]]
44
164
 
45
165
  * Installation
46
-
47
- ** Installing the gem
48
-
166
+ ** Using in a gem
49
167
  Add this line to your application's Gemfile:
50
-
51
- #+BEGIN_SRC ruby
168
+ #+BEGIN_SRC ruby :exports code
52
169
  gem 'fat_table'
53
170
  #+END_SRC
54
171
 
55
- And then execute:
172
+ Or, something like this in your gemspec file:
173
+ #+begin_SRC ruby :exports code
174
+ gem.add_runtime_dependency 'fat_table'
175
+ #+end_SRC
56
176
 
177
+ And then execute:
57
178
  #+BEGIN_SRC sh
58
179
  $ bundle
59
180
  #+END_SRC
60
181
 
182
+ ** Manually install
61
183
  Or install it yourself as:
62
184
 
63
185
  #+BEGIN_SRC sh
64
186
  $ gem install fat_table
65
187
  #+END_SRC
66
188
 
189
+ ** Require
190
+ Somewhere in your code, make sure that =FatTable= is required:
191
+ #+begin_src ruby :exports code :results silent
192
+ require 'fat_table'
193
+ #+end_src
194
+
67
195
  * Usage
68
196
  ** Quick Start
69
197
 
@@ -71,10 +199,10 @@ Or install it yourself as:
71
199
  operated on in a number of ways. Here's a quick example to illustrate the use of
72
200
  ~FatTable~. See the detailed explanations further on down.
73
201
 
74
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
75
- #+BEGIN_SRC ruby
76
- require 'fat_table'
202
+ Here is a set of data that records some kind of stock activity. It's an array
203
+ of arrays with the first inner array being the headings.
77
204
 
205
+ #+BEGIN_SRC ruby :exports code :results silent
78
206
  data =
79
207
  [['Date', 'Code', 'Raw', 'Shares', 'Price', 'Info', 'Ok'],
80
208
  ['2013-05-29', 'S', 15_700.00, 6601.85, 24.7790, 'ENTITY3', 'F'],
@@ -89,9 +217,17 @@ operated on in a number of ways. Here's a quick example to illustrate the use of
89
217
  ['2013-05-29', 'S', 15_900.00, 6685.95, 24.5802, 'ENTITY3', 'T'],
90
218
  ['2013-05-30', 'S', 6_679.00, 2808.52, 25.0471, 'ENTITY3', 'T'],
91
219
  ['2013-05-23', 'S', 23_054.00, 9694.21, 26.8015, 'ENTITY3', 'F']]
220
+ #+END_SRC
221
+
222
+ Use FatTable to read the data and convert in into a table object. Note that
223
+ the headings within the table are all converted to symbols, lower-cased and
224
+ any spaces replaced with underscores.
92
225
 
93
- # Build the Table and then perform chained operations on it
226
+ Below, we select only those rows having more than 2000 shares, sort by a
227
+ compund key, select all columns but add a column, :ref, for the row number,
228
+ and finally re-order the columns with a final select.
94
229
 
230
+ #+BEGIN_SRC ruby :results silent :exports code
95
231
  table = FatTable.from_aoa(data) \
96
232
  .where('shares > 2000') \
97
233
  .order_by(:date, :code) \
@@ -99,27 +235,51 @@ operated on in a number of ways. Here's a quick example to illustrate the use of
99
235
  :price, :ok, ref: '@row') \
100
236
  .select(:ref, :date, :code,
101
237
  :shares, :price, :ok)
238
+ #+END_SRC
102
239
 
103
- # Convert the table to an ASCII text string
104
-
240
+ You can use the resulting table in other operations, such as performing joins
241
+ or set operations with other tables, etc. The world's your oyster. But
242
+ eventually you will want to present the table in some format, and that is
243
+ where the formatting methods come in. They let you add footers, including
244
+ groups footers, as well as styling the various elements with very simple
245
+ formatting directives that can apply to various "locations" in the table. Any
246
+ formatting directives that are beyond the capabilities of the output medium
247
+ are simply ignored.
248
+
249
+ We can format the table constructed above.
250
+ #+BEGIN_SRC ruby :exports both
105
251
  table.to_text do |fmt|
106
- # Add some table footers
252
+ # Add a group footer at the bottom of each group that results from sorting
253
+ # with the order_by method.
254
+ fmt.gfooter('Avg', shares: :avg, price: :avg)
255
+ # Add some table footers. Averages for the price and shares columns. The
256
+ # avg_footer method applies the avg aggregate to all the named columns with
257
+ # an "Average" label.
107
258
  fmt.avg_footer(:price, :shares)
259
+ # And a second footer that shows the sum for the shares column.
108
260
  fmt.sum_footer(:shares)
109
- # Add a group footer
110
- fmt.gfooter('Avg', shares: :avg, price: :avg)
111
- # Formats for all locations
261
+ # Formats for all locations, :ref column is centered and bold, all numerics
262
+ # are right-aligned, and all booleans are centered and printed with 'Y' or
263
+ # 'N'
112
264
  fmt.format(ref: 'CB', numeric: 'R', boolean: 'CY')
113
- # Formats for different "locations" in the table
265
+ # Formats for different "locations" in the table:
266
+ # The headers are all centered and bold.
114
267
  fmt.format_for(:header, string: 'CB')
268
+ # In the body rows (i.e., not the headers or footers), the code column is
269
+ # centered, shares have grouping commas applied and are rounded to one
270
+ # decimal place, but the price column is rounded to 4 places with no
271
+ # grouping commas.
115
272
  fmt.format_for(:body, code: 'C', shares: ',0.1', price: '0.4', )
273
+ # But the price column in the first row of the body (:bfirst location) will
274
+ # also be formatted with a currency symbol.
116
275
  fmt.format_for(:bfirst, price: '$0.4', )
117
- fmt.format_for(:footer, shares: 'B,0.1', price: '$B0.4', )
276
+ # In the footers, apply the same rounding rules, but make the results bold.
118
277
  fmt.format_for(:gfooter, shares: 'B,0.1', price: 'B0.4', )
278
+ fmt.format_for(:footer, shares: 'B,0.1', price: '$B0.4', )
119
279
  end
120
280
  #+END_SRC
121
281
 
122
- #+BEGIN_EXAMPLE
282
+ #+begin_example
123
283
  +=========+============+======+=============+==========+====+
124
284
  | Ref | Date | Code | Shares | Price | Ok |
125
285
  +---------+------------+------+-------------+----------+----+
@@ -154,23 +314,64 @@ operated on in a number of ways. Here's a quick example to illustrate the use of
154
314
  +---------+------------+------+-------------+----------+----+
155
315
  | Total | | | 1,020,119.1 | | |
156
316
  +=========+============+======+=============+==========+====+
157
- #+END_EXAMPLE
317
+ #+end_example
158
318
 
159
- ** A Word About the Examples
319
+ For the text format above, we were wasting our breath specifying bold styling
320
+ since there is no way to make that happen in plain ASCII text. But with
321
+ LaTeX, bold is doable. The output of the following code block is being
322
+ written to a file =examples/quicktable.tex= which is then =\included=-ed in a
323
+ simple wrapper file, =examples/quick.tex= so it can be compiled by LaTeX.
324
+
325
+ #+BEGIN_SRC ruby :results file :file "examples/quicktable.tex"
326
+ table.to_latex do |fmt|
327
+ fmt.gfooter('Avg', shares: :avg, price: :avg)
328
+ fmt.avg_footer(:price, :shares)
329
+ fmt.sum_footer(:shares)
330
+ fmt.format(ref: 'CB', numeric: 'R', boolean: 'CY')
331
+ fmt.format_for(:header, string: 'CB')
332
+ fmt.format_for(:body, code: 'C', shares: ',0.1c[blue.lightgray]', price: '0.4', )
333
+ fmt.format_for(:bfirst, price: '$0.4', )
334
+ fmt.format_for(:gfooter, shares: 'B,0.1', price: 'B0.4', )
335
+ fmt.format_for(:footer, shares: 'B,0.1', price: '$B0.4', )
336
+ end
337
+ #+END_SRC
338
+
339
+ #+begin_EXAMPLE
340
+ [[file:examples/quicktable.tex]]
341
+ #+end_EXAMPLE
342
+
343
+ These commands run pdflatex on the result twice to get the table aligned
344
+ properly.
345
+ #+begin_src sh :results silent
346
+ cd examples
347
+ pdflatex quick.tex
348
+ pdflatex quick.tex
349
+ #+end_src
350
+
351
+ And we convert the =PDF= into a smaller image for display:
352
+ #+begin_src sh :results verbatim
353
+ cd examples
354
+ pdftoppm -png quick.pdf >quick.png
355
+ convert quick.png -resize 600x800 quick_small.png
356
+ #+end_src
357
+
358
+ [[file:examples/quick_small.png]]
160
359
 
360
+ ** A Word About the Examples
161
361
  When you install the ~fat_table~ gem, you have access to a program ~ft_console~,
162
362
  which opens a ~pry~ session with ~fat_table~ loaded and the tables used in the
163
363
  examples in this ~README~ defined as instance variables so you can experiment
164
364
  with them. Because they are defined as instance variables, you have to write
165
- ~tab1~ as ~@tab1~ in ~ft_console~, but otherwise the examples should work as
166
- shown in this ~README~.
365
+ ~tab1~ as ~@tab1~ in ~ft_console~, but otherwise the examples should work as shown
366
+ in this ~README~.
167
367
 
168
- The examples in this ~README~ file are executed as code blocks within the
169
- ~README.org~ file, so they typically end with a call to ~.to_aoa~. That causes
170
- the table to be inserted into the file and formatted as a table. With
171
- ~ft_console~, you should instead display your tables with ~.to_text~ or
172
- ~.to_term~. These will return a string that you can print to the terminal with
173
- ~puts~.
368
+ The examples in this ~README~ file are executed in Emacs org-mode as code
369
+ blocks within the ~README.org~ file, so they typically end with a call to
370
+ ~.to_aoa~. That causes Emacs to insert the "Array of Array" ruby data
371
+ structure into the file and format it as a table, which is the convention for
372
+ Emacs org-mode. With ~ft_console~, you should instead display your tables with
373
+ ~.to_text~ or ~.to_term~. These will return a string that you can print to the
374
+ terminal with ~puts~.
174
375
 
175
376
  To read in the table used in the Quick Start section above, you might do the
176
377
  following:
@@ -230,7 +431,6 @@ directives.
230
431
 
231
432
  ** Anatomy of a Table
232
433
  *** Columns
233
-
234
434
  ~FatTable::Table~ objects consist of an array of ~FatTable::Column~ objects.
235
435
  Each ~Column~ has a header, a type, and an array of items, all of the given type
236
436
  or nil. There are only five permissible types for a ~Column~:
@@ -252,39 +452,38 @@ Items of input must be either one of the permissible ruby objects or strings. If
252
452
  they are strings, ~FatTable~ attempts to parse them as one of the permissible
253
453
  types as follows:
254
454
 
255
- - Boolean :: the strings, ~'t'~, ~'true'~, ~'yes'~, or ~'y'~, regardless of
256
- case, are interpreted as ~TrueClass~ and the strings, ~'f'~, ~'false'~,
257
- ~'no'~, or ~'n'~, regardless of case, are interpreted as ~FalseClass~, in
455
+ - Boolean :: The strings, ~t~, ~true~, ~yes~, or ~y~, regardless of
456
+ case, are interpreted as ~TrueClass~ and the strings, ~f~, ~false~,
457
+ ~no~, or ~n~, regardless of case, are interpreted as ~FalseClass~, in
258
458
  either case resulting in a Boolean column. Empty strings in a column
259
459
  already having a Boolean type are converted to ~nil~.
260
- - DateTime :: strings that contain patterns of ~'yyyy-mm-dd'~ or ~'yyyy/mm/dd'~
261
- or ~'mm-dd-yyy'~ or ~'mm/dd/yyyy'~ or any of the foregoing with an added
262
- ~'Thh:mm:ss'~ or ~'Thh:mm'~ will be interpreted as a ~DateTime~ or a ~Date~
460
+ - DateTime :: Strings that contain patterns of ~yyyy-mm-dd~ or ~yyyy/mm/dd~
461
+ or ~mm-dd-yyy~ or ~mm/dd/yyyy~ or any of the foregoing with an added
462
+ ~Thh:mm:ss~ or ~Thh:mm~ will be interpreted as a ~DateTime~ or a ~Date~
263
463
  (if there are no sub-day time components present). The number of digits in
264
464
  the month and day can be one or two, but the year component must be four
265
465
  digits. Any time components are valid if they can be properly interpreted
266
466
  by ~DateTime.parse~. Org mode timestamps (any of the foregoing surrounded
267
- by square '~[]~' or pointy '~<>~' brackets), active or inactive, are valid
467
+ by square ~[]~ or pointy ~<>~ brackets), active or inactive, are valid
268
468
  input strings for ~DateTime~ columns. Empty strings in a column already
269
469
  having the ~DateTime~ type are converted to ~nil~.
270
- - Numeric :: all commas ~','~, underscores, ~'_'~, and ~'$'~ dollar signs (or
271
- other currency symbol as set by ~FatTable.currency_symbol~ are removed from
272
- the string and if the remaining string can be interpreted as a ~Numeric~,
273
- it will be. It is interpreted as an ~Integer~ if there are no decimal
274
- places in the remaining string, as a ~Rational~ if the string has the form
275
- '~<number>:<number>~' or '~<number>/<number>~', or as a ~BigDecimal~ if
276
- there is a decimal point in the remaining string. Empty strings in a column
277
- already having the Numeric type are converted to nil.
278
- - String :: if all else fails, ~FatTable~ applies ~#to_s~ to the input value
470
+ - Numeric :: All commas (~,~) underscores (~_~) and (~$~) dollar signs (or
471
+ other currency symbol as set by ~FatTable.currency_symbol~ are removed from
472
+ the string and if the remaining string can be interpreted as a ~Numeric~, it
473
+ will be. It is interpreted as an ~Integer~ if there are no decimal places in
474
+ the remaining string, as a ~Rational~ if the string has the form
475
+ ~<number>:<number>~ or ~<number>/<number>~, or as a ~BigDecimal~ if there is
476
+ a decimal point in the remaining string. Empty strings in a column already
477
+ having the Numeric type are converted to nil.
478
+ - String :: If all else fails, ~FatTable~ applies ~#to_s~ to the input value
279
479
  and, treats it as an item of type ~String~. Empty strings in a column
280
480
  already having the ~String~ type are kept as empty strings.
281
- - NilClass :: until the input contains a non-blank string that can be parsed as
481
+ - NilClass :: Until the input contains a non-blank string that can be parsed as
282
482
  one of the other types, it has this type, meaning that the type is still
283
483
  open. A column comprised completely of blank strings or ~nils~ will retain
284
484
  the ~NilClass~ type.
285
485
 
286
486
  *** Headers
287
-
288
487
  Headers for the columns are formed from the input. No two columns in a table can
289
488
  have the same header. Headers in the input are converted to symbols by
290
489
 
@@ -293,33 +492,36 @@ have the same header. Headers in the input are converted to symbols by
293
492
  - removing any characters that are not letters, numbers, or underscores, and
294
493
  - lowercasing all remaining letters
295
494
 
296
- Thus, a header of ~'Date'~ becomes ~:date~, a header of ~'Id Number'~ becomes,
495
+ Thus, a header of ~Date~ becomes ~:date~, a header of ~Id Number~ becomes,
297
496
  ~:id_number~, etc. When referring to a column in code, you must use the symbol
298
497
  form of the header.
299
498
 
300
499
  If no sensible headers can be discerned from the input, headers of the form
301
500
  ~:col_1~, ~:col_2~, etc., are synthesized.
302
501
 
303
- *** Groups
502
+ You should avoid the use of the column names ~:omni~ and ~:sort_key~ because
503
+ they have special meanings in the ~select~ and ~order_with~ commands,
504
+ respectively.
304
505
 
305
- The rows of a ~FatTable~ table can be sub-divided into groups, either from
306
- markers in the input or as a result of certain operations. There is only one
307
- level of grouping, so ~FatTable~ has no concept of sub-groups. Groups can be
308
- shown on output with rules or "hlines" that underline the last row in each
309
- group, and you can decorate the output with group footers that summarize the
310
- columns in each group.
506
+ *** Groups
507
+ The rows of a ~FatTable~ table can be divided into groups, either from markers
508
+ in the input or as a result of certain operations. There is only one level of
509
+ grouping, so ~FatTable~ has no concept of sub-groups. Groups can be shown on
510
+ output with rules or "hlines" that underline the last row in each group, and
511
+ you can decorate the output with group footers that summarize the rows in
512
+ each group.
311
513
 
312
514
  ** Constructing Tables
313
515
  *** Empty Tables
516
+ **** Without Headers
517
+ You can create an empty table with ~FatTable::Table.new~ or, the shorter form,
518
+ ~FatTable.new~, and then add rows with the ~<<~ operator and a Hash. The keys
519
+ in the added rows determine the names of the headers:
314
520
 
315
- You can create an empty table with ~FatTable.new~, and then add rows with the
316
- ~<<~ operator and a Hash:
317
-
318
- #+BEGIN_SRC ruby
521
+ #+BEGIN_SRC ruby :results silent
319
522
  tab = FatTable.new
320
- tab << { a: 1, b: 2, c: "<2017-01-21>', d: 'f', e: '' }
523
+ tab << { a: 1, b: 2, c: "<2017-01-21>", d: 'f', e: '' }
321
524
  tab << { a: 3.14, b: 2.17, c: '[2016-01-21 Thu]', d: 'Y', e: nil }
322
- tab.to_aoa
323
525
  #+END_SRC
324
526
 
325
527
  After this, the table will have column headers ~:a~, ~:b~, ~:c~, ~:d~, and ~:e~.
@@ -328,14 +530,187 @@ Column, ~:a~ and ~:b~ will have type Numeric, column ~:c~ will have type
328
530
  have an open type. Notice that dates in the input can be wrapped in brackets as
329
531
  in org-mode time stamps.
330
532
 
533
+ #+BEGIN_SRC ruby :wrap EXAMPLE
534
+ tab.to_text
535
+ #+END_SRC
536
+
537
+ #+begin_EXAMPLE
538
+ +======+======+============+===+===+
539
+ | A | B | C | D | E |
540
+ +------+------+------------+---+---+
541
+ | 1 | 2 | 2017-01-21 | F | |
542
+ | 3.14 | 2.17 | 2016-01-21 | T | |
543
+ +======+======+============+===+===+
544
+ #+end_EXAMPLE
545
+
546
+ You can continue to add rows to the table:
547
+ #+BEGIN_SRC ruby :results silent
548
+ tab << { 'F' => '335:113', a: Rational(3, 5) }
549
+ #+END_SRC
550
+
551
+ This last ~<<~ operation adds a new column headed ~:f~ to the table and makes
552
+ the value of =:f= in all prior rows ~nil~. Also, the values for the new row
553
+ for which no key was give are assigned ~nil~ as well:
554
+
555
+ #+BEGIN_SRC ruby
556
+ tab.to_text
557
+ #+END_SRC
558
+
559
+ #+begin_EXAMPLE
560
+ +======+======+============+===+===+=========+
561
+ | A | B | C | D | E | F |
562
+ +------+------+------------+---+---+---------+
563
+ | 1 | 2 | 2017-01-21 | F | | |
564
+ | 3.14 | 2.17 | 2016-01-21 | T | | |
565
+ +------+------+------------+---+---+---------+
566
+ | 3/5 | | | | | 335/113 |
567
+ +======+======+============+===+===+=========+
568
+ #+end_EXAMPLE
569
+
570
+ **** With Headers
571
+ Alternatively, you can specify the headers at the outset, in which case,
572
+ headers in added rows that do not match any of the initial headers cause new
573
+ columns to be created:
574
+
575
+ #+BEGIN_SRC ruby :wrap EXAMPLE :results raw
576
+ require 'fat_table'
577
+ tab = FatTable.new(:a, 'b', 'C', :d)
578
+ tab.headers
579
+ #+END_SRC
580
+
581
+ #+begin_EXAMPLE
582
+ [:a, :b, :c, :d]
583
+ #+end_EXAMPLE
584
+
585
+ #+begin_src ruby :wrap EXAMPLE
586
+ tab << { a: 1, b: 2, c: "<2017-01-21>", d: 'f', e: '' }
587
+ tab << { a: 3.14, b: 2.17, c: '[2016-01-21 Thu]', d: 'Y', e: nil }
588
+ tab.to_text
589
+ #+end_src
590
+
591
+ #+begin_EXAMPLE
592
+ +======+======+============+===+===+
593
+ | A | B | C | D | E |
594
+ +------+------+------------+---+---+
595
+ | 1 | 2 | 2017-01-21 | F | |
596
+ | 3.14 | 2.17 | 2016-01-21 | T | |
597
+ +------+------+------------+---+---+
598
+ | 1 | 2 | 2017-01-21 | F | |
599
+ | 3.14 | 2.17 | 2016-01-21 | T | |
600
+ +======+======+============+===+===+
601
+ #+end_EXAMPLE
602
+
603
+ **** Forcing String Type
604
+ Occasionally, ~FatTable~'s automatic type detection can get in the way and you
605
+ just want it to treat one or more columns as Strings regardless of their
606
+ appearance. Think, for example, of zip codes. At any time after creating a
607
+ table, you can have it force the String type on any number of columns with the
608
+ ~force_string!~ method. When you do so, all exisiting items in the column are
609
+ converted to strings with the #to_s method.
610
+
611
+ #+begin_src ruby :wrap EXAMPLE
612
+ tab = FatTable.new(:a, 'b', 'C', :d, :zip)
613
+ tab << { a: 1, b: 2, c: "<2017-01-21>", d: 'f', e: '', zip: 18552 }
614
+ tab << { a: 3.14, b: 2.17, c: '[2016-01-21 Thu]', d: 'Y', e: nil }
615
+ tab.force_string!(:zip, :c)
616
+ tab << { zip: '01879' }
617
+ tab << { zip: '66210' }
618
+ tab << { zip: '90210' }
619
+ tab.to_text
620
+ #+end_src
621
+
622
+ #+begin_EXAMPLE
623
+ +======+======+============+===+=======+===+
624
+ | A | B | C | D | Zip | E |
625
+ +------+------+------------+---+-------+---+
626
+ | 1 | 2 | 2017-01-21 | F | 18552 | |
627
+ | 3.14 | 2.17 | 2016-01-21 | T | | |
628
+ | | | | | 01879 | |
629
+ | | | | | 66210 | |
630
+ | | | | | 90210 | |
631
+ +======+======+============+===+=======+===+
632
+ #+end_EXAMPLE
633
+
634
+ **** Designating "Tolerant" Columns
635
+ Related to the problem just discussed is the problem of reading files in from
636
+ the wild where a column may get typed as, say Numeric, but then contain
637
+ something that can't be parsed as a Numeric. ~FatTable~ raises an exception
638
+ is such cases, and that may be what you want if you can control the input.
639
+ But, especially when you cannot do so, it can be helpful to designate one or
640
+ more columns as "tolerant." This means that when a conversion problem occurs,
641
+ the column is forced to String type instead of throwing an exception, and the
642
+ table can continue to be read.
643
+
644
+ All of the table construction methods, allow a keyword parameter,
645
+ ~tolerant_columns~, where you can designate what columns should be convert to
646
+ String type when conversion to the auto-typed column type is not possible.
647
+ The parameter should be an array of headers, in either string or symbol form,
648
+ for which this behavior is desired. In addition, it can be set to the special
649
+ string '*' or symbol ~:*~ to indicate that all the columns should be made
650
+ tolerant.
651
+
652
+ #+begin_src ruby :wrap EXAMPLE
653
+ require 'fat_table'
654
+ tab = FatTable.new(:a, 'b', 'C', :d, :zip, tolerant_columns: [:zip])
655
+ tab << { a: 1, b: 2, c: "<2017-01-21>", d: 'f', e: '', zip: 18552 }
656
+ tab << { a: 3.14, b: 2.17, c: '[2016-01-21 Thu]', d: 'Y', e: nil }
657
+ tab << { zip: '01879--7884' }
658
+ tab << { zip: '66210' }
659
+ tab << { zip: '90210' }
660
+ tab.to_text
661
+ #+end_src
662
+
663
+ #+RESULTS:
664
+ #+begin_EXAMPLE
665
+ +======+======+============+===+=============+===+
666
+ | A | B | C | D | Zip | E |
667
+ +------+------+------------+---+-------------+---+
668
+ | 1 | 2 | 2017-01-21 | F | 18552 | |
669
+ | 3.14 | 2.17 | 2016-01-21 | T | | |
670
+ | | | | | 01879--7884 | |
671
+ | | | | | 66210 | |
672
+ | | | | | 90210 | |
673
+ +======+======+============+===+=============+===+
674
+ #+end_EXAMPLE
675
+
676
+ Another way to designate a column as tolerant is to end a column you want to
677
+ designate as tolerant with a ~!~. The ~!~ will be stripped from the header,
678
+ but it will be marked as tolerant.
679
+ #+begin_src ruby :wrap EXAMPLE
680
+ require 'fat_table'
681
+ tab = FatTable.new(:a, 'b!', 'C', :d, :zip!)
682
+ tab << { a: 1, b: 2, c: "<2017-01-21>", d: 'f', e: '', zip: 18552 }
683
+ tab << { a: 3.14, b: 2.17, c: '[2016-01-21 Thu]', d: 'Y', e: nil }
684
+ tab << { zip: '01879--7884' }
685
+ tab << { zip: '66210', b: 'Not a Number' }
686
+ tab << { zip: '90210' }
687
+ tab.to_text
688
+ #+end_src
689
+
690
+ #+RESULTS:
691
+ #+begin_EXAMPLE
692
+ +======+==============+============+===+=============+===+
693
+ | A | B | C | D | Zip | E |
694
+ +------+--------------+------------+---+-------------+---+
695
+ | 1 | 2 | 2017-01-21 | F | 18552 | |
696
+ | 3.14 | 2.17 | 2016-01-21 | T | | |
697
+ | | | | | 01879--7884 | |
698
+ | | Not a Number | | | 66210 | |
699
+ | | | | | 90210 | |
700
+ +======+==============+============+===+=============+===+
701
+ #+end_EXAMPLE
702
+
331
703
  *** From CSV or Org Mode files or strings
704
+ Tables can also be read from ~.csv~ files or files containing ~org-mode~
705
+ tables. Remember that you can make any column tolerant with a
706
+ ~tolerant_columns:~ keyword argument or make them all tolerant by designating
707
+ the pseudo-column ~:*~ as tolerant.
332
708
 
333
- Tables can also be read from ~.csv~ files or files containing ~org-mode~ tables.
334
709
  In the case of org-mode files, ~FatTable~ skips through the file until it finds
335
710
  a line that look like a table, that is, it begins with any number of spaces
336
711
  followed by ~|-~. Only the first table in an ~.org~ file is read.
337
712
 
338
- For both ~.csv~ and ~.org~ files, the first row in the tables is taken as the
713
+ For both ~.csv~ and ~.org~ files, the first row in the table is taken as the
339
714
  header row, and the headers are converted to symbols as described above.
340
715
 
341
716
  #+BEGIN_SRC ruby
@@ -385,9 +760,11 @@ header row, and the headers are converted to symbols as described above.
385
760
  #+END_SRC
386
761
 
387
762
  *** From Arrays of Arrays
388
-
389
- You can also initialize a table directly from ruby data structures. You can, for
390
- example, build a table from an array of arrays:
763
+ **** In Ruby Code
764
+ You can also initialize a table directly from ruby data structures. You can,
765
+ for example, build a table from an array of arrays. Remember that you can
766
+ make any column tolerant with a ~tolerant_columns:~ keyword argument or make
767
+ them all tolerant by designating the pseudo-column ~:*~ as tolerant.
391
768
 
392
769
  #+BEGIN_SRC ruby
393
770
  aoa = [
@@ -411,6 +788,7 @@ example, build a table from an array of arrays:
411
788
  Notice that the values can either be ruby objects, such as the Integer ~85_000~,
412
789
  or strings that can be parsed into one of the permissible column types.
413
790
 
791
+ **** In Emacs Org Files
414
792
  This method of building a table, ~.from_aoa~, is particularly useful in dealing
415
793
  with Emacs org-mode code blocks. Tables in org-mode are passed to code blocks as
416
794
  arrays of arrays. Likewise, a result of a code block in the form of an array of
@@ -480,15 +858,17 @@ This example illustrates several things:
480
858
 
481
859
  A second ruby data structure that can be used to initialize a ~FatTable~ table
482
860
  is an array of ruby Hashes. Each hash represents a row of the table, and the
483
- headers of the table are taken from the keys of the hashes. Accordingly, all the
484
- hashes must have the same keys.
861
+ headers of the table are taken from the keys of the hashes. Accordingly, all
862
+ the hashes must have the same keys. Remember that you can make any column
863
+ tolerant with a ~tolerant_columns:~ keyword argument or make them all tolerant
864
+ by designating the pseudo-column ~:*~ as tolerant.
485
865
 
486
866
  This same method can in fact take an array of any objects that can be converted
487
867
  to a Hash with the ~#to_h~ method, so you can use an array of your own objects
488
868
  to initialize a table, provided that you define a suitable ~#to_h~ method for
489
869
  the objects' class.
490
870
 
491
- #+BEGIN_SRC ruby
871
+ #+BEGIN_SRC ruby :results silent
492
872
  aoh = [
493
873
  { ref: 'T001', date: '2016-11-01', code: 'P', price: '7.7000', shares: 100 },
494
874
  { ref: 'T002', date: '2016-11-01', code: 'P', price: 7.7500, shares: 200 },
@@ -514,7 +894,6 @@ Notice, again, that the values can either be ruby objects, such as ~Date.today~,
514
894
  or strings that can be parsed into one of the permissible column types.
515
895
 
516
896
  *** From SQL queries
517
-
518
897
  Another way to initialize a ~FatTable~ table is with the results of a SQL
519
898
  query. Before you can connect to a database, you need to make sure that the required
520
899
  adapter for your database is installed. ~FatTable~ uses the ~sequel~ gem
@@ -529,15 +908,30 @@ You must first set the database parameters to be used for the queries.
529
908
 
530
909
  #+BEGIN_SRC ruby
531
910
  # This automatically requires sequel.
532
- require 'fat_table'
533
- FatTable.connect(adapter: 'postgres',
534
- database: 'XXX_development',
535
- user: 'ken',
536
- password: 'imsecret',
537
- host: 'db.lan')
538
- tab = FatTable.from_sql('select * from trades;')
911
+ FatTable.connect(adapter: 'sqlite',
912
+ database: 'examples/trades.db')
913
+ tab = FatTable.from_sql('select * from trans;').to_text
539
914
  #+END_SRC
540
915
 
916
+ #+begin_example
917
+ +============+======+==========+==========+=========+=========+====+
918
+ | Date | Code | Raw | Shares | Price | Info | Ok |
919
+ +------------+------+----------+----------+---------+---------+----+
920
+ | 2013-05-29 | S | 15700.0 | 6601.85 | 24.779 | ENTITY3 | F |
921
+ | 2013-05-02 | P | 118186.4 | 118186.4 | 11.85 | ENTITY1 | T |
922
+ | 2013-05-20 | S | 12000.0 | 5046.0 | 28.2804 | ENTITY3 | F |
923
+ | 2013-05-23 | S | 8000.0 | 3364.0 | 27.1083 | ENTITY3 | T |
924
+ | 2013-05-23 | S | 39906.0 | 16780.47 | 25.1749 | ENTITY3 | T |
925
+ | 2013-05-20 | S | 85000.0 | 35742.5 | 28.3224 | ENTITY3 | T |
926
+ | 2013-05-02 | P | 795546.2 | 795546.2 | 1.185 | ENTITY1 | T |
927
+ | 2013-05-29 | S | 13459.0 | 5659.51 | 24.7464 | ENTITY3 | T |
928
+ | 2013-05-20 | S | 33302.0 | 14003.49 | 28.6383 | ENTITY3 | T |
929
+ | 2013-05-29 | S | 15900.0 | 6685.95 | 24.5802 | ENTITY3 | T |
930
+ | 2013-05-30 | S | 6679.0 | 2808.52 | 25.0471 | ENTITY3 | T |
931
+ | 2013-05-23 | S | 23054.0 | 9694.21 | 26.8015 | ENTITY3 | F |
932
+ +============+======+==========+==========+=========+=========+====+
933
+ #+end_example
934
+
541
935
  The arguments to ~connect~ are simply passed on to ~sequel~'s connect method, so
542
936
  any set of arguments that work for it should work for ~connect~. Alternatively,
543
937
  you can build the ~Sequel~ connection directly with ~Sequel.connect~ or with
@@ -545,7 +939,6 @@ adapter-specific ~Sequel~ connection methods and let ~FatTable~ know to use that
545
939
  connection:
546
940
 
547
941
  #+BEGIN_SRC ruby
548
- require 'fat_table'
549
942
  FatTable.db = Sequel.connect('postgres://user:password@localhost/dbname')
550
943
  FatTable.db = Sequel.ado(conn_string: 'Provider=Microsoft.ACE.OLEDB.12.0;Data Source=drive:\path\filename.accdb')
551
944
  #+END_SRC
@@ -557,7 +950,18 @@ The ~.connect~ function need only be called once, and the database handle it
557
950
  creates will be used for all subsequent ~.from_sql~ calls until ~.connect~ is
558
951
  called again.
559
952
 
953
+ Remember that you can make any column tolerant with a ~tolerant_columns:~
954
+ keyword argument or make them all tolerant by designating the pseudo-column
955
+ ~:*~ as tolerant.
956
+
560
957
  *** Marking Groups in Input
958
+ **** Manually
959
+ At any point, you can add a boundary to a table by invokong the
960
+ ~mark_boundary~ method. Without an argument, it adds the boundary to the end
961
+ of the table; with a numeric argument, ~n~, it adds the boundary after row
962
+ ~n~.
963
+
964
+ **** When Reading in Tables
561
965
 
562
966
  ~FatTable~ tables has a concept of "groups" of rows that play a role in many of
563
967
  the methods for operating on them as explained [[Groups][below]].
@@ -577,13 +981,12 @@ the form ~:col_1~, ~:col_2~, ... ~:col_n~.
577
981
  In org mode table text passed to ~.from_org_file~ and ~.from_org_string~, you
578
982
  /must/ mark the header row by following it with an hrule and you /may/ mark
579
983
  group boundaries with an hrule. In org mode tables, hlines are table rows
580
- beginning with something like '~|---~'. The ~.from_org_...~ functions always
984
+ beginning with something like ~|---~. The ~.from_org_...~ functions always
581
985
  recognizes hlines in the input, so it takes no ~hlines:~ keyword parameter.
582
986
 
583
987
  ** Accessing Parts of Tables
584
988
 
585
989
  *** Rows
586
-
587
990
  A ~FatTable~ table is an Enumerable, yielding each row of the table as a Hash
588
991
  keyed on the header symbols. The method ~Table#rows~ returns an Array of the
589
992
  rows as Hashes as well.
@@ -594,15 +997,13 @@ data row of the table, while ~tab[0]~ returns the first row and tab[-1] returns
594
997
  the last row.
595
998
 
596
999
  *** Columns
597
-
598
1000
  If the index provided to ~[]~ is a string or a symbol, it returns an Array of
599
1001
  the items of the column with that header. Thus, ~tab[:ref]~ returns an Array of
600
1002
  all the items of the table's ~:ref~ column.
601
1003
 
602
1004
  *** Cells
603
-
604
- The two forms of indexing can be combined to access individual cells of the
605
- table:
1005
+ The two forms of indexing can be combined, in either order, to access
1006
+ individual cells of the table:
606
1007
 
607
1008
  #+BEGIN_SRC ruby
608
1009
  tab[13] # => Hash of the 14th row
@@ -612,53 +1013,76 @@ table:
612
1013
  #+END_SRC
613
1014
 
614
1015
  *** Other table attributes
1016
+ Here is a quick rundown of other table attributes that you can access:
615
1017
 
616
1018
  #+BEGIN_SRC ruby
617
1019
  tab.headers # => an Array of the headers in symbol form
618
1020
  tab.types # => a Hash mapping headers to column types
1021
+ tab.type(head) # => return the type of the column for the given head
619
1022
  tab.size # => the number of rows in the table
620
1023
  tab.width # => the number of columns in the table
621
1024
  tab.empty? # => is the table empty?
622
- tab.column?(head) # => does the table have a column with the given header?
1025
+ tab.column(head) # => return the FatTable::Column object for the given head
1026
+ tab.column?(head) # => does the table have a column with the given head?
623
1027
  tab.groups # => return an Array of the table's groups as Arrays of row Hashes.
624
1028
  #+END_SRC
625
1029
 
626
- ** Operations on Tables
1030
+ You should note that what the ~.types~ and ~.type(head)~ methods return is a
1031
+ string naming the "type" assigned by ~FatTable~. All of them are also the
1032
+ names of Ruby classes except to 'Boolean' a class that doesn't exist in Ruby.
1033
+ The value ~true~ is a member of the ~TrueClass~ and ~false~ a member of the
1034
+ ~FalseClass~. So for ~FatTable~ to provide a column of type 'Boolean'
1035
+ requires it to synthesize the type from these Ruby classes.
1036
+
1037
+ #+begin_src ruby :wrap EXAMPLE :results raw
1038
+ tab.types
1039
+ #+end_src
1040
+
1041
+ #+begin_EXAMPLE
1042
+ {:a=>"Numeric", :b=>"Numeric", :c=>"DateTime", :d=>"Boolean", :e=>"NilClass", :f=>"Numeric"}
1043
+ #+end_EXAMPLE
1044
+
1045
+ #+begin_src ruby :wrap EXAMPLE :results output
1046
+ puts "Column :d says its type is '#{tab.type(:d)}' and that is a #{tab.type(:d).class}"
1047
+ #+end_src
1048
+
1049
+ #+begin_EXAMPLE
1050
+ Column :d says its type is 'Boolean' and that is a String
1051
+ #+end_EXAMPLE
627
1052
 
1053
+ ** Operations on Tables
628
1054
  Once you have one or more tables, you will likely want to perform operations on
629
1055
  them. The operations provided by ~FatTable~ are the subject of this section.
630
1056
  Before getting into the operations, though, there are a couple of issues that
631
1057
  cut across all or many of the operations.
632
1058
 
633
1059
  First, tables are by and large immutable objects. Each operation creates a new
634
- table without affecting the input tables. The only exception is the ~degroup!~
635
- operation, which mutates the receiver table by removing its group boundaries.
1060
+ table without affecting the input tables. The only exceptions are the
1061
+ ~degroup!~ operation, which mutates the receiver table by removing its group
1062
+ boundaries, and ~force_string!~ (explained above at [[*Forcing String Type][Forcing String Type]]),
1063
+ which forces columns to have the String type despite what the automatic typing
1064
+ rules determine.
636
1065
 
637
1066
  Second, because each operation returns a ~FatTable::Table~ object, the
638
1067
  operations are chainable.
639
1068
 
640
- <<Groups>>
641
1069
  Third, ~FatTable::Table~ objects can have "groups" of rows within the table.
642
- These can be decorated with hlines and group footers on output. Some of these
643
- operations result in marking group boundaries in the result table, others remove
644
- group boundaries that may have existed in the input table. Operations that
645
- either create or remove groups will be noted below.
1070
+ These can be decorated with hlines and group footers on output. Some
1071
+ operations result in marking group boundaries in the result table, others
1072
+ remove group boundaries that may have existed in the input table. Operations
1073
+ that either create or remove groups will be noted below.
646
1074
 
647
1075
  Finally, the operations are for the most part patterned on SQL table operations,
648
1076
  but when expressions play a role, you write them using ruby syntax rather than
649
1077
  SQL.
650
1078
 
651
- *** Example Input Table
652
-
1079
+ *** Example Input Tables
653
1080
  For illustration purposes assume that the following tables are read into ruby
654
- variables called '~tab1~' and '~tab2~. We have given the table groups, marked by
1081
+ variables called ~tab1~ and ~tab2~. We have given the table groups, marked by
655
1082
  the hlines below, and included some duplicate rows to illustrate the effect of
656
1083
  certain operations on groups and duplicates.
657
1084
 
658
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
659
- #+BEGIN_SRC ruby
660
- require 'fat_table'
661
-
1085
+ #+BEGIN_SRC ruby :results silent
662
1086
  tab1_str = <<-EOS
663
1087
  | Ref | Date | Code | Price | G10 | QP10 | Shares | LP | QP | IPLP | IPQP |
664
1088
  |------+------------------+------+--------+-----+------+--------+------+-------+--------+--------|
@@ -708,26 +1132,31 @@ tab2_str = <<-EOS
708
1132
  | T021 | [2017-01-23 Mon] | P | 7.16 | T | T | 12100 | 11050 | 1050 | 0.2453 | 0.1924 |
709
1133
  | T021 | [2017-01-23 Mon] | P | 7.16 | T | T | 12100 | 11050 | 1050 | 0.2453 | 0.1924 |
710
1134
  EOS
1135
+ #+END_SRC
711
1136
 
712
- tab1 = FatTable.from_org_string(tab1_str)
713
- tab2 = FatTable.from_org_string(tab2_str)
1137
+ Rendering ~tab1~ into Emacs org-mode:
1138
+ #+BEGIN_SRC ruby :wrap EXAMPLE :results silent
1139
+ tab1 = FatTable.from_org_string(tab1_str)
714
1140
  #+END_SRC
715
1141
 
716
- *** Select
1142
+ Rendering ~tab2~ into Emacs org-mode:
717
1143
 
718
- With the ~select~ method, you can select which existing columns should appear in
719
- the output table and create new columns in the output table that are a function
720
- of existing and new columns.
1144
+ #+BEGIN_SRC ruby :wrap EXAMPLE :results silent
1145
+ tab2 = FatTable.from_org_string(tab2_str)
1146
+ #+END_SRC
721
1147
 
722
- **** Selecting Existing Columns
1148
+ *** Select
1149
+ With the ~select~ method, you can select columns to appear in the output
1150
+ table, rearrange their order, and create new columns that are a function of
1151
+ other columns.
723
1152
 
1153
+ **** Selecting Existing Columns (Also of :omni)
724
1154
  Here we select three existing columns by simply passing header symbols in the
725
1155
  order we want them to appear in the output. Thus, one use of =select= is to
726
1156
  filter and permute the order of existing columns. The =select= method preserves
727
1157
  any group boundaries present in the input table.
728
1158
 
729
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
730
- #+BEGIN_SRC ruby
1159
+ #+BEGIN_SRC ruby :wrap EXAMPLE
731
1160
  tab1.select(:price, :ref, :shares).to_aoa
732
1161
  #+END_SRC
733
1162
 
@@ -758,15 +1187,91 @@ any group boundaries present in the input table.
758
1187
  | 8.25 | T016 | 100 |
759
1188
  #+END_EXAMPLE
760
1189
 
761
- **** Adding New Columns
1190
+ It can be tedious to type the names of all the columns in a ~select~
1191
+ statement, so ~FatTable~ recognizes the special column name ~:omni~. If the
1192
+ ~select~'s first and only column argument is ~:omni~, it will expand to the
1193
+ names of all the existing columns in the table. Use of ~:omni~ otherwise is
1194
+ not interpreted specially, so you will get an error complaining about a
1195
+ non-existent column unless you happen to have a column named ~:omni~ in your
1196
+ table, which is not advisable. You can add hash arguments after ~:omni~ but
1197
+ you cannot add additional column names:
1198
+
1199
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1200
+ tab1.select(:omni, cost: 'shares * price').to_aoa
1201
+ #+END_SRC
1202
+
1203
+ #+begin_EXAMPLE
1204
+ | Ref | Date | Code | Price | G10 | QP10 | Shares | Lp | Qp | Iplp | Ipqp | Cost |
1205
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1206
+ | T001 | 2016-11-01 | P | 7.7 | T | F | 100 | 14 | 86 | 0.2453 | 0.1924 | 770.0 |
1207
+ | T002 | 2016-11-01 | P | 7.75 | T | F | 200 | 28 | 172 | 0.2453 | 0.1924 | 1550.0 |
1208
+ | T003 | 2016-11-01 | P | 7.5 | F | T | 800 | 112 | 688 | 0.2453 | 0.1924 | 6000.0 |
1209
+ | T003 | 2016-11-01 | P | 7.5 | F | T | 800 | 112 | 688 | 0.2453 | 0.1924 | 6000.0 |
1210
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1211
+ | T004 | 2016-11-01 | S | 7.55 | T | F | 6811 | 966 | 5845 | 0.2453 | 0.1924 | 51423.05 |
1212
+ | T005 | 2016-11-01 | S | 7.5 | F | F | 4000 | 572 | 3428 | 0.2453 | 0.1924 | 30000.0 |
1213
+ | T006 | 2016-11-01 | S | 7.6 | F | T | 1000 | 143 | 857 | 0.2453 | 0.1924 | 7600.0 |
1214
+ | T006 | 2016-11-01 | S | 7.6 | F | T | 1000 | 143 | 857 | 0.2453 | 0.1924 | 7600.0 |
1215
+ | T007 | 2016-11-01 | S | 7.65 | T | F | 200 | 28 | 172 | 0.2453 | 0.1924 | 1530.0 |
1216
+ | T008 | 2016-11-01 | P | 7.65 | F | F | 2771 | 393 | 2378 | 0.2453 | 0.1924 | 21198.15 |
1217
+ | T009 | 2016-11-01 | P | 7.6 | F | F | 9550 | 1363 | 8187 | 0.2453 | 0.1924 | 72580.0 |
1218
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1219
+ | T010 | 2016-11-01 | P | 7.55 | F | T | 3175 | 451 | 2724 | 0.2453 | 0.1924 | 23971.25 |
1220
+ | T011 | 2016-11-02 | P | 7.425 | T | F | 100 | 14 | 86 | 0.2453 | 0.1924 | 742.5 |
1221
+ | T012 | 2016-11-02 | P | 7.55 | F | F | 4700 | 677 | 4023 | 0.2453 | 0.1924 | 35485.0 |
1222
+ | T012 | 2016-11-02 | P | 7.55 | F | F | 4700 | 677 | 4023 | 0.2453 | 0.1924 | 35485.0 |
1223
+ | T013 | 2016-11-02 | P | 7.35 | T | T | 53100 | 7656 | 45444 | 0.2453 | 0.1924 | 390285.0 |
1224
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1225
+ | T014 | 2016-11-02 | P | 7.45 | F | T | 5847 | 835 | 5012 | 0.2453 | 0.1924 | 43560.15 |
1226
+ | T015 | 2016-11-02 | P | 7.75 | F | F | 500 | 72 | 428 | 0.2453 | 0.1924 | 3875.0 |
1227
+ | T016 | 2016-11-02 | P | 8.25 | T | T | 100 | 14 | 86 | 0.2453 | 0.1924 | 825.0 |
1228
+ #+end_EXAMPLE
1229
+
1230
+ **** Copying and Renaming Existing Columns
1231
+ After the list of selected column names in the call to ~select~, you can add
1232
+ any number of hash-like arguments. You can use these to add a copy of an
1233
+ existing column. By calling select again, you can include only the copied
1234
+ column, in effect renaming it. For example, if you want ~tab1~ but with ~:ref~
1235
+ changed to ~:id~, just add an argument to define the new ~:id~ column:
762
1236
 
763
- More interesting is that ~select~ can take hash-like keyword arguments after the
764
- symbol arguments to create new columns in the output as functions of other
765
- columns. For each hash-like parameter, the keyword given must be a symbol, which
766
- becomes the header for the new column, and the value must be either: (1) a
767
- symbol representing an existing column, which has the effect of renaming an
768
- existing column, or (2) a string representing a ruby expression for the value of
769
- a new column.
1237
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1238
+ tab1.select(:omni, id: :ref).
1239
+ select(:id, :date, :code, :price, :shares).to_aoa
1240
+ #+END_SRC
1241
+
1242
+ #+begin_EXAMPLE
1243
+ | Id | Date | Code | Price | Shares |
1244
+ |------+------------+------+-------+--------|
1245
+ | T001 | 2016-11-01 | P | 7.7 | 100 |
1246
+ | T002 | 2016-11-01 | P | 7.75 | 200 |
1247
+ | T003 | 2016-11-01 | P | 7.5 | 800 |
1248
+ | T003 | 2016-11-01 | P | 7.5 | 800 |
1249
+ |------+------------+------+-------+--------|
1250
+ | T004 | 2016-11-01 | S | 7.55 | 6811 |
1251
+ | T005 | 2016-11-01 | S | 7.5 | 4000 |
1252
+ | T006 | 2016-11-01 | S | 7.6 | 1000 |
1253
+ | T006 | 2016-11-01 | S | 7.6 | 1000 |
1254
+ | T007 | 2016-11-01 | S | 7.65 | 200 |
1255
+ | T008 | 2016-11-01 | P | 7.65 | 2771 |
1256
+ | T009 | 2016-11-01 | P | 7.6 | 9550 |
1257
+ |------+------------+------+-------+--------|
1258
+ | T010 | 2016-11-01 | P | 7.55 | 3175 |
1259
+ | T011 | 2016-11-02 | P | 7.425 | 100 |
1260
+ | T012 | 2016-11-02 | P | 7.55 | 4700 |
1261
+ | T012 | 2016-11-02 | P | 7.55 | 4700 |
1262
+ | T013 | 2016-11-02 | P | 7.35 | 53100 |
1263
+ |------+------------+------+-------+--------|
1264
+ | T014 | 2016-11-02 | P | 7.45 | 5847 |
1265
+ | T015 | 2016-11-02 | P | 7.75 | 500 |
1266
+ | T016 | 2016-11-02 | P | 8.25 | 100 |
1267
+ #+end_EXAMPLE
1268
+
1269
+ **** Adding New Columns
1270
+ More interesting is that ~select~ can take hash-like keyword arguments after
1271
+ the symbol arguments to create new columns in the output as functions of other
1272
+ columns. For each hash-like parameter, the keyword given must be a symbol,
1273
+ which becomes the header for the new column, and the value can be a string
1274
+ representing a ruby expression for the value of a new column.
770
1275
 
771
1276
  Within the string expression, the names of existing or already-specified
772
1277
  columns are available as local variables. In addition the instance variables
@@ -781,8 +1286,7 @@ variables are set the number of the current row and group number respectively.
781
1286
  For example, if we want to rename the ~traded_on~ column to ~:date~ and add a
782
1287
  new column to compute the cost of shares, we could do the following:
783
1288
 
784
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
785
- #+BEGIN_SRC ruby
1289
+ #+BEGIN_SRC ruby :wrap EXAMPLE
786
1290
  tab1.select(:ref, :price, :shares, traded_on: :date, cost: 'price * shares').to_aoa
787
1291
  #+END_SRC
788
1292
 
@@ -813,8 +1317,8 @@ new column to compute the cost of shares, we could do the following:
813
1317
  | T016 | 8.25 | 100 | 2016-11-02 | 825.0 |
814
1318
  #+END_EXAMPLE
815
1319
 
816
- The parameter '~traded_on: :date~' caused the ~:date~ column of the input table
817
- to be renamed '~:traded_on~, and the parameter ~cost: 'price * shares'~ created
1320
+ The parameter ~traded_on: :date~ caused the ~:date~ column of the input table
1321
+ to be renamed ~:traded_on~, and the parameter ~cost: 'price * shares'~ created
818
1322
  a new column, ~:cost~, as the product of values in the ~:price~ and ~:shares~
819
1323
  columns.
820
1324
 
@@ -822,14 +1326,12 @@ The order of the columns in the result tables is the same as the order of the
822
1326
  parameters to the ~select~ method. So, you can re-order the columns with a
823
1327
  second, chained call to ~select~:
824
1328
 
825
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
826
- #+BEGIN_SRC ruby
827
- tab1.select(:ref, :price, :shares, traded_on: :date, cost: 'price * shares') \
828
- .select(:ref, :traded_on, :price, :shares, :cost) \
829
- .to_aoa
1329
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1330
+ tab1.select(:ref, :price, :shares, traded_on: :date, cost: 'price * shares').
1331
+ select(:ref, :traded_on, :price, :shares, :cost).to_aoa
830
1332
  #+END_SRC
831
1333
 
832
- #+BEGIN_EXAMPLE
1334
+ #+begin_EXAMPLE
833
1335
  | Ref | Traded On | Price | Shares | Cost |
834
1336
  |------+------------+-------+--------+----------|
835
1337
  | T001 | 2016-11-01 | 7.7 | 100 | 770.0 |
@@ -854,10 +1356,9 @@ second, chained call to ~select~:
854
1356
  | T014 | 2016-11-02 | 7.45 | 5847 | 43560.15 |
855
1357
  | T015 | 2016-11-02 | 7.75 | 500 | 3875.0 |
856
1358
  | T016 | 2016-11-02 | 8.25 | 100 | 825.0 |
857
- #+END_EXAMPLE
1359
+ #+end_EXAMPLE
858
1360
 
859
1361
  **** Custom Instance Variables and Hooks
860
-
861
1362
  As the above examples demonstrate, the instance variables ~@row~ and ~@group~
862
1363
  are available when evaluating expressions that add new columns. You can also set
863
1364
  up your own instance variables as well for keeping track of things that cross
@@ -878,8 +1379,7 @@ shows the cumulative cost after each transaction in our example table. The
878
1379
  following example uses the ~ivars:~ and ~before_hook:~ parameters to keep track
879
1380
  of the running cost of shares, then formats the table.
880
1381
 
881
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
882
- #+BEGIN_SRC ruby
1382
+ #+BEGIN_SRC ruby :wrap EXAMPLE
883
1383
  tab = tab1.select(:ref, :price, :shares, traded_on: :date, \
884
1384
  cost: 'price * shares', cumulative: '@total_cost', \
885
1385
  ivars: { total_cost: 0 }, \
@@ -917,7 +1417,6 @@ of the running cost of shares, then formats the table.
917
1417
  #+END_EXAMPLE
918
1418
 
919
1419
  **** Argument Order and Boundaries
920
-
921
1420
  Notice that ~select~ can take any number of arguments but all the symbol
922
1421
  arguments must come first followed by all the hash-like keyword arguments,
923
1422
  including the special arguments for instance variables and hooks.
@@ -926,21 +1425,21 @@ As the example illustrates, ~.select~ transmits any group boundaries in its
926
1425
  input table to the result table.
927
1426
 
928
1427
  *** Where
929
-
930
1428
  You can filter the rows of the result table with the ~.where~ method. It takes a
931
1429
  single string expression as an argument which is evaluated in a manner similar
932
1430
  to ~.select~ in which the value of the cells in each column are available as
933
1431
  local variables and the instance variables ~@row~ and ~@group~ are available for
934
1432
  testing. The expression is evaluated for each row, and if the expression
935
1433
  evaluates to a truthy value, the row is included in the output, otherwise it is
936
- not. The ~.where~ method obliterates any group boundaries in the input, so the
937
- output table has only a single group.
1434
+ not.
1435
+
1436
+ The ~.where~ method removes any group boundaries in the input, so the output
1437
+ table has only a single group.
938
1438
 
939
1439
  Here we select only those even-numbered rows where either of the two boolean
940
1440
  fields is true:
941
1441
 
942
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
943
- #+BEGIN_SRC ruby
1442
+ #+BEGIN_SRC ruby :wrap EXAMPLE
944
1443
  tab1.where('@row.even? && (g10 || qp10)') \
945
1444
  .to_aoa
946
1445
  #+END_SRC
@@ -956,7 +1455,6 @@ fields is true:
956
1455
  #+END_EXAMPLE
957
1456
 
958
1457
  *** Order_by
959
-
960
1458
  You can sort a table on any number of columns with ~order_by~. The ~order_by~
961
1459
  method takes any number of symbol arguments for the columns to sort on. If you
962
1460
  specify more than one column, the sort is performed on the first column, then
@@ -967,8 +1465,7 @@ All columns of the input table are included in the output.
967
1465
 
968
1466
  Let's sort our table first by ~:code~, then in reverse order of ~:date~.
969
1467
 
970
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
971
- #+BEGIN_SRC ruby
1468
+ #+BEGIN_SRC ruby :wrap EXAMPLE
972
1469
  tab1.order_by(:code, :date!) \
973
1470
  .to_aoa
974
1471
  #+END_SRC
@@ -1004,8 +1501,59 @@ input, it adds group boundaries in the output table at those rows where the sort
1004
1501
  keys change. Thus, in each group, ~:code~ and ~:date~ are the same, and when
1005
1502
  either changes, ~order_by~ inserts a group boundary.
1006
1503
 
1007
- *** Group_by
1504
+ *** Order_with
1505
+ The ~order_with~ method is a convenient combination of ~select~ and
1506
+ ~order_by~. It takes a single string expression as an argument to serve as a
1507
+ sort key---one that would be valid as a select expression---but with an
1508
+ optional trailing ~!~ to indicate reverse sort. The resulting table has an
1509
+ additional column called ~:sort_key~ with the expression evaluated for each
1510
+ row, and the table is sorted as with ~order_by~ on that column.
1511
+
1512
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1513
+ tab1.order_with('price * shares').to_aoa
1514
+ #+END_SRC
1008
1515
 
1516
+ #+begin_EXAMPLE
1517
+ | Ref | Date | Code | Price | G10 | QP10 | Shares | Lp | Qp | Iplp | Ipqp | Sort Key |
1518
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1519
+ | T011 | 2016-11-02 | P | 7.425 | T | F | 100 | 14 | 86 | 0.2453 | 0.1924 | 742.5 |
1520
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1521
+ | T001 | 2016-11-01 | P | 7.7 | T | F | 100 | 14 | 86 | 0.2453 | 0.1924 | 770.0 |
1522
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1523
+ | T016 | 2016-11-02 | P | 8.25 | T | T | 100 | 14 | 86 | 0.2453 | 0.1924 | 825.0 |
1524
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1525
+ | T007 | 2016-11-01 | S | 7.65 | T | F | 200 | 28 | 172 | 0.2453 | 0.1924 | 1530.0 |
1526
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1527
+ | T002 | 2016-11-01 | P | 7.75 | T | F | 200 | 28 | 172 | 0.2453 | 0.1924 | 1550.0 |
1528
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1529
+ | T015 | 2016-11-02 | P | 7.75 | F | F | 500 | 72 | 428 | 0.2453 | 0.1924 | 3875.0 |
1530
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1531
+ | T003 | 2016-11-01 | P | 7.5 | F | T | 800 | 112 | 688 | 0.2453 | 0.1924 | 6000.0 |
1532
+ | T003 | 2016-11-01 | P | 7.5 | F | T | 800 | 112 | 688 | 0.2453 | 0.1924 | 6000.0 |
1533
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1534
+ | T006 | 2016-11-01 | S | 7.6 | F | T | 1000 | 143 | 857 | 0.2453 | 0.1924 | 7600.0 |
1535
+ | T006 | 2016-11-01 | S | 7.6 | F | T | 1000 | 143 | 857 | 0.2453 | 0.1924 | 7600.0 |
1536
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1537
+ | T008 | 2016-11-01 | P | 7.65 | F | F | 2771 | 393 | 2378 | 0.2453 | 0.1924 | 21198.15 |
1538
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1539
+ | T010 | 2016-11-01 | P | 7.55 | F | T | 3175 | 451 | 2724 | 0.2453 | 0.1924 | 23971.25 |
1540
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1541
+ | T005 | 2016-11-01 | S | 7.5 | F | F | 4000 | 572 | 3428 | 0.2453 | 0.1924 | 30000.0 |
1542
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1543
+ | T012 | 2016-11-02 | P | 7.55 | F | F | 4700 | 677 | 4023 | 0.2453 | 0.1924 | 35485.0 |
1544
+ | T012 | 2016-11-02 | P | 7.55 | F | F | 4700 | 677 | 4023 | 0.2453 | 0.1924 | 35485.0 |
1545
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1546
+ | T014 | 2016-11-02 | P | 7.45 | F | T | 5847 | 835 | 5012 | 0.2453 | 0.1924 | 43560.15 |
1547
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1548
+ | T004 | 2016-11-01 | S | 7.55 | T | F | 6811 | 966 | 5845 | 0.2453 | 0.1924 | 51423.05 |
1549
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1550
+ | T009 | 2016-11-01 | P | 7.6 | F | F | 9550 | 1363 | 8187 | 0.2453 | 0.1924 | 72580.0 |
1551
+ |------+------------+------+-------+-----+------+--------+------+-------+--------+--------+----------|
1552
+ | T013 | 2016-11-02 | P | 7.35 | T | T | 53100 | 7656 | 45444 | 0.2453 | 0.1924 | 390285.0 |
1553
+ #+end_EXAMPLE
1554
+
1555
+
1556
+ *** Group_by
1009
1557
  Like ~order_by~, ~group_by~ takes a set of parameters of column header symbols,
1010
1558
  the "grouping parameters", by which to sort the table into a set of groups that
1011
1559
  are equal with respect to values in those columns. In addition, those parameters
@@ -1019,8 +1567,7 @@ For example, let's summarize the ~trades~ table by ~:code~ and ~:price~ again,
1019
1567
  and determine total shares, average price, and a few other features of each
1020
1568
  group:
1021
1569
 
1022
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1023
- #+BEGIN_SRC ruby
1570
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1024
1571
  tab1.group_by(:code, :date, price: :avg,
1025
1572
  shares: :sum, lp: :sum, qp: :sum,
1026
1573
  qp10: :all?) \
@@ -1040,7 +1587,7 @@ hash-like "aggregating" parameters where the key is the column to aggregate and
1040
1587
  the value is a symbol for one of several aggregating methods that
1041
1588
  ~FatTable::Column~ objects understand. For example, the ~:avg~ method is applied
1042
1589
  to the :price column so that the output shows the average price in each group.
1043
- The ~:shares~, ~:lp~, and ~:qp~ columns are summed, and the ~:any?~ aggregate is
1590
+ The ~:shares~, ~:lp~, and ~:qp~ columns are summed, and the ~:all?~ aggregate is
1044
1591
  applied to one of the boolean fields, that is, it is ~true~ if any of the values
1045
1592
  in that column are ~true~.
1046
1593
 
@@ -1053,15 +1600,15 @@ will raise an exception.
1053
1600
 
1054
1601
  - ~first~ :: the first non-nil item in the column,
1055
1602
  - ~last~ :: the last non-nil item in the column,
1056
- - ~rng~ :: form a string of the form ~"#{first}..#{last}"~ to show the range of
1057
- values in the column,
1058
- - ~sum~ :: for ~Numeric~ and ~String~ columns, apply '+' to all the non-nil
1059
- values,
1603
+ - ~range~ :: form a Range ~~{min}..{max}~ to show the range of values in the
1604
+ column,
1605
+ - ~sum~ :: for ~Numeric~ columns, apply '+' to all the non-nil
1606
+ values; for ~String~ columns, join the elements with a single space,
1060
1607
  - ~count~ :: the number of non-nil values in the column,
1061
1608
  - ~min~ :: for ~Numeric~, ~String~, and ~DateTime~ columns, return the smallest
1062
- non-nil value in the column,
1609
+ non-nil, non-blank value in the column,
1063
1610
  - ~max~ :: for ~Numeric~, ~String~, and ~DateTime~ columns, return the largest
1064
- non-nil value in the column,
1611
+ non-nil, non-blank value in the column,
1065
1612
  - ~avg~ :: for ~Numeric~ and ~DateTime~ columns, return the arithmetic mean of
1066
1613
  the non-nil values in the column; with respect to ~Date~ or ~DateTime~
1067
1614
  objects, each is converted to a numeric Julian date, the average is
@@ -1093,7 +1640,6 @@ implicit ~order_by~ on the grouping columns is collapsed into a single row.
1093
1640
 
1094
1641
  *** Join
1095
1642
  **** Join Types
1096
-
1097
1643
  So far, all the operations have operated on a single table. ~FatTable~ provides
1098
1644
  several ~join~ methods for combining two tables, each of which takes as
1099
1645
  parameters (1) a second table and (2) except in the case of ~cross_join~, zero
@@ -1130,7 +1676,6 @@ for inclusion in the joined output table.
1130
1676
  M~ rows.
1131
1677
 
1132
1678
  **** Join Expressions
1133
-
1134
1679
  For each of the join types, if no join expressions are given, the tables will be
1135
1680
  joined on columns having the same column header in both tables, and the join
1136
1681
  condition is satisfied when all the values in those columns are equal. If the
@@ -1158,48 +1703,74 @@ local variables within the expression, but the instance variables ~@row~ and
1158
1703
  ~@group~ are not.
1159
1704
 
1160
1705
  **** Join Examples
1161
-
1162
1706
  The following examples are taken from the [[https://www.tutorialspoint.com/postgresql/postgresql_using_joins.htm][Postgresql tutorial]], with some slight
1163
1707
  modifications. The examples will use the following two tables, which are also
1164
1708
  available in ~ft_console~ as ~@tab_a~ and ~@tab_b~:
1165
1709
 
1166
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1167
- #+BEGIN_SRC ruby
1168
- require 'fat_table'
1169
-
1170
- tab_a_str = <<-EOS
1171
- | Id | Name | Age | Address | Salary | Join Date |
1172
- |----+-------+-----+------------+--------+------------|
1173
- | 1 | Paul | 32 | California | 20000 | 2001-07-13 |
1174
- | 3 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
1175
- | 4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
1176
- | 5 | David | 27 | Texas | 85000 | 2007-12-13 |
1177
- | 2 | Allen | 25 | Texas | | 2005-07-13 |
1178
- | 8 | Paul | 24 | Houston | 20000 | 2005-07-13 |
1179
- | 9 | James | 44 | Norway | 5000 | 2005-07-13 |
1180
- | 10 | James | 45 | Texas | 5000 | |
1181
- EOS
1710
+ #+BEGIN_SRC ruby :wrap EXAMPLE :results silent
1711
+ tab_a_str = <<-EOS
1712
+ | Id | Name | Age | Address | Salary | Join Date |
1713
+ |----+-------+-----+------------+--------+------------|
1714
+ | 1 | Paul | 32 | California | 20000 | 2001-07-13 |
1715
+ | 3 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
1716
+ | 4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
1717
+ | 5 | David | 27 | Texas | 85000 | 2007-12-13 |
1718
+ | 2 | Allen | 25 | Texas | | 2005-07-13 |
1719
+ | 8 | Paul | 24 | Houston | 20000 | 2005-07-13 |
1720
+ | 9 | James | 44 | Norway | 5000 | 2005-07-13 |
1721
+ | 10 | James | 45 | Texas | 5000 | |
1722
+ EOS
1182
1723
 
1183
- tab_b_str = <<-EOS
1184
- | Id | Dept | Emp Id |
1185
- |----+-------------+--------|
1186
- | 1 | IT Billing | 1 |
1187
- | 2 | Engineering | 2 |
1188
- | 3 | Finance | 7 |
1189
- EOS
1724
+ tab_b_str = <<-EOS
1725
+ | Id | Dept | Emp Id |
1726
+ |----+-------------+--------|
1727
+ | 1 | IT Billing | 1 |
1728
+ | 2 | Engineering | 2 |
1729
+ | 3 | Finance | 7 |
1730
+ EOS
1190
1731
 
1191
- tab_a = FatTable.from_org_string(tab_a_str)
1192
- tab_b = FatTable.from_org_string(tab_b_str)
1732
+ tab_b = FatTable.from_org_string(tab_b_str)
1193
1733
  #+END_SRC
1194
1734
 
1195
- ***** Inner Joins
1735
+ Here is ~tab_a~:
1736
+ #+begin_src ruby :wrap EXAMPLE
1737
+ tab_a = FatTable.from_org_string(tab_a_str)
1738
+ tab_a.to_aoa
1739
+ #+end_src
1740
+
1741
+ #+begin_EXAMPLE
1742
+ | Id | Name | Age | Address | Salary | Join Date |
1743
+ |----+-------+-----+------------+--------+------------|
1744
+ | 1 | Paul | 32 | California | 20000 | 2001-07-13 |
1745
+ | 3 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
1746
+ | 4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
1747
+ | 5 | David | 27 | Texas | 85000 | 2007-12-13 |
1748
+ | 2 | Allen | 25 | Texas | | 2005-07-13 |
1749
+ | 8 | Paul | 24 | Houston | 20000 | 2005-07-13 |
1750
+ | 9 | James | 44 | Norway | 5000 | 2005-07-13 |
1751
+ | 10 | James | 45 | Texas | 5000 | |
1752
+ #+end_EXAMPLE
1753
+
1754
+ And ~tab_b~:
1755
+ #+begin_src ruby :wrap EXAMPLE
1756
+ tab_b = FatTable.from_org_string(tab_b_str)
1757
+ tab_b.to_aoa
1758
+ #+end_src
1196
1759
 
1760
+ #+begin_EXAMPLE
1761
+ | Id | Dept | Emp Id |
1762
+ |----+-------------+--------|
1763
+ | 1 | IT Billing | 1 |
1764
+ | 2 | Engineering | 2 |
1765
+ | 3 | Finance | 7 |
1766
+ #+end_EXAMPLE
1767
+
1768
+ ***** Inner Joins
1197
1769
  With no join expression arguments, the tables are joined when their sole common
1198
1770
  field, ~:id~, is equal in both tables. The result is the natural join of the
1199
1771
  two tables.
1200
1772
 
1201
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1202
- #+BEGIN_SRC ruby
1773
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1203
1774
  tab_a.join(tab_b).to_aoa
1204
1775
  #+END_SRC
1205
1776
 
@@ -1216,8 +1787,7 @@ in the second table. To correct this, we need to explicitly state the columns we
1216
1787
  want to join on in each table by disambiguating them with ~_a~ and ~_b~
1217
1788
  suffixes:
1218
1789
 
1219
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1220
- #+BEGIN_SRC ruby
1790
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1221
1791
  tab_a.join(tab_b, :id_a, :emp_id_b).to_aoa
1222
1792
  #+END_SRC
1223
1793
 
@@ -1232,8 +1802,7 @@ Instead of using the disambiguated column names as symbols, we could also use a
1232
1802
  string containing a ruby expression. Within the expression, the column names
1233
1803
  should be treated as local variables:
1234
1804
 
1235
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1236
- #+BEGIN_SRC ruby
1805
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1237
1806
  tab_a.join(tab_b, 'id_a == emp_id_b').to_aoa
1238
1807
  #+END_SRC
1239
1808
 
@@ -1245,12 +1814,10 @@ should be treated as local variables:
1245
1814
  #+END_EXAMPLE
1246
1815
 
1247
1816
  ***** Left and Right Joins
1248
-
1249
1817
  In left join, all the rows of ~tab_a~ are included in the output, augmented by
1250
1818
  the matching columns of ~tab_b~ and augmented with nils where there is no match:
1251
1819
 
1252
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1253
- #+BEGIN_SRC ruby
1820
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1254
1821
  tab_a.left_join(tab_b, 'id_a == emp_id_b').to_aoa
1255
1822
  #+END_SRC
1256
1823
 
@@ -1271,8 +1838,7 @@ In a right join, all the rows of ~tab_b~ are included in the output, augmented
1271
1838
  by the matching columns of ~tab_a~ and augmented with nils where there is no
1272
1839
  match:
1273
1840
 
1274
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1275
- #+BEGIN_SRC ruby
1841
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1276
1842
  tab_a.right_join(tab_b, 'id_a == emp_id_b').to_aoa
1277
1843
  #+END_SRC
1278
1844
 
@@ -1285,13 +1851,11 @@ match:
1285
1851
  #+END_EXAMPLE
1286
1852
 
1287
1853
  ***** Full Join
1288
-
1289
1854
  A full join combines the effects of a left join and a right join. All the rows
1290
1855
  from both tables are included in the output augmented by columns of the other
1291
1856
  table where the join expression is satisfied and augmented with nils otherwise.
1292
1857
 
1293
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1294
- #+BEGIN_SRC ruby
1858
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1295
1859
  tab_a.full_join(tab_b, 'id_a == emp_id_b').to_aoa
1296
1860
  #+END_SRC
1297
1861
 
@@ -1310,14 +1874,12 @@ table where the join expression is satisfied and augmented with nils otherwise.
1310
1874
  #+END_EXAMPLE
1311
1875
 
1312
1876
  ***** Cross Join
1313
-
1314
1877
  Finally, a cross join outputs every row of ~tab_a~ augmented with every row of
1315
1878
  ~tab_b~, in other words, the Cartesian product of the two tables. If ~tab_a~ has
1316
1879
  ~N~ rows and ~tab_b~ has ~M~ rows, the output table will have ~N * M~ rows.
1317
1880
  So be careful lest you consume all your computer's memory.
1318
1881
 
1319
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1320
- #+BEGIN_SRC ruby
1882
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1321
1883
  tab_a.cross_join(tab_b).to_aoa
1322
1884
  #+END_SRC
1323
1885
 
@@ -1351,7 +1913,6 @@ So be careful lest you consume all your computer's memory.
1351
1913
  #+END_EXAMPLE
1352
1914
 
1353
1915
  *** Set Operations
1354
-
1355
1916
  ~FatTable~ can perform several set operations on pairs of tables. In order for
1356
1917
  two tables to be used this way, they must have the same number of columns with
1357
1918
  the same types or an exception will be raised. We'll call two tables that
@@ -1361,8 +1922,7 @@ We'll use the following two set-compatible tables in the examples. They each
1361
1922
  have some duplicates and some group boundaries so you can see the effect of the
1362
1923
  set operations on duplicates and groups.
1363
1924
 
1364
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1365
- #+BEGIN_SRC ruby
1925
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1366
1926
  tab1.to_aoa
1367
1927
  #+END_SRC
1368
1928
 
@@ -1393,8 +1953,7 @@ set operations on duplicates and groups.
1393
1953
  | T016 | 2016-11-02 | P | 8.25 | T | T | 100 | 14 | 86 | 0.2453 | 0.1924 |
1394
1954
  #+END_EXAMPLE
1395
1955
 
1396
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1397
- #+BEGIN_SRC ruby
1956
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1398
1957
  tab2.to_aoa
1399
1958
  #+END_SRC
1400
1959
 
@@ -1422,7 +1981,6 @@ set operations on duplicates and groups.
1422
1981
  #+END_EXAMPLE
1423
1982
 
1424
1983
  **** Unions
1425
-
1426
1984
  Two tables that are set-compatible can be combined with the ~union~ or
1427
1985
  ~union_all~ methods so that the rows of both tables appear in the output. In the
1428
1986
  output table, the headers of the receiver table are used. You can use ~select~
@@ -1433,8 +1991,7 @@ Any group boundaries in the input tables are destroyed by ~union~ but are
1433
1991
  preserved by ~union_all~. In addition, ~union_all~ (but not ~union~) adds a
1434
1992
  group boundary between the rows of the two input tables.
1435
1993
 
1436
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1437
- #+BEGIN_SRC ruby
1994
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1438
1995
  tab1.union(tab2).to_aoa
1439
1996
  #+END_SRC
1440
1997
 
@@ -1464,8 +2021,7 @@ group boundary between the rows of the two input tables.
1464
2021
  | T021 | 2017-01-23 | P | 7.16 | T | T | 12100 | 11050 | 1050 | 0.2453 | 0.1924 |
1465
2022
  #+END_EXAMPLE
1466
2023
 
1467
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1468
- #+BEGIN_SRC ruby
2024
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1469
2025
  tab1.union_all(tab2).to_aoa
1470
2026
  #+END_SRC
1471
2027
 
@@ -1516,12 +2072,10 @@ group boundary between the rows of the two input tables.
1516
2072
  #+END_EXAMPLE
1517
2073
 
1518
2074
  **** Intersections
1519
-
1520
2075
  The ~intersect~ method returns a table having only rows common to both tables,
1521
2076
  eliminating any duplicate rows in the result.
1522
2077
 
1523
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1524
- #+BEGIN_SRC ruby
2078
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1525
2079
  tab1.intersect(tab2).to_aoa
1526
2080
  #+END_SRC
1527
2081
 
@@ -1540,8 +2094,7 @@ With ~intersect_all~, all the rows of the first table, including duplicates, are
1540
2094
  included in the result if they also occur in the second table. However,
1541
2095
  duplicates in the second table do not appear.
1542
2096
 
1543
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1544
- #+BEGIN_SRC ruby
2097
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1545
2098
  tab1.intersect_all(tab2).to_aoa
1546
2099
  #+END_SRC
1547
2100
 
@@ -1562,8 +2115,7 @@ As a result, it makes a difference which table is the receiver of the
1562
2115
  ~intersect_all~ method call and which is the argument. In other words, order of
1563
2116
  operation matters.
1564
2117
 
1565
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1566
- #+BEGIN_SRC ruby
2118
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1567
2119
  tab2.intersect_all(tab1).to_aoa
1568
2120
  #+END_SRC
1569
2121
 
@@ -1580,13 +2132,11 @@ operation matters.
1580
2132
  | T016 | 2016-11-02 | P | 8.25 | T | T | 100 | 14 | 86 | 0.2453 | 0.1924 |
1581
2133
  #+END_EXAMPLE
1582
2134
 
1583
- **** Differences with Except
1584
-
2135
+ **** Set Differences with Except
1585
2136
  You can use the ~except~ method to delete from a table any rows that occur in
1586
2137
  another table, that is, compute the set difference between the tables.
1587
2138
 
1588
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1589
- #+BEGIN_SRC ruby
2139
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1590
2140
  tab1.except(tab2).to_aoa
1591
2141
  #+END_SRC
1592
2142
 
@@ -1608,8 +2158,7 @@ another table, that is, compute the set difference between the tables.
1608
2158
  Like subtraction, though, the order of operands matters with set difference
1609
2159
  computed by ~except~.
1610
2160
 
1611
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1612
- #+BEGIN_SRC ruby
2161
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1613
2162
  tab2.except(tab1).to_aoa
1614
2163
  #+END_SRC
1615
2164
 
@@ -1626,8 +2175,7 @@ computed by ~except~.
1626
2175
  As with ~intersect_all~, ~except_all~ includes any duplicates in the first,
1627
2176
  receiver table, but not those in the second, argument table.
1628
2177
 
1629
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1630
- #+BEGIN_SRC ruby
2178
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1631
2179
  tab1.except_all(tab2).to_aoa
1632
2180
  #+END_SRC
1633
2181
 
@@ -1649,8 +2197,7 @@ receiver table, but not those in the second, argument table.
1649
2197
 
1650
2198
  And, of course, the order of operands matters here as well.
1651
2199
 
1652
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1653
- #+BEGIN_SRC ruby
2200
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1654
2201
  tab2.except_all(tab1).to_aoa
1655
2202
  #+END_SRC
1656
2203
 
@@ -1667,13 +2214,11 @@ And, of course, the order of operands matters here as well.
1667
2214
  #+END_EXAMPLE
1668
2215
 
1669
2216
  *** Uniq (aka Distinct)
1670
-
1671
2217
  The ~uniq~ method takes no arguments and simply removes any duplicate rows from
1672
2218
  the input table. The ~distinct~ method is an alias for ~uniq~. Any groups in
1673
2219
  the input table are lost.
1674
2220
 
1675
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1676
- #+BEGIN_SRC ruby
2221
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1677
2222
  tab1.uniq.to_aoa
1678
2223
  #+END_SRC
1679
2224
 
@@ -1699,13 +2244,11 @@ the input table are lost.
1699
2244
  #+END_EXAMPLE
1700
2245
 
1701
2246
  *** Remove groups with degroup!
1702
-
1703
2247
  Finally, it is sometimes helpful to remove any group boundaries from a table.
1704
- You can do this with ~.degroup!~, which is the only operation that mutates its
1705
- receiver table by removing its groups.
2248
+ You can do this with ~.degroup!~, which, together with ~force_string!~, are
2249
+ the only operations that mutate their receiver tables.
1706
2250
 
1707
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1708
- #+BEGIN_SRC ruby
2251
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1709
2252
  tab1.degroup!.to_aoa
1710
2253
  #+END_SRC
1711
2254
 
@@ -1734,7 +2277,6 @@ receiver table by removing its groups.
1734
2277
  #+END_EXAMPLE
1735
2278
 
1736
2279
  ** Formatting Tables
1737
-
1738
2280
  Besides creating and operating on tables, you may want to display the resulting
1739
2281
  table. ~FatTable~ seeks to provide a set of formatting directives that are the
1740
2282
  most common across many output media. It provides directives for alignment, for
@@ -1751,8 +2293,8 @@ an ~org-mode~ table as a String, and since ~org-mode~ does not support colors,
1751
2293
  any color directives are ignored. Some of the output targets are not strings,
1752
2294
  but ruby data structures, and for them, things such as alignment are irrelevant.
1753
2295
 
1754
- *** Available Formatters
1755
-
2296
+ *** Available Formatter Output Targets
2297
+ **** Output Media
1756
2298
  ~FatTable~ supports the following output targets for its tables:
1757
2299
 
1758
2300
  - Text :: form the table with ACSII characters,
@@ -1771,33 +2313,144 @@ class by defining about a dozen methods that get called at various places
1771
2313
  during the construction of the output table. The idea is that more output
1772
2314
  formats can be defined by adding additional classes.
1773
2315
 
1774
- *** Table Locations
2316
+ **** Examples
2317
+ ***** To Text
2318
+ This formatter uses nothing by ASCII characters to draw the table. Notice
2319
+ that, unlike to ~to_org~ formatter shown below, the intersections of lines are
2320
+ represented by a ~+~ character. Embelishments such as color, bold, and so
2321
+ forth are ignored.
1775
2322
 
1776
- In the formatting methods, the table is divided into several "locations" for
1777
- which separate formatting directives may be given. These locations are
1778
- identified with the following symbols:
2323
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2324
+ tab_a.to_text
2325
+ #+end_SRC
1779
2326
 
1780
- - :header :: the first row of the output table containing the headers,
1781
- - :footer :: all rows of the table's footers,
1782
- - :gfooter :: all rows of the table's group footers,
1783
- - :body :: all the data rows of the table, that is, those that are neither part
1784
- of the header, footers, or gfooters,
1785
- - :bfirst :: the first row of the table's body, and
1786
- - :gfirst :: the first row in each group in the table's body.
2327
+ #+BEGIN_EXAMPLE
2328
+ +====+=======+=====+============+========+============+
2329
+ | Id | Name | Age | Address | Salary | Join Date |
2330
+ +----+-------+-----+------------+--------+------------+
2331
+ | 1 | Paul | 32 | California | 20000 | 2001-07-13 |
2332
+ | 3 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
2333
+ | 4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
2334
+ | 5 | David | 27 | Texas | 85000 | 2007-12-13 |
2335
+ | 2 | Allen | 25 | Texas | | 2005-07-13 |
2336
+ | 8 | Paul | 24 | Houston | 20000 | 2005-07-13 |
2337
+ | 9 | James | 44 | Norway | 5000 | 2005-07-13 |
2338
+ | 10 | James | 45 | Texas | 5000 | |
2339
+ +====+=======+=====+============+========+============+
2340
+ #+END_EXAMPLE
1787
2341
 
1788
- *** Formatting Directives
2342
+ ***** To Org
2343
+ This formatter is designed to format tables in a manner consistent with the
2344
+ way tables are drawn within Emacs Org Mode. It also uses nothing by ASCII
2345
+ characters to draw the table, but, the intersections of lines are represented
2346
+ by a ~|~ character. Embelishments such as color, bold, and so forth are
2347
+ ignored. When working in Org Mode, note that Emacs will convert an Array of
2348
+ Arrays into an Org Mode table, so when constructing tables programmatically,
2349
+ it may be better to use that formatter as shown below.
2350
+
2351
+ #+begin_SRC ruby :wrap EXAMPLE
2352
+ tab_a.to_org
2353
+ #+end_SRC
2354
+
2355
+ #+begin_EXAMPLE
2356
+ |----+-------+-----+------------+--------+--------------|
2357
+ | Id | Name | Age | Address | Salary | Join Date |
2358
+ |----+-------+-----+------------+--------+--------------|
2359
+ | 1 | Paul | 32 | California | 20000 | [2001-07-13] |
2360
+ | 3 | Teddy | 23 | Norway | 20000 | [2007-12-13] |
2361
+ | 4 | Mark | 25 | Rich-Mond | 65000 | [2007-12-13] |
2362
+ | 5 | David | 27 | Texas | 85000 | [2007-12-13] |
2363
+ | 2 | Allen | 25 | Texas | | [2005-07-13] |
2364
+ | 8 | Paul | 24 | Houston | 20000 | [2005-07-13] |
2365
+ | 9 | James | 44 | Norway | 5000 | [2005-07-13] |
2366
+ | 10 | James | 45 | Texas | 5000 | |
2367
+ |----+-------+-----+------------+--------+--------------|
2368
+ #+end_EXAMPLE
2369
+
2370
+ ***** To Term
2371
+ When outputting to a terminal or other device that can interpret ANSI
2372
+ characters and escape codes, you can use this formatter to get a prettier
2373
+ table. It also allows embelishments such as color and text styles to the
2374
+ extent the device supports it.
2375
+
2376
+ #+begin_SRC ruby :wrap EXAMPLE
2377
+ tab_a.to_term
2378
+ #+end_SRC
2379
+
2380
+ #+begin_EXAMPLE
2381
+ ╒════╤═══════╤═════╤════════════╤════════╤════════════╕
2382
+ │ Id │ Name │ Age │ Address │ Salary │ Join Date │
2383
+ ├────┼───────┼─────┼────────────┼────────┼────────────┤
2384
+ │ 1 │ Paul │ 32 │ California │ 20000 │ 2001-07-13 │
2385
+ │ 3 │ Teddy │ 23 │ Norway │ 20000 │ 2007-12-13 │
2386
+ │ 4 │ Mark │ 25 │ Rich-Mond │ 65000 │ 2007-12-13 │
2387
+ │ 5 │ David │ 27 │ Texas │ 85000 │ 2007-12-13 │
2388
+ │ 2 │ Allen │ 25 │ Texas │ │ 2005-07-13 │
2389
+ │ 8 │ Paul │ 24 │ Houston │ 20000 │ 2005-07-13 │
2390
+ │ 9 │ James │ 44 │ Norway │ 5000 │ 2005-07-13 │
2391
+ │ 10 │ James │ 45 │ Texas │ 5000 │ │
2392
+ ╘════╧═══════╧═════╧════════════╧════════╧════════════╛
2393
+ #+end_EXAMPLE
2394
+
2395
+ ***** To LaTeX
2396
+ This formatter outputs a table in the form suitable for inclusion in a LaTeX
2397
+ document using the ~logtable~ package. Natualy it allows embelishments such
2398
+ as color and text styles to the full extent of LaTeX's formatting prowess.
2399
+
2400
+ #+begin_SRC ruby :wrap EXAMPLE
2401
+ tab_b.to_latex
2402
+ #+end_SRC
2403
+
2404
+ #+begin_EXAMPLE
2405
+ \begin{longtable}{lll}
2406
+ Id&
2407
+ Dept&
2408
+ Emp Id\\
2409
+ \endhead
2410
+ 1&
2411
+ IT Billing&
2412
+ 1\\
2413
+ 2&
2414
+ Engineering&
2415
+ 2\\
2416
+ 3&
2417
+ Finance&
2418
+ 7\\
2419
+ \end{longtable}
2420
+ #+end_EXAMPLE
2421
+
2422
+ ***** To AoA (Array of Arrays)
2423
+ #+begin_SRC ruby :wrap EXAMPLE
2424
+ tab_b.to_aoa
2425
+ #+end_SRC
2426
+
2427
+ #+begin_EXAMPLE
2428
+ [["Id", "Dept", "Emp Id"], nil, ["1", "IT Billing", "1"], ["2", "Engineering", "2"],
2429
+ ["3", "Finance", "7"]]
2430
+ #+end_EXAMPLE
2431
+
2432
+ ***** To AoH (Array of Hashes)
2433
+ #+begin_SRC ruby :wrap EXAMPLE
2434
+ tab_b.to_aoh
2435
+ #+end_SRC
2436
+
2437
+ #+begin_EXAMPLE
2438
+ [{:id=>"1", :dept=>"IT Billing", :emp_id=>"1"}, {:id=>"2", :dept=>"Engineering", :emp_id=>"2"},
2439
+ {:id=>"3", :dept=>"Finance", :emp_id=>"7"}]
2440
+ #+end_EXAMPLE
1789
2441
 
2442
+
2443
+ *** Formatting Directives
1790
2444
  The formatting methods explained in the next section all take formatting
1791
2445
  directives as strings in which letters and other characters signify what
1792
- formatting applies. For example, we may apply the formatting directive ~'R,$'~
2446
+ formatting applies. For example, we may apply the formatting directive 'R,$'
1793
2447
  to numbers in a certain part of the table. Each of those characters, and in
1794
2448
  some cases a whole substring, is a single directive. They can appear in any
1795
- order, so ~'$R,'~ and ~',$R'~ are equivalent.
2449
+ order, so '$R,' and ',$R' are equivalent.
1796
2450
 
1797
2451
  Here is a list of all the formatting directives that apply to each cell type:
1798
2452
 
1799
2453
  **** String
1800
-
1801
2454
  For a string element, the following instructions are valid. Note that these can
1802
2455
  also be applied to all the other cell types as well since they are all converted
1803
2456
  to a string in forming the output.
@@ -1811,22 +2464,21 @@ to a string in forming the output.
1811
2464
  - R :: align the element on the right of the column
1812
2465
  - L :: align the element on the left of the column
1813
2466
  - C :: align the element in the center of the column
1814
- - c[color] :: render the element in the given color; the color can have
1815
- the form fgcolor, fgcolor.bgcolor, or .bgcolor, to set the
1816
- foreground or background colors respectively, and each of those can
1817
- be an ANSI or X11 color name in addition to the special color,
1818
- 'none', which keeps the terminal's default color.
2467
+ - c[<color_spec>] :: render the element in the given color; the <color_spec>
2468
+ can have the form fgcolor, fgcolor.bgcolor, or .bgcolor, to set the
2469
+ foreground or background colors respectively, and each of those can be an
2470
+ ANSI or X11 color name in addition to the special color, 'none', which keeps
2471
+ the output's default color.
1819
2472
  - _ ~_ :: underline the element, or turn off underline
1820
2473
  - * ~* :: cause the element to blink, or turn off blink
1821
2474
 
1822
- For example, the directive ~'tCc[red.yellow]'~ would title-case the element,
2475
+ For example, the directive 'tCc[red.yellow]' would title-case the element,
1823
2476
  center it, and color it red on a yellow background. The directives that are
1824
2477
  boolean have negating forms so that, for example, if bold is turned on for all
1825
2478
  columns of a given type, it can be countermanded in formatting directives for
1826
2479
  particular columns.
1827
2480
 
1828
2481
  **** Numeric
1829
-
1830
2482
  For a numeric element, all the instructions valid for string are available, in
1831
2483
  addition to the following:
1832
2484
 
@@ -1841,11 +2493,10 @@ addition to the following:
1841
2493
  will result in a :numeric expressed as seconds and can be displayed in
1842
2494
  hours, minutes, and seconds with this formatting instruction.
1843
2495
 
1844
- For example, the directive ~'R5.0c[blue]'~ would right-align the numeric
2496
+ For example, the directive 'R5.0c[blue]' would right-align the numeric
1845
2497
  element, pad it on the left with zeros, and color it blue.
1846
2498
 
1847
2499
  **** DateTime
1848
-
1849
2500
  For a ~DateTime~, all the instructions valid for string are available, in
1850
2501
  addition to the following:
1851
2502
 
@@ -1857,61 +2508,216 @@ addition to the following:
1857
2508
  component where fmt is a valid format string for Date#strftime, otherwise,
1858
2509
  the datetime will be formatted as an ISO 8601 string, YYYY-MM-DD.
1859
2510
 
1860
- For example, ~'c[pink]d[%b %-d, %Y]C'~, would format a date element like 'Sep
2511
+ For example, 'c[pink]d[%b %-d, %Y]C', would format a date element like 'Sep
1861
2512
  22, 1957', center it, and color it pink.
1862
2513
 
1863
2514
  **** Boolean
1864
-
1865
2515
  For a boolean cell, all the instructions valid for string are available, in
1866
2516
  addition to the following:
1867
2517
 
1868
- - Y :: print true as '~Y~' and false as '~N~',
1869
- - T :: print true as '~T~' and false as '~F~',
1870
- - X :: print true as '~X~' and false as an empty string '',
2518
+ - Y :: print true as ~Y~ and false as ~N~,
2519
+ - T :: print true as ~T~ and false as ~F~,
2520
+ - X :: print true as ~X~ and false as an empty string '',
1871
2521
  - b[xxx,yyy] :: print true as the string given as ~xxx~ and false as the string
1872
2522
  given as ~yyy~,
1873
2523
  - c[tcolor,fcolor] :: color a true element with ~tcolor~ and a false element
1874
2524
  with ~fcolor~. Each of the colors may be specified in the same manner as
1875
2525
  colors for strings described above.
1876
2526
 
1877
- For example, the directive '~b[Yeppers,Nope]c[green.pink,red.pink]~' would
1878
- render a true boolean as '~Yeppers~' colored green on pink and render a false
1879
- boolean as '~Nope~' colored red on pink. See [[https://www.youtube.com/watch?v=oLdFFD8II8U][Yeppers]] for additional information.
2527
+ For example, the directive 'b[Yeppers,Nope]c[green.pink,red.pink]' would
2528
+ render a true boolean as ~Yeppers~ colored green on pink and render a false
2529
+ boolean as ~Nope~ colored red on pink. See [[https://www.youtube.com/watch?v=oLdFFD8II8U][Yeppers]] for additional information.
1880
2530
 
1881
2531
  **** NilClass
1882
-
1883
2532
  By default, ~nil~ elements are rendered as blank cells, but you can make them
1884
2533
  visible with the following, and in that case, all the formatting instructions
1885
2534
  valid for strings are also available:
1886
2535
 
1887
2536
  - n[niltext] :: render a ~nil~ item with the given niltext.
1888
2537
 
1889
- For example, you might want to use ~'n[-]Cc[purple]'~ to make nils visible as a
2538
+ For example, you might want to use 'n[-]Cc[purple]' to make nils visible as a
1890
2539
  centered purple hyphen.
1891
2540
 
1892
- *** Footers Methods
2541
+ *** The ~format~ and ~format_for~ methods
2542
+ Formatters take only two kinds of methods, those that attach footers to a
2543
+ table, which are discussed in the next section, and those that specify
2544
+ formatting for table cells, which are the subject of this section.
2545
+
2546
+ To set formatting directives for all locations in a table at once, use the
2547
+ ~format~ method; to set formatting directives for a particular location in the
2548
+ table, use the ~format_for~ method, giving the location as the first
2549
+ parameter. See below at [[*Table Locations][Table Locations]] for an explanation of all the
2550
+ locations available.
1893
2551
 
1894
- You can call the ~footer~ and ~gfooter~ methods on ~Formatter~ objects to add
1895
- footers and group footers. Their signatures are:
2552
+ Other than that first parameter, the two methods take the same types of
2553
+ parameters. The remaining parameters are hash-like parameters that use either a
2554
+ column name or a type as the key and a string with the formatting directives to
2555
+ apply as the value. The following example says to set the formatting for all
2556
+ locations in the table and to format all numeric fields as strings that are
2557
+ rounded to whole numbers (the '0.0' part), that are right-aligned (the 'R'
2558
+ part), and have grouping commas inserted (the ',' part). But the ~:id~ column is
2559
+ numeric, and the second parameter overrides the formatting for numerics in
2560
+ general and calls for the ~:id~ column to be padded to three digits with zeros
2561
+ on the left (the '3.0' part) and to be centered (the 'C' part).
2562
+
2563
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2564
+ tab_a.to_text do |f|
2565
+ f.format(numeric: '0.0,R', id: '3.0C')
2566
+ f.format_for(:body, string: 'R')
2567
+ f.format_for(:header, string: 'C')
2568
+ end
2569
+ #+END_SRC
2570
+
2571
+ #+begin_EXAMPLE
2572
+ +=====+=======+=====+============+========+============+
2573
+ | Id | Name | Age | Address | Salary | Join Date |
2574
+ +-----+-------+-----+------------+--------+------------+
2575
+ | 001 | Paul | 32 | California | 20,000 | 2001-07-13 |
2576
+ | 003 | Teddy | 23 | Norway | 20,000 | 2007-12-13 |
2577
+ | 004 | Mark | 25 | Rich-Mond | 65,000 | 2007-12-13 |
2578
+ | 005 | David | 27 | Texas | 85,000 | 2007-12-13 |
2579
+ | 002 | Allen | 25 | Texas | | 2005-07-13 |
2580
+ | 008 | Paul | 24 | Houston | 20,000 | 2005-07-13 |
2581
+ | 009 | James | 44 | Norway | 5,000 | 2005-07-13 |
2582
+ | 010 | James | 45 | Texas | 5,000 | |
2583
+ +=====+=======+=====+============+========+============+
2584
+ #+end_EXAMPLE
2585
+
2586
+ In the example, the ~format~ method affects the whole table. Its ~numeric:~
2587
+ directive affected the ~:age~ and ~:salary~ columns because their types are
2588
+ Numeric. The ~id:~ column is also Numeric, but it's more specific directive
2589
+ takes precedence and it is formatted accordingly.
2590
+
2591
+ But the ~format_for~ methods affected two "locations": the "body" and the
2592
+ "header". Within the body, the ~:string~ directive calls for all strings to
2593
+ be right-aligned, but the headers are unaffected by it. The ~format_for~ the
2594
+ ~:header~ location caused all the headers to be centered.
2595
+
2596
+ All the other cells in the table, namely the cells in the ~:join_date~ column,
2597
+ had the default formatting applied.
2598
+
2599
+ **** Table Locations
2600
+ In the ~format_for~ formatting method, the first argument names a "location."
2601
+ The table is divided into several locations for which separate formatting
2602
+ directives may be given. These locations are identified by the following
2603
+ symbols:
2604
+
2605
+ - :header :: the first row of the output table containing the headers,
2606
+ - :footer :: all rows of the table's footers,
2607
+ - :gfooter :: all rows of the table's group footers,
2608
+ - :body :: all the data rows of the table, that is, those that are neither part
2609
+ of the header, footers, or gfooters,
2610
+ - :bfirst :: the first row of the table's body, and
2611
+ - :gfirst :: the first row in each group in the table's body.
2612
+
2613
+ **** Location priority
2614
+ Formatting for any given cell depends on its location in the table. The
2615
+ ~format_for~ method takes a location to which its formatting directive are
2616
+ restricted as the first argument. It can be one of the following:
2617
+
2618
+ - ~:header~ :: The directives apply only to the header row, that is the first
2619
+ row, of the output table; before the directives are applied, the header's
2620
+ symbol form is converted back into a string and capitalized as is a book
2621
+ title. Thus, only directives applicable to the String type have any effect.
2622
+
2623
+ - ~:body~ :: The directives apply to all rows in the body of the table.
2624
+
2625
+ - ~:gfirst~ :: directives apply to the first row in each group in the body of
2626
+ the table, unless the row is also the first row in the table as a whole, in
2627
+ which case the ~:bfirst~ directives apply,
2628
+
2629
+ - ~:bfirst~ :: The directives apply to the first row in the body of the table,
2630
+ taking precedence over those directives that apply to the body generally or
2631
+ the ~:gfirst~ directives that apply to the first row in each group.
2632
+
2633
+ - ~:footer~ :: The directives apply to all the footer rows of the output
2634
+ table, regardless of how many there are.
2635
+
2636
+ - ~gfooter~ :: The directives apply to all group footer rows of the output
2637
+ tables, regardless of how many there are.
2638
+
2639
+ Directives given to the ~format~ method apply the directives to all locations in
2640
+ the table, but they can be overridden by more specific directives given in a
2641
+ ~format_for~ directive.
2642
+
2643
+ **** Type and Column priority
2644
+ A directive based on type applies to all columns having that type unless
2645
+ overridden by a directive specific to a named column; a directive based on a
2646
+ column name applies only to cells in that column.
2647
+
2648
+ However, there is a twist. Since the end result of formatting is to convert
2649
+ all columns to strings, the formatting directives for the ~String~ type can
2650
+ be applied to all column types. Likewise, since all columns may contain nils,
2651
+ the ~NilClass:~ type applies to nils in all columns regardless of the column's
2652
+ type.
2653
+
2654
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2655
+ tab_a.to_text do |f|
2656
+ f.format(string: 'R', id: '3.0C', nil: 'Cn[-]', salary: 'n[N/A]')
2657
+ end
2658
+ #+END_SRC
2659
+
2660
+ #+BEGIN_EXAMPLE
2661
+ +=====+=======+=====+============+========+============+
2662
+ | Id | Name | Age | Address | Salary | Join Date |
2663
+ +-----+-------+-----+------------+--------+------------+
2664
+ | 001 | Paul | 32 | California | 20000 | 2001-07-13 |
2665
+ | 003 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
2666
+ | 004 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
2667
+ | 005 | David | 27 | Texas | 85000 | 2007-12-13 |
2668
+ | 002 | Allen | 25 | Texas | N/A | 2005-07-13 |
2669
+ | 008 | Paul | 24 | Houston | 20000 | 2005-07-13 |
2670
+ | 009 | James | 44 | Norway | 5000 | 2005-07-13 |
2671
+ | 010 | James | 45 | Texas | 5000 | |
2672
+ +=====+=======+=====+============+========+============+
2673
+ #+END_EXAMPLE
2674
+
2675
+ The ~string: 'R'~ directive causes all the cells to be right-aligned except
2676
+ ~:id~ which specifies centering for the ~:id~ column only. The ~n[N/A]~
2677
+ directive for specifies how nil are displayed in the numeric column, ~:salary~,
2678
+ but not for other nils, such as in the last row of the ~:join_date~ column.
2679
+
2680
+ *** Footers
2681
+ **** Adding Footers
2682
+ You can call the ~footer,~ ~gfooter, foot, and gfoot~ methods on ~Formatter~
2683
+ objects to add footers and group footers. Note that all of these methods
2684
+ return a ~Footer~ object that can be accessed to extract the computed values.
2685
+ All of these methods return the ~FatTable::Footer~ object so constructed. It
2686
+ can be used to access the values and other attributes of the footer
2687
+ computed. Their signatures are:
1896
2688
 
1897
2689
  - ~footer(label, *sum_cols, **agg_cols)~ :: where ~label~ is a label to be
1898
- placed in the first cell of the footer (unless that column is named as one
1899
- of the ~sum_cols~ or ~agg_cols~, in which case the label is ignored),
1900
- ~*sum_cols~ are zero or more symbols for columns to be summed, and
1901
- ~**agg_cols~ is zero or more hash-like parameters with a column symbol as a
1902
- key and a symbol for an aggregate method as the value. This causes a
1903
- table-wide header to be added at the bottom of the table applying the
1904
- ~:sum~ aggregate to the ~sum_cols~ and the named aggregate method to the
1905
- ~agg_cols~. A table can have any number of footers attached, and they will
1906
- appear at the bottom of the output table in the order they are given.
1907
-
1908
- - ~gfooter(label, *sum_cols, **agg_cols)~ :: where the parameters have the same
1909
- meaning as for the ~footer~ method, but result in a footer for each group
1910
- in the table rather than the table as a whole. These will appear in the
1911
- output table just below each group.
2690
+ placed in the first cell of the footer (unless that column is named as one
2691
+ of the ~sum_cols~ or ~agg_cols~, in which case the label is ignored),
2692
+ ~*sum_cols~ are zero or more symbols for columns to be summed, and
2693
+ ~**agg_cols~ is zero or more hash-like parameters with a column symbol as a
2694
+ key and a valid aggregate as the value. This causes a table-wide header to
2695
+ be added at the bottom of the table applying the ~:sum~ aggregate to the
2696
+ ~sum_cols~ and the named aggregate to the ~agg_cols~. A table can have any
2697
+ number of footers attached, and they will appear at the bottom of the output
2698
+ table in the order they are given.
2699
+
2700
+ - ~foot(label, label_col, **agg_cols)~ :: where ~label~ is a label to be
2701
+ placed in the column with header ~label_col~, or, if ommitted, in the first
2702
+ cell of the footer (unless that column is named as one of the ~agg_cols~, in
2703
+ which case the label is ignored), and ~**agg_cols~ is zero or more hash-like
2704
+ parameters with a column symbol as a key and a valid aggregate as the
2705
+ value. This causes a table-wide header to be added at the bottom of the
2706
+ table applying ~agg~, to the ~agg_cols~. A table can have any number of
2707
+ footers attached, and they will appear at the bottom of the output table in
2708
+ the order they are given.
2709
+
2710
+ - ~gfooter(label, *sum_cols, **agg_cols)~ :: where the parameters have the
2711
+ same meaning as for the ~footer~ method, but results in a footer for each
2712
+ group in the table rather than the table as a whole. These will appear in
2713
+ the output table just below each group.
2714
+
2715
+ - ~gfoot(label, label_col, **agg_cols)~ :: where the parameters have the same
2716
+ meaning as for the ~foot~ method, but results in a footer for each group in
2717
+ the table rather than the table as a whole. These will appear in the output
2718
+ table just below each group.
1912
2719
 
1913
2720
  There are also a number of convenience methods for adding common footers:
1914
-
1915
2721
  - ~sum_footer(*cols)~ :: Add a footer summing the given columns with the label
1916
2722
  'Total'.
1917
2723
  - ~sum_gfooter(*cols)~ :: Add a group footer summing the given columns with the
@@ -1929,22 +2735,324 @@ There are also a number of convenience methods for adding common footers:
1929
2735
  - ~max_gfooter(*cols)~ :: Add a group footer showing the maximum for the given
1930
2736
  columns with the label 'Group Maximum'.
1931
2737
 
1932
- *** Formatting Methods
2738
+ **** Aggregators
2739
+ When adding a footer with the above methods, you can specify an aggregator for
2740
+ each column named in the ~agg_cols~ parameter. There are several candidates
2741
+ for what you can use for an aggregator:
2742
+
2743
+ - Symbol :: one of the following built-in aggregators: :first, :last, :range,
2744
+ :sum, :count, :min, :max, :avg, :var, :pvar, :dev, :pdev, :any?, :all?,
2745
+ :none?, and :one?.
2746
+ + The symbols ending in a question mark are valid only for boolean columns;
2747
+ + :count, :first, and :last work with any column type,
2748
+ + :min, :max, and :range work with all types except boolean;
2749
+ + :sum, works only with numeric columns, and
2750
+ + :avg, :var, :dev, :pvar, and :pdev work with numeric or datetime columns.
2751
+ In the case of datetime columns, these aggrgators convert the dates to
2752
+ julian date numbers, perform the calculation, then convert the result back
2753
+ to a datetime object.
2754
+ - String :: using a string as an aggrgegator can result in:
2755
+ + the string being converted to an object matching the type of the column
2756
+ (for example, using '$1,888' in a numeric column puts the constant number
2757
+ 1888 in the footer field, using '1957-09-22' puts the fixed date in the
2758
+ field, etc.)
2759
+ + if the string cannot be parsed as a valid object matching the column's
2760
+ type, it is placed literally in the footer field (for example, using
2761
+ '(estimated)' can be used to add additional information to the footer)
2762
+ - Ruby object :: you can put a number in a numeric footer field, a DateTime
2763
+ object in a datetime footer field, or a true or false in a boolean footer
2764
+ field;
2765
+ - A Lambda :: finally, you can provide a lambda for performing arbitrary
2766
+ calculations and placing the result in the footer field. The number of
2767
+ arguments the lambda takes can vary:
2768
+ * If the lambda is used in a group footer, it must take a single integer
2769
+ argument that is set to the group number being calculated and /can/ take a
2770
+ second argument for the column symbol in which it appears, or
2771
+ * If the lambda is used in an ordinary footer, it either takes no arguments,
2772
+ or a single argument for the column symbol in which it appears.
2773
+
2774
+ **** Footer objects
2775
+ Each of the methods for adding a footer to a ~Formatter~ returns a ~Footer~ object
2776
+ that you can query for attributes of the generated footer, including accessing
2777
+ their computed values. Here are the accessors available on a
2778
+ ~FatTable::Footer~ object:
2779
+
2780
+ - ~[h]~ :: Return the value of under the ~h~ header, or if this is a group
2781
+ footer, return an array of the values for all the groups under the ~h~
2782
+ header.
2783
+ - .<header> :: like, ~[h]~ but makes the values available in method-call form.
2784
+ - ~number_of_groups~ :: Return the total number of groups in the table to
2785
+ which this footer belongs. Note that if the table has both group footers
2786
+ and normal footers, this will return the number of groups even for a normal
2787
+ footer.
2788
+ - ~column(h)~, ~column(h, k)~ :: Return a FatTable::Column object for the
2789
+ header h and, if the footer is a group footer, the kth group.
2790
+ - ~items(h)~, ~items(h, k)~ :: Return an Array of the values for the header
2791
+ ~h~ and, if a group, for the ~k~th group.
2792
+ - ~to_h~, ~to_h(k)~ :: Return a Hash with a key for each column header mapped
2793
+ to the footer value for that column, nil for unused columns. Use the index
2794
+ ~k~ to specify which group to access in the case of a group footer.
2795
+
2796
+
2797
+ **** Footer Examples
2798
+ As a reminder, here is the table, ~tab_a~ defined earlier:
2799
+
2800
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2801
+ tab_a.to_aoa
2802
+ #+END_SRC
1933
2803
 
1934
- You can call methods on ~Formatter~ objects to specify formatting directives
1935
- for specific columns or types. There are two methods for doing so, ~format_for~
1936
- and ~format~.
2804
+ #+begin_EXAMPLE
2805
+ | Id | Name | Age | Address | Salary | Join Date |
2806
+ |----+-------+-----+------------+--------+------------|
2807
+ | 1 | Paul | 32 | California | 20000 | 2001-07-13 |
2808
+ | 3 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
2809
+ | 4 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
2810
+ | 5 | David | 27 | Texas | 85000 | 2007-12-13 |
2811
+ | 2 | Allen | 25 | Texas | | 2005-07-13 |
2812
+ | 8 | Paul | 24 | Houston | 20000 | 2005-07-13 |
2813
+ | 9 | James | 44 | Norway | 5000 | 2005-07-13 |
2814
+ | 10 | James | 45 | Texas | 5000 | |
2815
+ #+end_EXAMPLE
1937
2816
 
1938
- **** Instantiating a Formatter
2817
+ ***** Built-in Aggregators
2818
+ You can add a footer compute the average of the given columns. You may be
2819
+ surprised that you can average a set of dates, but ~:avg~ simply converts the
2820
+ dates to Julian numbers, averages that, then converts the result back to a
2821
+ date.
2822
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2823
+ tab_a.to_text do |f|
2824
+ f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]')
2825
+ f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
2826
+ f.footer('Tally', age: :count)
2827
+ end
2828
+ #+END_SRC
1939
2829
 
1940
- There are several ways to invoke the formatting methods on a table. First, you
1941
- can instantiate a ~XXXFormatter~ object and feed it a table as a parameter.
1942
- There is a Formatter subclass for each target output medium, for example,
1943
- ~AoaFormatter~ will produce a ruby array of arrays. You can then call the
1944
- ~output~ method on the ~XXXFormatter~.
2830
+ #+begin_EXAMPLE
2831
+ +=========+=======+=====+============+========+=============+
2832
+ | Id | Name | Age | Address | Salary | Join Date |
2833
+ +---------+-------+-----+------------+--------+-------------+
2834
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 |
2835
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 |
2836
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 |
2837
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 |
2838
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 |
2839
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 |
2840
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 |
2841
+ | 10 | James | 45 | Texas | 5,000 | |
2842
+ +---------+-------+-----+------------+--------+-------------+
2843
+ | Average | | 31 | | 31,429 | 29-DEC-2005 |
2844
+ +---------+-------+-----+------------+--------+-------------+
2845
+ | Tally | | 8 | | | |
2846
+ +=========+=======+=====+============+========+=============+
2847
+ #+end_EXAMPLE
1945
2848
 
1946
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1947
- #+BEGIN_SRC ruby
2849
+ ***** String Aggregators
2850
+ If the string is convertible into its columns's type, it will be converted to
2851
+ that type; otherwise, it will be placed in the footer literally. This example
2852
+ also shows how the values from one footer might be used in composing another
2853
+ footer.
2854
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2855
+ tab_a.to_text do |f|
2856
+ f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]')
2857
+ avg_ft = f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
2858
+ f.footer('Tally', age: :count)
2859
+ if avg_ft[:salary] < 30000
2860
+ cmt = "We're saving"
2861
+ else
2862
+ cmt = "We're overspending"
2863
+ end
2864
+ f.footer('Pay', join_date: "We have #{avg_ft.number_of_groups} grp")
2865
+ f.footer('Group count', join_date: "We have #{avg_ft.number_of_groups} grp")
2866
+ f.footer('Comment', join_date: cmt)
2867
+ end
2868
+ #+END_SRC
2869
+
2870
+ #+begin_EXAMPLE
2871
+ +=============+=======+=====+============+========+====================+
2872
+ | Id | Name | Age | Address | Salary | Join Date |
2873
+ +-------------+-------+-----+------------+--------+--------------------+
2874
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 |
2875
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 |
2876
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 |
2877
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 |
2878
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 |
2879
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 |
2880
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 |
2881
+ | 10 | James | 45 | Texas | 5,000 | |
2882
+ +-------------+-------+-----+------------+--------+--------------------+
2883
+ | Average | | 31 | | 31,429 | 29-DEC-2005 |
2884
+ +-------------+-------+-----+------------+--------+--------------------+
2885
+ | Tally | | 8 | | | |
2886
+ +-------------+-------+-----+------------+--------+--------------------+
2887
+ | Pay | | | | | We have 1 grp |
2888
+ +-------------+-------+-----+------------+--------+--------------------+
2889
+ | Group count | | | | | We have 1 grp |
2890
+ +-------------+-------+-----+------------+--------+--------------------+
2891
+ | Comment | | | | | We're overspending |
2892
+ +=============+=======+=====+============+========+====================+
2893
+ #+end_EXAMPLE
2894
+
2895
+ ***** Ruby Objects
2896
+ You can make the aggregator an normal ruby object, in which case it is just
2897
+ inserted into the footer at the requested location. If its type is the same
2898
+ as the column type, it participates in the formatting for that type and
2899
+ column.
2900
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2901
+ tab_a.to_text do |f|
2902
+ f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
2903
+ f.footer('Report Date', age: :count, join_date: Date.today)
2904
+ f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]')
2905
+ end
2906
+ #+END_SRC
2907
+
2908
+ #+begin_EXAMPLE
2909
+ +=============+=======+=====+============+========+=============+
2910
+ | Id | Name | Age | Address | Salary | Join Date |
2911
+ +-------------+-------+-----+------------+--------+-------------+
2912
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 |
2913
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 |
2914
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 |
2915
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 |
2916
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 |
2917
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 |
2918
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 |
2919
+ | 10 | James | 45 | Texas | 5,000 | |
2920
+ +-------------+-------+-----+------------+--------+-------------+
2921
+ | Average | | 31 | | 31,429 | 29-DEC-2005 |
2922
+ +-------------+-------+-----+------------+--------+-------------+
2923
+ | Report Date | | 8 | | | 20-JAN-2022 |
2924
+ +=============+=======+=====+============+========+=============+
2925
+ #+end_EXAMPLE
2926
+
2927
+ But it can be any type. Here we pick a lottery winner from the employee ids.
2928
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2929
+ tab_a.to_text do |f|
2930
+ f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
2931
+ winner_id = tab_a.column(:id).items.sample
2932
+ f.footer('Lottery Winner', age: :count, join_date: winner_id)
2933
+ f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]')
2934
+ end
2935
+ #+END_SRC
2936
+
2937
+ #+begin_EXAMPLE
2938
+ +================+=======+=====+============+========+=============+
2939
+ | Id | Name | Age | Address | Salary | Join Date |
2940
+ +----------------+-------+-----+------------+--------+-------------+
2941
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 |
2942
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 |
2943
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 |
2944
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 |
2945
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 |
2946
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 |
2947
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 |
2948
+ | 10 | James | 45 | Texas | 5,000 | |
2949
+ +----------------+-------+-----+------------+--------+-------------+
2950
+ | Average | | 31 | | 31,429 | 29-DEC-2005 |
2951
+ +----------------+-------+-----+------------+--------+-------------+
2952
+ | Lottery Winner | | 8 | | | 4 |
2953
+ +================+=======+=====+============+========+=============+
2954
+ #+end_EXAMPLE
2955
+
2956
+ ***** Lambdas
2957
+ Perhaps the most flexible form of aggregator is a lambda form. They require 2
2958
+ or 3 parameters in non-group and group footers, respectively:
2959
+
2960
+ - ~->(f, c) {...}~ :: in a normal, non-group footer, you must provide for two
2961
+ paramters: the first, ~f~, will be bound to the footer in which the lambda
2962
+ appears and the second, ~c~, will be bound to the column header to which the
2963
+ lambda is attached.
2964
+ - ~->(f, c, k)~ :: in a group footer, you must provide for three paramters:
2965
+ the first, ~f~, will be bound to the footer in which the lambda appears, the
2966
+ second, ~c~, will be bound to the column header to which the lambda is
2967
+ attached, and the third, ~k~ will be bound to the group number of the group
2968
+ being evaluated.
2969
+
2970
+ With the first argument, the footer itself becomes available and with it all
2971
+ the things accessible with the footers, including the items in the current
2972
+ column, through the ~f.items(c)~ accessor.
2973
+
2974
+ Compute the summ of the squares if the items in the ~:age~ column:
2975
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2976
+ tab_a.to_text do |f|
2977
+ f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]')
2978
+ f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
2979
+ f.footer('SSQ', age: ->(f, c) { sa = f.items(c).map {|x| x * x}.sum; Math.sqrt(sa) })
2980
+ end
2981
+ #+END_SRC
2982
+
2983
+ #+begin_EXAMPLE
2984
+ +=========+=======+=====+============+========+=============+
2985
+ | Id | Name | Age | Address | Salary | Join Date |
2986
+ +---------+-------+-----+------------+--------+-------------+
2987
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 |
2988
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 |
2989
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 |
2990
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 |
2991
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 |
2992
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 |
2993
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 |
2994
+ | 10 | James | 45 | Texas | 5,000 | |
2995
+ +---------+-------+-----+------------+--------+-------------+
2996
+ | Average | | 31 | | 31,429 | 29-DEC-2005 |
2997
+ +---------+-------+-----+------------+--------+-------------+
2998
+ | SSQ | | 90 | | | |
2999
+ +=========+=======+=====+============+========+=============+
3000
+ #+end_EXAMPLE
3001
+
3002
+ Group the table according to the employee's year of joining, then compute the
3003
+ summ of the squares if the ages in each group:
3004
+ #+BEGIN_SRC ruby :wrap EXAMPLE
3005
+ tab_a.order_with('join_date.year').to_text do |f|
3006
+ f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]', sort_key: '0.0~,')
3007
+ f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
3008
+ f.gfooter('Group SSQ', age: ->(f, c, k) { sa = f.items(c, k).map {|x| x * x}.sum; Math.sqrt(sa) })
3009
+ f.footer('Total SSQ', age: ->(f, c) { sa = f.items(c).map {|x| x * x}.sum; Math.sqrt(sa) })
3010
+ end
3011
+ #+END_SRC
3012
+
3013
+ #+begin_EXAMPLE
3014
+ +===========+=======+=====+============+========+=============+==========+
3015
+ | Id | Name | Age | Address | Salary | Join Date | Sort Key |
3016
+ +-----------+-------+-----+------------+--------+-------------+----------+
3017
+ | 10 | James | 45 | Texas | 5,000 | | |
3018
+ +-----------+-------+-----+------------+--------+-------------+----------+
3019
+ | Group SSQ | | 45 | | | | |
3020
+ +-----------+-------+-----+------------+--------+-------------+----------+
3021
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 | 2001 |
3022
+ +-----------+-------+-----+------------+--------+-------------+----------+
3023
+ | Group SSQ | | 32 | | | | |
3024
+ +-----------+-------+-----+------------+--------+-------------+----------+
3025
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 | 2005 |
3026
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 | 2005 |
3027
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 | 2005 |
3028
+ +-----------+-------+-----+------------+--------+-------------+----------+
3029
+ | Group SSQ | | 56 | | | | |
3030
+ +-----------+-------+-----+------------+--------+-------------+----------+
3031
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 | 2007 |
3032
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 | 2007 |
3033
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 | 2007 |
3034
+ +-----------+-------+-----+------------+--------+-------------+----------+
3035
+ | Group SSQ | | 43 | | | | |
3036
+ +-----------+-------+-----+------------+--------+-------------+----------+
3037
+ | Average | | 31 | | 31,429 | 29-DEC-2005 | |
3038
+ +-----------+-------+-----+------------+--------+-------------+----------+
3039
+ | Total SSQ | | 90 | | | | |
3040
+ +===========+=======+=====+============+========+=============+==========+
3041
+ #+end_EXAMPLE
3042
+
3043
+ *** Invoking Formatters
3044
+ As the examples show, one way to invoke the formatting methods is simply to
3045
+ call one of the ~to_xxx~ methods directly on a table, which will yield a
3046
+ ~FatTable::Formatter~ object to the block, and that is often the most
3047
+ convenient way to do it. But there are a few other ways.
3048
+
3049
+ **** By Instantiating a Formatter
3050
+ You can instantiate a ~XXXFormatter~ object and feed it a table as a
3051
+ parameter. There is a Formatter subclass for each target output medium, for
3052
+ example, ~AoaFormatter~ will produce a ruby array of arrays. You can then call
3053
+ the ~output~ method on the ~XXXFormatter~.
3054
+
3055
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1948
3056
  FatTable::AoaFormatter.new(tab_a).output
1949
3057
  #+END_SRC
1950
3058
 
@@ -1964,8 +3072,7 @@ There is a Formatter subclass for each target output medium, for example,
1964
3072
  The ~XXXFormatter.new~ method yields the new instance to any block given, and
1965
3073
  you can call methods on it to affect the formatting of the output:
1966
3074
 
1967
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1968
- #+BEGIN_SRC ruby
3075
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1969
3076
  FatTable::AoaFormatter.new(tab_a) do |f|
1970
3077
  f.format(numeric: '0.0,R', id: '3.0C')
1971
3078
  end.output
@@ -1984,15 +3091,13 @@ you can call methods on it to affect the formatting of the output:
1984
3091
  | 010 | James | 45 | Texas | 5,000 | |
1985
3092
  #+END_EXAMPLE
1986
3093
 
1987
- **** ~FatTable~ module-level method calls
1988
-
3094
+ **** By Using ~FatTable~ module-level method calls
1989
3095
  The ~FatTable~ module provides a set of methods of the form ~to_aoa~, ~to_text~,
1990
3096
  etc., to access a ~Formatter~ without having to create an instance yourself.
1991
3097
  Without a block, they apply the default formatting to the table and call the
1992
3098
  ~.output~ method automatically:
1993
3099
 
1994
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
1995
- #+BEGIN_SRC ruby
3100
+ #+BEGIN_SRC ruby :wrap EXAMPLE
1996
3101
  FatTable.to_aoa(tab_a)
1997
3102
  #+END_SRC
1998
3103
 
@@ -2013,8 +3118,7 @@ With a block, these methods yield a ~Formatter~ instance on which you can call
2013
3118
  formatting and footer methods. The ~.output~ method is called on the ~Formatter~
2014
3119
  automatically after the block:
2015
3120
 
2016
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
2017
- #+BEGIN_SRC ruby
3121
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2018
3122
  FatTable.to_aoa(tab_a) do |f|
2019
3123
  f.format(numeric: '0.0,R', id: '3.0C')
2020
3124
  end
@@ -2033,13 +3137,11 @@ automatically after the block:
2033
3137
  | 010 | James | 45 | Texas | 5,000 | |
2034
3138
  #+END_EXAMPLE
2035
3139
 
2036
- **** Calling methods on Table objects
2037
-
2038
- Finally, you can call methods such as ~to_aoa~, ~to_text~, etc., directly on a
2039
- Table:
3140
+ **** By Calling Methods on Table Objects
3141
+ Finally, as in many of the examples, you can call methods such as ~to_aoa~,
3142
+ ~to_text~, etc., directly on a Table:
2040
3143
 
2041
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
2042
- #+BEGIN_SRC ruby
3144
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2043
3145
  tab_a.to_aoa
2044
3146
  #+END_SRC
2045
3147
 
@@ -2058,8 +3160,7 @@ Table:
2058
3160
 
2059
3161
  And you can supply a block to them as well to specify formatting or footers:
2060
3162
 
2061
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
2062
- #+BEGIN_SRC ruby
3163
+ #+BEGIN_SRC ruby :wrap EXAMPLE
2063
3164
  tab_a.to_aoa do |f|
2064
3165
  f.format(numeric: '0.0,R', id: '3.0C')
2065
3166
  f.sum_footer(:salary, :age)
@@ -2081,135 +3182,13 @@ And you can supply a block to them as well to specify formatting or footers:
2081
3182
  | Total | | 245 | | 220,000 | |
2082
3183
  #+END_EXAMPLE
2083
3184
 
2084
- *** The ~format~ and ~format_for~ methods
2085
-
2086
- Formatters take only two kinds of methods, those that attach footers to a
2087
- table, which are discussed in the next section, and those that specify
2088
- formatting for table cells, which are the subject of this section.
2089
-
2090
- To set formatting directives for all locations in a table at once, use the
2091
- ~format~ method; to set formatting directives for a particular location in the
2092
- table, use the ~format_for~ method, giving the location as the first parameter.
2093
-
2094
- Other than that first parameter, the two methods take the same types of
2095
- parameters. The remaining parameters are hash-like parameters that use either a
2096
- column name or a type as the key and a string with the formatting directives to
2097
- apply as the value. The following example says to set the formatting for all
2098
- locations in the table and to format all numeric fields as strings that are
2099
- rounded to whole numbers (the '0.0' part), that are right-aligned (the 'R'
2100
- part), and have grouping commas inserted (the ',' part). But the ~:id~ column is
2101
- numeric, and the second parameter overrides the formatting for numerics in
2102
- general and calls for the ~:id~ column to be padded to three digits with zeros
2103
- on the left (the '3.0' part) and to be centered (the 'C' part).
2104
-
2105
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
2106
- #+BEGIN_SRC ruby
2107
- tab_a.to_aoa do |f|
2108
- f.format(numeric: '0.0,R', id: '3.0C')
2109
- end
2110
- #+END_SRC
2111
-
2112
- #+BEGIN_EXAMPLE
2113
- | Id | Name | Age | Address | Salary | Join Date |
2114
- |-----+-------+-----+------------+--------+------------|
2115
- | 001 | Paul | 32 | California | 20,000 | 2001-07-13 |
2116
- | 003 | Teddy | 23 | Norway | 20,000 | 2007-12-13 |
2117
- | 004 | Mark | 25 | Rich-Mond | 65,000 | 2007-12-13 |
2118
- | 005 | David | 27 | Texas | 85,000 | 2007-12-13 |
2119
- | 002 | Allen | 25 | Texas | | 2005-07-13 |
2120
- | 008 | Paul | 24 | Houston | 20,000 | 2005-07-13 |
2121
- | 009 | James | 44 | Norway | 5,000 | 2005-07-13 |
2122
- | 010 | James | 45 | Texas | 5,000 | |
2123
- #+END_EXAMPLE
2124
-
2125
- The ~numeric:~ directive affected the ~:age~ and ~:salary~ columns and the ~id:~
2126
- directive affected only the ~:id~ column. All the other cells in the table had
2127
- the default formatting applied.
2128
-
2129
- **** Location priority
2130
-
2131
- Formatting for any given cell depends on its location in the table. The
2132
- ~format_for~ method takes a location to which its formatting directive are
2133
- restricted as the first argument. It can be one of the following:
2134
-
2135
- - ~:header~ :: directive apply only to the header row, that is the first row, of
2136
- the output table,
2137
-
2138
- - ~:footer~ :: directives apply to all the footer rows of the output table,
2139
- regardless of how many there are,
2140
-
2141
- - ~gfooter~ :: directives apply to all group footer rows of the output tables,
2142
- regardless of how many there are,
2143
-
2144
- - ~:body~ :: directives apply to all rows in the body of the table unless the
2145
- row is the first row in the table or in a group and separate directives for
2146
- those have been given, in which case those directives apply,
2147
-
2148
- - ~:gfirst~ :: directives apply to the first row in each group in the body of
2149
- the table, unless the row is also the first row in the table as a whole, in
2150
- which case the ~:bfirst~ directives apply,
2151
-
2152
- - ~:bfirst~ :: directives apply to the first row in the body of the table.
2153
-
2154
- If you give directives for ~:body~, they are copied to ~:bfirst~ and ~:gfirst~
2155
- as well and can be overridden by directives for those locations.
2156
-
2157
- Directives given to the ~format~ method apply the directives to all locations in
2158
- the table, but they can be overridden by more specific directives given in a
2159
- ~format_for~ directive.
2160
-
2161
- **** Type and Column priority
2162
-
2163
- A directive based on type applies to all columns having that type unless
2164
- overridden by a directive specific to a named column; a directive based on a
2165
- column name applies only to cells in that column.
2166
-
2167
- However, there is a twist. Since the end result of formatting is to convert all
2168
- columns to strings, the formatting directives for the ~:string~ type applies to
2169
- all columns. Likewise, since all columns may contain nils, the ~nil:~ type
2170
- applies to nils in all columns regardless of the column's type.
2171
-
2172
- #+HEADER: :colnames no :session readme :hlines yes :wrap EXAMPLE :exports both
2173
- #+BEGIN_SRC ruby
2174
- require 'fat_table'
2175
- tab_a.to_text do |f|
2176
- f.format(string: 'R', id: '3.0C', salary: 'n[N/A]')
2177
- end
2178
- #+END_SRC
2179
-
2180
- #+BEGIN_EXAMPLE
2181
- +=====+=======+=====+============+========+============+
2182
- | Id | Name | Age | Address | Salary | Join Date |
2183
- +-----+-------+-----+------------+--------+------------+
2184
- | 001 | Paul | 32 | California | 20000 | 2001-07-13 |
2185
- | 003 | Teddy | 23 | Norway | 20000 | 2007-12-13 |
2186
- | 004 | Mark | 25 | Rich-Mond | 65000 | 2007-12-13 |
2187
- | 005 | David | 27 | Texas | 85000 | 2007-12-13 |
2188
- | 002 | Allen | 25 | Texas | N/A | 2005-07-13 |
2189
- | 008 | Paul | 24 | Houston | 20000 | 2005-07-13 |
2190
- | 009 | James | 44 | Norway | 5000 | 2005-07-13 |
2191
- | 010 | James | 45 | Texas | 5000 | |
2192
- +=====+=======+=====+============+========+============+
2193
- #+END_EXAMPLE
2194
-
2195
- The ~string: 'R'~ directive causes all the cells to be right-aligned except
2196
- ~:id~ which specifies centering for the ~:id~ column only. The ~n[N/A]~
2197
- directive for specifies how nil are displayed in the numeric column, ~:salary~,
2198
- but not for other nils, such as in the last row of the ~:join_date~ column.
2199
-
2200
3185
  * Development
2201
-
2202
3186
  After checking out the repo, run `bin/setup` to install dependencies. Then, run
2203
3187
  `rake spec` to run the tests. You can also run `bin/console` for an interactive
2204
3188
  prompt that will allow you to experiment.
2205
3189
 
2206
- To install this gem onto your local machine, run `bundle exec rake install`. To
2207
- release a new version, update the version number in `version.rb`, and then run
2208
- `bundle exec rake release`, which will create a git tag for the version, push
2209
- git commits and tags, and push the `.gem` file to
2210
- [rubygems.org](https://rubygems.org).
3190
+ To install this gem onto your local machine, run `bundle exec rake install`.
2211
3191
 
2212
3192
  * Contributing
2213
-
2214
3193
  Bug reports and pull requests are welcome on GitHub at
2215
3194
  https://github.com/ddoherty03/fat_table.