fat_table 0.5.5 → 0.6.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 2f391d5e4ad9d7a4dcb303098b90f6fb42379d9df382192c4bacaf169523dab1
4
- data.tar.gz: ea75f906fcd164752a3ca2220324ad10d8438562bb31c4846bc6575723e834fa
3
+ metadata.gz: f348d317c061becae08890ff02cc9c08789787d966f9ed88f3a4ef22b6eddb44
4
+ data.tar.gz: bf672b4f4f4ab07df465d06904ccebb9b48507177dc88a343eb09bfb0e98bc02
5
5
  SHA512:
6
- metadata.gz: 2914c40a497cf24bcdba8868c4a4607ea1bdb0a94fba8caa3d6e31407ff6832621df2a0b4a8a2bb98c3b40080fed6d752f8e936f66a96270fe675e93d5a852d6
7
- data.tar.gz: dbc43f4d2bac4a2a19bc7cc90d1fbfbf739a12f0f280a543670af588cfcf2bb0df74d50cfb7ded76b851f5470fd30d4f971659cead5131f9ea15e24b492e5823
6
+ metadata.gz: c721233a04cc1664e8d8acea3cf677190aa47da30b3db7e1b9f6c13ddd56028a8ecd8b0c71915d0a1703f46fc9a22a1c3a8a3f13d6c80fb07964a22fd864ab7e
7
+ data.tar.gz: 7877d4529d8a6f2a13ee0a1518730791b4e5ed7dbadd2030367593c95ccdbd5159e711f7ffe69b9b2fa9b4812a6f49d3d1a9fce46642e4454f54ff40d769a4cb
data/README.org CHANGED
@@ -31,8 +31,9 @@ The following is for org.
31
31
  "Current version is: #{FatTable::VERSION}"
32
32
  #+end_src
33
33
 
34
+ #+RESULTS:
34
35
  #+begin_EXAMPLE
35
- Current version is: 0.5.4
36
+ Current version is: 0.6.0
36
37
  #+end_EXAMPLE
37
38
 
38
39
  * Introduction
@@ -148,6 +149,7 @@ org-mode buffer as an org-table, ready for processing by other code blocks.
148
149
  - [[#type-and-column-priority][Type and Column priority]]
149
150
  - [[#footers][Footers]]
150
151
  - [[#adding-footers][Adding Footers]]
152
+ - [[#dynamic-labels][Dynamic Labels]]
151
153
  - [[#aggregators][Aggregators]]
152
154
  - [[#footer-objects][Footer objects]]
153
155
  - [[#footer-examples][Footer Examples]]
@@ -534,6 +536,7 @@ You can create an empty table with ~FatTable::Table.new~ or, the shorter form,
534
536
  in the added rows determine the names of the headers:
535
537
 
536
538
  #+BEGIN_SRC ruby :results silent
539
+ require 'fat_table'
537
540
  tab = FatTable.new
538
541
  tab << { a: 1, b: 2, c: "<2017-01-21>", d: 'f', e: '' }
539
542
  tab << { a: 3.14, b: 2.17, c: '[2016-01-21 Thu]', d: 'Y', e: nil }
@@ -1754,8 +1757,6 @@ available in ~ft_console~ as ~@tab_a~ and ~@tab_b~:
1754
1757
  | 2 | Engineering | 2 |
1755
1758
  | 3 | Finance | 7 |
1756
1759
  EOS
1757
-
1758
- tab_b = FatTable.from_org_string(tab_b_str)
1759
1760
  #+END_SRC
1760
1761
 
1761
1762
  Here is ~tab_a~:
@@ -2465,7 +2466,6 @@ Finance&
2465
2466
  {:id=>"3", :dept=>"Finance", :emp_id=>"7"}]
2466
2467
  #+end_EXAMPLE
2467
2468
 
2468
-
2469
2469
  *** Formatting Directives
2470
2470
  The formatting methods explained in the next section all take formatting
2471
2471
  directives as strings in which letters and other characters signify what
@@ -2706,12 +2706,27 @@ but not for other nils, such as in the last row of the ~:join_date~ column.
2706
2706
 
2707
2707
  *** Footers
2708
2708
  **** Adding Footers
2709
- You can call the ~footer,~ ~gfooter, foot, and gfoot~ methods on ~Formatter~
2710
- objects to add footers and group footers. Note that all of these methods
2711
- return a ~Footer~ object that can be accessed to extract the computed values.
2712
- All of these methods return the ~FatTable::Footer~ object so constructed. It
2713
- can be used to access the values and other attributes of the footer
2714
- computed. Their signatures are:
2709
+ You can call the ~foot~, ~gfoot~, ~footer,~ or ~gfooter~, methods on
2710
+ ~Formatter~ objects to add footers and group footers. Note that all of these
2711
+ methods return a ~Footer~ object that can be accessed to extract the computed
2712
+ values. All of these methods return the ~FatTable::Footer~ object so
2713
+ constructed. It can be used to access the values and other attributes of the
2714
+ footer computed. Their signatures are:
2715
+
2716
+ - ~foot(label: label, label_col: nil, **agg_cols)~ :: where ~label~ is a label
2717
+ to be placed in the column with header ~label_col~, or, if ommitted, in the
2718
+ first cell of the footer (unless that column is named as one of the
2719
+ ~agg_cols~, in which case the label is ignored), and ~**agg_cols~ is zero or
2720
+ more hash-like parameters with a column symbol as a key and a valid
2721
+ aggregate as the value. This causes a table-wide header to be added at the
2722
+ bottom of the table applying ~agg~, to the ~agg_cols~. A table can have any
2723
+ number of footers attached, and they will appear at the bottom of the output
2724
+ table in the order they are given.
2725
+
2726
+ - ~gfoot(label: 'Group Total', label_col: nil, **agg_cols)~ :: where the
2727
+ parameters have the same meaning as for the ~foot~ method, but results in a
2728
+ footer for each group in the table rather than the table as a whole. These
2729
+ will appear in the output table just below each group.
2715
2730
 
2716
2731
  - ~footer(label, *sum_cols, **agg_cols)~ :: where ~label~ is a label to be
2717
2732
  placed in the first cell of the footer (unless that column is named as one
@@ -2724,26 +2739,11 @@ computed. Their signatures are:
2724
2739
  number of footers attached, and they will appear at the bottom of the output
2725
2740
  table in the order they are given.
2726
2741
 
2727
- - ~foot(label, label_col, **agg_cols)~ :: where ~label~ is a label to be
2728
- placed in the column with header ~label_col~, or, if ommitted, in the first
2729
- cell of the footer (unless that column is named as one of the ~agg_cols~, in
2730
- which case the label is ignored), and ~**agg_cols~ is zero or more hash-like
2731
- parameters with a column symbol as a key and a valid aggregate as the
2732
- value. This causes a table-wide header to be added at the bottom of the
2733
- table applying ~agg~, to the ~agg_cols~. A table can have any number of
2734
- footers attached, and they will appear at the bottom of the output table in
2735
- the order they are given.
2736
-
2737
2742
  - ~gfooter(label, *sum_cols, **agg_cols)~ :: where the parameters have the
2738
2743
  same meaning as for the ~footer~ method, but results in a footer for each
2739
2744
  group in the table rather than the table as a whole. These will appear in
2740
2745
  the output table just below each group.
2741
2746
 
2742
- - ~gfoot(label, label_col, **agg_cols)~ :: where the parameters have the same
2743
- meaning as for the ~foot~ method, but results in a footer for each group in
2744
- the table rather than the table as a whole. These will appear in the output
2745
- table just below each group.
2746
-
2747
2747
  There are also a number of convenience methods for adding common footers:
2748
2748
  - ~sum_footer(*cols)~ :: Add a footer summing the given columns with the label
2749
2749
  'Total'.
@@ -2762,6 +2762,39 @@ There are also a number of convenience methods for adding common footers:
2762
2762
  - ~max_gfooter(*cols)~ :: Add a group footer showing the maximum for the given
2763
2763
  columns with the label 'Group Maximum'.
2764
2764
 
2765
+ **** Dynamic Labels
2766
+ Most of the time, you will want a fixed string as the label. However,
2767
+ especially in the case of a group footer, you might want a dynamically
2768
+ contructed label. You can use a proc or lambda for a label, and it will be
2769
+ computed for you. In the case of non-group footers, the proc takes a single
2770
+ parameter, the footer object itself. This allows you to make the label a
2771
+ function of other footer values, for example, you could make the label
2772
+ include the most recent year from the date column:
2773
+
2774
+ #+begin_src ruby
2775
+ fmtr.foot(label: -> (f) { "Average (latest year #{f.column(:date).max.year})" },
2776
+ temp: :avg)
2777
+ #+end_src
2778
+
2779
+ In the case of a group footer, the lambda or proc may take either one or qtwo parameters.
2780
+ If it takes one, the parameter is simply the 0-based number of the group:
2781
+
2782
+ #+begin_src ruby
2783
+ fmtr.gfoot(label: -> (k) { "Group #{(k+1).to_roman} Average" }, temp: :avg)
2784
+ #+end_src
2785
+ This would format the label with a roman numeral (assuming you defined a
2786
+ method to do so) for the group number.
2787
+
2788
+ If it takes two arguments, the second argument is the footer itself, as with
2789
+ non-group footers:
2790
+
2791
+ #+begin_src ruby
2792
+ fmtr.gfoot(label: -> (k, f) { "Year #{f.column(:date, k).max.year} Group #{(k+1).to_roman} Average" },
2793
+ temp: :avg)
2794
+ #+end_src
2795
+ This would add the group's year to label, assuming the :date column of the
2796
+ footer's table had the same year for each item in the group.
2797
+
2765
2798
  **** Aggregators
2766
2799
  When adding a footer with the above methods, you can specify an aggregator for
2767
2800
  each column named in the ~agg_cols~ parameter. There are several candidates
@@ -2778,6 +2811,9 @@ for what you can use for an aggregator:
2778
2811
  In the case of datetime columns, these aggrgators convert the dates to
2779
2812
  julian date numbers, perform the calculation, then convert the result back
2780
2813
  to a datetime object.
2814
+ Apart from the built-in aggrgators, you could define your own by opening the
2815
+ FatTable::Column class and adding a suitable instance method. In that
2816
+ case, the symbol could also refer to the method you defined.
2781
2817
  - String :: using a string as an aggrgegator can result in:
2782
2818
  + the string being converted to an object matching the type of the column
2783
2819
  (for example, using '$1,888' in a numeric column puts the constant number
@@ -2792,11 +2828,16 @@ for what you can use for an aggregator:
2792
2828
  - A Lambda :: finally, you can provide a lambda for performing arbitrary
2793
2829
  calculations and placing the result in the footer field. The number of
2794
2830
  arguments the lambda takes can vary:
2795
- * If the lambda is used in a group footer, it must take a single integer
2796
- argument that is set to the group number being calculated and /can/ take a
2797
- second argument for the column symbol in which it appears, or
2798
- * If the lambda is used in an ordinary footer, it either takes no arguments,
2799
- or a single argument for the column symbol in which it appears.
2831
+ * If the lambda is used in an ordinary footer column, it can take 0, 1, or 2
2832
+ arguments: (1) the first argument, if given, will be set to the
2833
+ FatTable::Column object for that column and (2) the second argument, if
2834
+ given, will be set to the Footer object itself.
2835
+ * If the lambda is used in a group footer column, it can 0, 1, 2, or 3
2836
+ arguments: (1) the first argument, if given, will be set to the group's
2837
+ 0-based index number, (2) the second argument, if given, will be set to a
2838
+ FatTable::Column object consisting of those items in the group's column,
2839
+ and (3) the third argument, if given, will be set to the Footer object
2840
+ itself.
2800
2841
 
2801
2842
  **** Footer objects
2802
2843
  Each of the methods for adding a footer to a ~Formatter~ returns a ~Footer~ object
@@ -2820,7 +2861,6 @@ their computed values. Here are the accessors available on a
2820
2861
  to the footer value for that column, nil for unused columns. Use the index
2821
2862
  ~k~ to specify which group to access in the case of a group footer.
2822
2863
 
2823
-
2824
2864
  **** Footer Examples
2825
2865
  As a reminder, here is the table, ~tab_a~ defined earlier:
2826
2866
 
@@ -2981,18 +3021,20 @@ But it can be any type. Here we pick a lottery winner from the employee ids.
2981
3021
  #+end_EXAMPLE
2982
3022
 
2983
3023
  ***** Lambdas
2984
- Perhaps the most flexible form of aggregator is a lambda form. They require 2
2985
- or 3 parameters in non-group and group footers, respectively:
2986
-
2987
- - ~->(f, c) {...}~ :: in a normal, non-group footer, you must provide for two
2988
- paramters: the first, ~f~, will be bound to the footer in which the lambda
2989
- appears and the second, ~c~, will be bound to the column header to which the
2990
- lambda is attached.
2991
- - ~->(f, c, k)~ :: in a group footer, you must provide for three paramters:
2992
- the first, ~f~, will be bound to the footer in which the lambda appears, the
2993
- second, ~c~, will be bound to the column header to which the lambda is
2994
- attached, and the third, ~k~ will be bound to the group number of the group
2995
- being evaluated.
3024
+ Perhaps the most flexible form of aggregator is a lambda form. They can take
3025
+ up to 2 or up to 3 parameters in non-group and group footers, respectively:
3026
+
3027
+ - ~->(c, f) {...}~ :: in a normal, non-group footer, you may provide for up to
3028
+ two paramters: the first, ~c~, if given, will be bound to the column header
3029
+ to which the lambda is attached and and the second, ~f~, if given will be
3030
+ bound to the footer in which the lambda appears. A lambda with no
3031
+ parameters can be provided as well if none are needed.
3032
+ - ~->(k, c, f)~ :: in a group footer, you may provide for up to three
3033
+ paramters: the the first, ~k~, if provided, will be bound to the group
3034
+ number of the group being evaluated, the second, ~c~, if provided, will be
3035
+ bound to the column header to which the lambda is attached, and the third,
3036
+ ~f~, will be bound to the footer in which the lambda appears. A lambda with
3037
+ no parameters can be provided as well if none are needed.
2996
3038
 
2997
3039
  With the first argument, the footer itself becomes available and with it all
2998
3040
  the things accessible with the footers, including the items in the current
@@ -3003,7 +3045,7 @@ Compute the summ of the squares if the items in the ~:age~ column:
3003
3045
  tab_a.to_text do |f|
3004
3046
  f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]')
3005
3047
  f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
3006
- f.footer('SSQ', age: ->(f, c) { sa = f.items(c).map {|x| x * x}.sum; Math.sqrt(sa) })
3048
+ f.footer('SSQ', age: ->(c) { sa = c.items.map {|x| x * x}.sum; Math.sqrt(sa) })
3007
3049
  end
3008
3050
  #+END_SRC
3009
3051
 
@@ -3032,8 +3074,8 @@ summ of the squares if the ages in each group:
3032
3074
  tab_a.order_with('join_date.year').to_text do |f|
3033
3075
  f.format(numeric: '0.0R,', datetime: 'd[%v]D[%v]', sort_key: '0.0~,')
3034
3076
  f.footer('Average', age: :avg, salary: :avg, join_date: :avg)
3035
- f.gfooter('Group SSQ', age: ->(f, c, k) { sa = f.items(c, k).map {|x| x * x}.sum; Math.sqrt(sa) })
3036
- f.footer('Total SSQ', age: ->(f, c) { sa = f.items(c).map {|x| x * x}.sum; Math.sqrt(sa) })
3077
+ f.gfooter('Group SSQ', age: ->(k, c, f) { sa = c.items.map {|x| x * x}.sum; Math.sqrt(sa) })
3078
+ f.footer('Total SSQ', age: ->(c, f) { sa = c.items.map {|x| x * x}.sum; Math.sqrt(sa) })
3037
3079
  end
3038
3080
  #+END_SRC
3039
3081
 
@@ -3045,19 +3087,19 @@ summ of the squares if the ages in each group:
3045
3087
  +-----------+-------+-----+------------+--------+-------------+----------+
3046
3088
  | Group SSQ | | 45 | | | | |
3047
3089
  +-----------+-------+-----+------------+--------+-------------+----------+
3048
- | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 | 2001 |
3090
+ | 1 | Paul | 32 | California | 20,000 | 13-JUL-2001 | 2001 |
3049
3091
  +-----------+-------+-----+------------+--------+-------------+----------+
3050
3092
  | Group SSQ | | 32 | | | | |
3051
3093
  +-----------+-------+-----+------------+--------+-------------+----------+
3052
- | 2 | Allen | 25 | Texas | | 13-JUL-2005 | 2005 |
3053
- | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 | 2005 |
3054
- | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 | 2005 |
3094
+ | 2 | Allen | 25 | Texas | | 13-JUL-2005 | 2005 |
3095
+ | 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 | 2005 |
3096
+ | 9 | James | 44 | Norway | 5,000 | 13-JUL-2005 | 2005 |
3055
3097
  +-----------+-------+-----+------------+--------+-------------+----------+
3056
3098
  | Group SSQ | | 56 | | | | |
3057
3099
  +-----------+-------+-----+------------+--------+-------------+----------+
3058
- | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 | 2007 |
3059
- | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 | 2007 |
3060
- | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 | 2007 |
3100
+ | 3 | Teddy | 23 | Norway | 20,000 | 13-DEC-2007 | 2007 |
3101
+ | 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 | 2007 |
3102
+ | 5 | David | 27 | Texas | 85,000 | 13-DEC-2007 | 2007 |
3061
3103
  +-----------+-------+-----+------------+--------+-------------+----------+
3062
3104
  | Group SSQ | | 43 | | | | |
3063
3105
  +-----------+-------+-----+------------+--------+-------------+----------+
@@ -2,7 +2,7 @@
2
2
 
3
3
  module FatTable
4
4
  class Footer
5
- attr_reader :table, :label, :label_col, :values, :group
5
+ attr_reader :table, :label_col, :values, :group
6
6
 
7
7
  ###########################################################################
8
8
  # Constructors
@@ -15,6 +15,7 @@ module FatTable
15
15
  # for the footer are added later with the #add_value method.
16
16
  def initialize(label = 'Total', table, label_col: nil, group: false)
17
17
  @label = label
18
+
18
19
  unless table.is_a?(Table)
19
20
  raise ArgumentError, 'Footer.new needs a table argument'
20
21
  end
@@ -30,14 +31,7 @@ module FatTable
30
31
  @group = group
31
32
  @group_cols = {}
32
33
  @values = {}
33
- if group
34
- @values[@label_col] = []
35
- table.number_of_groups.times do
36
- @values[@label_col] << @label
37
- end
38
- else
39
- @values[@label_col] = [@label]
40
- end
34
+ insert_labels_in_label_col
41
35
  make_accessor_methods
42
36
  end
43
37
 
@@ -71,6 +65,11 @@ module FatTable
71
65
  end
72
66
  end
73
67
 
68
+ # Return the value of the label, for the kth group if grouped.
69
+ def label(k = 0)
70
+ calc_label(k)
71
+ end
72
+
74
73
  # :category: Accessors
75
74
 
76
75
  # Return the value of under the +key+ header, or if this is a group
@@ -108,8 +107,10 @@ module FatTable
108
107
  if group && k.nil?
109
108
  raise ArgumentError, 'Footer#column(h, k) missing the group number argument k'
110
109
  end
110
+
111
111
  if group
112
- k.nil? ? @group_cols[h] : @group_cols[h][k]
112
+ @group_cols[h] ||= table.group_cols(h)
113
+ @group_cols[h][k]
113
114
  else
114
115
  table.column(h)
115
116
  end
@@ -151,14 +152,13 @@ module FatTable
151
152
 
152
153
  # Evaluate the given agg for the header col and, in the case of a group
153
154
  # footer, the group k.
154
- def calc_val(agg, col, k = nil)
155
- column =
156
- if group
157
- @group_cols[col] ||= table.group_cols(col)
158
- @group_cols[col][k]
159
- else
160
- table.column(col)
161
- end
155
+ def calc_val(agg, h, k = nil)
156
+ column = column(h, k)
157
+
158
+ # Convert Date and Time objects to DateTime
159
+ if [Date, Time].include?(agg.class)
160
+ agg = agg.to_datetime
161
+ end
162
162
 
163
163
  case agg
164
164
  when Symbol
@@ -179,29 +179,69 @@ module FatTable
179
179
  when Proc
180
180
  result =
181
181
  if group
182
- unless agg.arity == 3
183
- msg = 'a lambda used in a group footer must have three arguments: (f, c, k)'
182
+ case agg.arity
183
+ when 0
184
+ agg.call
185
+ when 1
186
+ agg.call(k)
187
+ when 2
188
+ agg.call(k, column)
189
+ when 3
190
+ agg.call(k, column, self)
191
+ else
192
+ msg = 'a lambda used in a group footer may have 0 to 3 three arguments: (k, c, f)'
184
193
  raise ArgumentError, msg
185
194
  end
186
- agg.call(self, col, k)
187
195
  else
188
- unless agg.arity == 2
189
- msg = 'a lambda used in a non-group footer must have two arguments: (f, c)'
196
+ case agg.arity
197
+ when 0
198
+ agg.call
199
+ when 1
200
+ agg.call(column)
201
+ when 2
202
+ agg.call(column, self)
203
+ else
204
+ msg = 'a lambda used in a non-group footer may have 0 to 2 arguments: (c, f)'
190
205
  raise ArgumentError, msg
191
206
  end
192
- agg.call(self, col)
193
207
  end
194
- # Make sure the result returned can be inserted into footer field.
195
- case result
196
- when Symbol, String
197
- calc_val(result, col, k)
198
- when column.type.constantize
199
- result
208
+ # Pass the result back into this method as the new agg
209
+ calc_val(result, h, k)
210
+ else
211
+ agg.to_s
212
+ end
213
+ end
214
+
215
+ # Insert a possibly calculated value for the label in the appropriate
216
+ # @values column.
217
+ def insert_labels_in_label_col
218
+ if group
219
+ @values[@label_col] = []
220
+ table.number_of_groups.times do |k|
221
+ @values[@label_col] << calc_label(k)
222
+ end
223
+ else
224
+ @values[@label_col] = [calc_label(0)]
225
+ end
226
+ end
227
+
228
+ # Calculate the label for the kth group, using k = 0 for non-group
229
+ # footers. If the label is a proc, call it with the group number.
230
+ def calc_label(k)
231
+ case @label
232
+ when Proc
233
+ case @label.arity
234
+ when 0
235
+ @label.call
236
+ when 1
237
+ @label.call(k)
238
+ when 2
239
+ @label.call(k, self)
200
240
  else
201
- raise ArgumentError, "lambda cannot return an object of class #{result.class}"
241
+ raise ArgumentError, "footer label proc may only have 1 argument for group number k"
202
242
  end
203
243
  else
204
- agg
244
+ @label.to_s
205
245
  end
206
246
  end
207
247
 
@@ -181,41 +181,74 @@ module FatTable
181
181
  end
182
182
 
183
183
  # :category: Add Footers
184
-
185
- # A simpler method for adding a footer to the formatted output having the
186
- # label +label+ placed in the column with the header +label_col+ or in the
187
- # first column if +label_col+ is ommitted. The remaining hash arguments
188
- # apply an aggregate to the values of the column, which can be:
189
- #
190
- # (1) a symbol representing one of the builtin aggregates, i.e., :first,
191
- # :last, :range, :sum, :count, :min, :max, :avg, :var, :pvar, :dev, :pdev,
192
- # :any?, :all?, :none?, and :one?,
193
184
  #
194
- # (2) an arbitrary value of one of the four supported types: Boolean,
195
- # DateTime, Numeric, or String: true, false, 3.14159, 'Total debits', or a
196
- # string that is convertible into one of these types by the usual methods
197
- # used in contructing a table,
185
+ # A keyword method for adding a footer to the formatted output having the
186
+ # label +label:+ (default 'Total') placed in the column with the header
187
+ # +label_col:+ or in the first column if +label_col+ is ommitted.
188
+ # This assigns a fixed group label to be placed in the :date column:
189
+ # #+begin_src ruby
190
+ # fmtr.foot(label: "Year's Average", label_col: :date, temp: avg)
191
+ # #+end_src
192
+ #
193
+ # Besides being a fixed string, the +label:+ can also be a proc or lambda
194
+ # taking one argument, the foooter itself.
195
+ # Thus, a label such as:
196
+ #
197
+ # #+begin_src ruby
198
+ # fmtr.foot(label: -> (f) { "Average (latest year #{f.column(:date).max.year})" },
199
+ # temp: :avg)
200
+ # #+end_src
201
+ # And this would add the highest number to label, assuming the :date column
202
+ # of the footer's table had the year for each item.
203
+ #
204
+ # The remaining hash arguments apply an aggregate to the values of the
205
+ # column, which can be:
206
+ #
207
+ # 1. a symbol representing one of the builtin aggregates, i.e., :first,
208
+ # :last, :range, :sum, :count, :min, :max, :avg, :var, :pvar, :dev,
209
+ # :pdev, :any?, :all?, :none?, and :one?, or a symbol for your own
210
+ # aggregate defined as an instance method on FatTable::Column.
211
+ # 2. a fixed string, but it the string can be converted into the Column's
212
+ # type, it will be converted, so the string '3.14159' will be converted
213
+ # to 3.14159 in a Numeric column.
214
+ # 3. a value of the Column's type, so Date.today would simply be evaluated
215
+ # for a Numeric column.
216
+ # 4. most flexibly of all, a proc or lambda taking arguments: f, the
217
+ # footer object itself; c, the column (or in the case of a group
218
+ # footer, the sub-column) corresponding to the current header, and in
219
+ # the case of a group footer, k, the number of the group (0-based).
220
+ # 5. Any other value is converted to a string with #to_s.
198
221
  #
199
222
  # Examples:
200
223
  #
201
224
  # Put the label in the :dickens column of the footer and the maximum value
202
225
  # from the :alpha column in the :alpha column of the footer.
203
226
  #
204
- # fmtr.foot('Best', :dickens, alpha: :max)
227
+ # fmtr.foot(label: 'Best', label_col: :dickens, alpha: :max)
205
228
  #
206
229
  # Put the label 'Today' in the first column of the footer and today's date
207
230
  # in the :beta column.
208
231
  #
209
- # fmtr.foot('Today', beta: Date.today)
232
+ # fmtr.foot(label: 'Today', beta: Date.today)
210
233
  #
211
234
  # Put the label 'Best' in the :dickens column of the footer and the string
212
235
  # 'Tale of Two Cities' in the :alpha column of the footer. Since it can't
213
236
  # be interpreted as Boolean, Numeric, or DateTime, it is placed in the
214
237
  # footer literally.
215
238
  #
216
- # fmtr.foot('Best', :dickens, alpha: 'A Tale of Two Cities')
239
+ # fmtr.foot(label: 'Best', label_col: :dickens, alpha: 'A Tale of Two
240
+ # Cities')
241
+ #
242
+ # Use a lambda to calculate the value to be placed in the column :gamma.
243
+ #
244
+ # fmtr.foot(label: 'Gamma', beta: :avg, gamma: ->(f, c) {
245
+ # (Math.gamma(c.count) + f[:beta] } )
217
246
  #
218
- def foot(label, label_col = nil, **agg_cols)
247
+ # Note that this way a footer can be made a function of the other footer
248
+ # values (using f[:other_col]) as well as the Column object corresponding
249
+ # to the lamda's column.
250
+ #
251
+ def foot(label: 'Total', label_col: nil, **agg_cols)
219
252
  foot = Footer.new(label, table, label_col: label_col)
220
253
  agg_cols.each_pair do |h, agg|
221
254
  foot.add_value(h, agg)
@@ -255,9 +288,92 @@ module FatTable
255
288
  foot
256
289
  end
257
290
 
258
- # Add a group footer to the formatted output. This method has the same
259
- # usage as the #foot method, but it adds group footers.
260
- def gfoot(label, label_col = nil, **agg_cols)
291
+ # :category: Add Footers
292
+ #
293
+ # A keyword method for adding a group footer to the formatted output
294
+ # having the label +label:+ (default 'Total') placed in the column with
295
+ # the header +label_col:+ or in the first column if +label_col+ is
296
+ # ommitted.
297
+ #
298
+ # This assigns a fixed group label to be placed in the :date column:
299
+ # #+begin_src ruby
300
+ # fmtr.gfoot(label: "Year's Average", label_col: :date, temp: avg)
301
+ # #+end_src
302
+ #
303
+ # Besides being a fixed string, the +label:+ can also be a proc or lambda
304
+ # taking one or two arguments. In the one argument form, the argument is
305
+ # the group number k. If a second argument is specified, the foooter
306
+ # itself is passed as the argument. Thus, a label such as:
307
+ #
308
+ # #+begin_src ruby
309
+ # fmtr.gfoot(label: -> (k) { "Group #{(k+1).to_roman} Average" }, temp: :avg)
310
+ # #+end_src
311
+ # This would format the label with a roman numeral (assuming you defined a
312
+ # method to do so) for the group number.
313
+ #
314
+ # #+begin_src ruby
315
+ # fmtr.gfoot(label: -> (k, f) { "Year #{f.column(:date, k).max.year} Group #{(k+1).to_roman} Average" },
316
+ # temp: :avg)
317
+ # #+end_src
318
+ # And this would add the group's year to label, assuming the :date column
319
+ # of the footer's table had the same year for each item in the group.
320
+ #
321
+ #
322
+ # The remaining hash arguments apply an aggregate to the values
323
+ # of the column, which can be:
324
+ #
325
+ # 1. a symbol representing one of the builtin aggregates, i.e., :first,
326
+ # :last, :range, :sum, :count, :min, :max, :avg, :var, :pvar, :dev,
327
+ # :pdev, :any?, :all?, :none?, and :one?, or a symbol for your own
328
+ # aggregate defined as an instance method on FatTable::Column.
329
+ # 2. a fixed string, but it the string can be converted into the Column's
330
+ # type, it will be converted, so the string '3.14159' will be converted
331
+ # to 3.14159 in a Numeric column.
332
+ # 3. a value of the Column's type, so Date.today would simply be evaluated
333
+ # for a Numeric column.
334
+ # 4. most flexibly of all, a proc or lambda taking arguments: f, the
335
+ # footer object itself; c, the column (or in the case of a group
336
+ # footer, the sub-column) corresponding to the current header, and k,
337
+ # this group's group number (0-based).
338
+ # 5. Any other value is converted to a string with #to_s.
339
+ #
340
+ # Examples:
341
+ #
342
+ # Put the label in the :dickens column of the footer and the maximum value
343
+ # from the :alpha column in the :alpha column of the footer.
344
+ #
345
+ # #+begin_src ruby
346
+ # fmtr.gfoot(label: 'Best', label_col: :dickens, alpha: :max)
347
+ # #+end_src
348
+ #
349
+ # Put the label 'Today' in the first column of the footer and today's date
350
+ # in the :beta column.
351
+ #
352
+ # #+begin_src ruby
353
+ # fmtr.gfoot(label: 'Today', beta: Date.today)
354
+ # #+end_src
355
+ #
356
+ # Put the label 'Best' in the :dickens column of the footer and the string
357
+ # 'Tale of Two Cities' in the :alpha column of the footer. Since it can't
358
+ # be interpreted as Boolean, Numeric, or DateTime, it is placed in the
359
+ # footer literally.
360
+ #
361
+ # #+begin_src ruby
362
+ # fmtr.gfoot(label: 'Best', label_col: :dickens, alpha: 'A Tale of Two
363
+ # Cities')
364
+ # #+end_src
365
+ #
366
+ # Use a lambda to calculate the value to be placed in the column :gamma.
367
+ #
368
+ # #+begin_src ruby
369
+ # fmtr.gfoot(label: 'Gamma', beta: :avg, gamma: ->(f, c) {
370
+ # (Math.gamma(c.count) + f[:beta] } )
371
+ # #+end_src
372
+ #
373
+ # Note that this way a footer can be made a function of the other footer
374
+ # values (using f[:other_col]) as well as the Column object corresponding
375
+ # to the lamda's column.
376
+ def gfoot(label: 'Group Total', label_col: nil, **agg_cols)
261
377
  foot = Footer.new(label, table, label_col: label_col, group: true)
262
378
  agg_cols.each_pair do |h, agg|
263
379
  foot.add_value(h, agg)
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FatTable
4
4
  # The current version of FatTable
5
- VERSION = '0.5.5'
5
+ VERSION = '0.6.0'
6
6
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fat_table
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.5
4
+ version: 0.6.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Daniel E. Doherty
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-03-25 00:00:00.000000000 Z
11
+ date: 2022-03-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler