fat_table 0.5.5 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.org +95 -53
- data/lib/fat_table/footer.rb +72 -32
- data/lib/fat_table/formatters/formatter.rb +136 -20
- data/lib/fat_table/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: f348d317c061becae08890ff02cc9c08789787d966f9ed88f3a4ef22b6eddb44
|
4
|
+
data.tar.gz: bf672b4f4f4ab07df465d06904ccebb9b48507177dc88a343eb09bfb0e98bc02
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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.
|
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 ~
|
2710
|
-
objects to add footers and group footers. Note that all of these
|
2711
|
-
return a ~Footer~ object that can be accessed to extract the computed
|
2712
|
-
All of these methods return the ~FatTable::Footer~ object so
|
2713
|
-
can be used to access the values and other attributes of the
|
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
|
2796
|
-
|
2797
|
-
|
2798
|
-
|
2799
|
-
|
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
|
2985
|
-
or 3 parameters in non-group and group footers, respectively:
|
2986
|
-
|
2987
|
-
- ~->(
|
2988
|
-
paramters: the first, ~
|
2989
|
-
|
2990
|
-
lambda
|
2991
|
-
|
2992
|
-
|
2993
|
-
|
2994
|
-
|
2995
|
-
|
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: ->(
|
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: ->(
|
3036
|
-
f.footer('Total SSQ', age: ->(
|
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 |
|
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 |
|
3053
|
-
| 8 | Paul | 24 | Houston | 20,000 | 13-JUL-2005 |
|
3054
|
-
| 9 | James | 44 | Norway | 5,000 | 13-JUL-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 |
|
3059
|
-
| 4 | Mark | 25 | Rich-Mond | 65,000 | 13-DEC-2007 |
|
3060
|
-
| 5 | David | 27 | Texas | 85,000 | 13-DEC-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
|
+-----------+-------+-----+------------+--------+-------------+----------+
|
data/lib/fat_table/footer.rb
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
|
3
3
|
module FatTable
|
4
4
|
class Footer
|
5
|
-
attr_reader :table, :
|
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
|
-
|
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
|
-
|
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,
|
155
|
-
column =
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
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
|
-
|
183
|
-
|
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
|
-
|
189
|
-
|
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
|
-
#
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
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, "
|
241
|
+
raise ArgumentError, "footer label proc may only have 1 argument for group number k"
|
202
242
|
end
|
203
243
|
else
|
204
|
-
|
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
|
-
#
|
195
|
-
#
|
196
|
-
#
|
197
|
-
#
|
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
|
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
|
-
|
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
|
259
|
-
#
|
260
|
-
|
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)
|
data/lib/fat_table/version.rb
CHANGED
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.
|
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-
|
11
|
+
date: 2022-03-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|