fat_core 1.6.0 → 1.7.1
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/lib/fat_core/column.rb +71 -9
- data/lib/fat_core/date.rb +6 -6
- data/lib/fat_core/enumerable.rb +12 -1
- data/lib/fat_core/formatters/aoa_formatter.rb +84 -0
- data/lib/fat_core/formatters/aoh_formatter.rb +82 -0
- data/lib/fat_core/formatters/formatter.rb +973 -0
- data/lib/fat_core/formatters/org_formatter.rb +72 -0
- data/lib/fat_core/formatters/text_formatter.rb +91 -0
- data/lib/fat_core/formatters.rb +5 -0
- data/lib/fat_core/hash.rb +13 -0
- data/lib/fat_core/numeric.rb +3 -3
- data/lib/fat_core/period.rb +5 -1
- data/lib/fat_core/string.rb +20 -0
- data/lib/fat_core/symbol.rb +1 -1
- data/lib/fat_core/table.rb +251 -266
- data/lib/fat_core/version.rb +2 -2
- data/lib/fat_core.rb +2 -0
- data/spec/lib/column_spec.rb +24 -8
- data/spec/lib/formatters/aoa_formatter_spec.rb +62 -0
- data/spec/lib/formatters/aoh_formatter_spec.rb +61 -0
- data/spec/lib/formatters/formatter_spec.rb +371 -0
- data/spec/lib/formatters/org_formatter_spec.rb +60 -0
- data/spec/lib/formatters/text_formatter_spec.rb +60 -0
- data/spec/lib/period_spec.rb +9 -2
- data/spec/lib/symbol_spec.rb +1 -1
- data/spec/lib/table_spec.rb +86 -167
- metadata +18 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dee8f90ed96b24c51a40eaaf816cda967450ed78
|
4
|
+
data.tar.gz: 83fe257ef4ceba08a7bf11e6ed281a17f452b26f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6f7c36cf04a7b5c0b36c8cdd84014f8b31481834dd674869ff1993af8024e2b42fd8cd5e07685173b236f0c16610972f61eb5c996e71c5fa9360f8f36aa3dee9
|
7
|
+
data.tar.gz: a41b43ff052e3eddf9c46e8047f3ccf424d8070e8afc3bf1b57f5e8fa2fe063057b1800ff8718bff2719429726f9490ce439db07d89b74599e1012b795af520d
|
data/lib/fat_core/column.rb
CHANGED
@@ -4,12 +4,18 @@ module FatCore
|
|
4
4
|
# nils before proceeding. My original attempt to do this by monkey-patching
|
5
5
|
# Array turned out badly. This works much nicer.
|
6
6
|
class Column
|
7
|
-
attr_reader :header, :type, :items
|
7
|
+
attr_reader :header, :raw_header, :type, :items
|
8
8
|
|
9
|
-
TYPES = %w(NilClass Boolean DateTime Numeric String)
|
9
|
+
TYPES = %w(NilClass Boolean DateTime Numeric String).freeze
|
10
10
|
|
11
11
|
def initialize(header:, items: [])
|
12
|
-
@
|
12
|
+
@raw_header = header
|
13
|
+
@header =
|
14
|
+
if @raw_header.is_a?(Symbol)
|
15
|
+
@raw_header
|
16
|
+
else
|
17
|
+
@raw_header.gsub(/[^A-Za-z0-9 ]/, '').as_sym
|
18
|
+
end
|
13
19
|
@type = 'NilClass'
|
14
20
|
raise "Unknown column type '#{type}" unless TYPES.include?(@type.to_s)
|
15
21
|
@items = []
|
@@ -44,38 +50,58 @@ module FatCore
|
|
44
50
|
# Aggregates
|
45
51
|
##########################################################################
|
46
52
|
|
53
|
+
VALID_AGGREGATES = %s(first last rng
|
54
|
+
sum count min max avg var dev
|
55
|
+
any? all? none? one?)
|
56
|
+
|
57
|
+
# Return the first non-nil item in the column. Works with any column type.
|
47
58
|
def first
|
48
59
|
items.compact.first
|
49
60
|
end
|
50
61
|
|
62
|
+
# Return the last non-nil item in the column. Works with any column type.
|
51
63
|
def last
|
52
64
|
items.compact.last
|
53
65
|
end
|
54
66
|
|
55
|
-
# Return a string
|
56
|
-
|
67
|
+
# Return a string of the first and last non-nil values. Works with any
|
68
|
+
# column type.
|
69
|
+
def rng
|
57
70
|
"#{first}..#{last}"
|
58
71
|
end
|
59
72
|
|
73
|
+
# Return the sum of the non-nil items in the column. Works with numeric and
|
74
|
+
# string columns. For a string column, it will return the concatenation of
|
75
|
+
# the non-nil items.
|
60
76
|
def sum
|
61
77
|
only_with('sum', 'Numeric', 'String')
|
62
78
|
items.compact.sum
|
63
79
|
end
|
64
80
|
|
81
|
+
# Return a count of the non-nil items in the column. Works with any column
|
82
|
+
# type.
|
65
83
|
def count
|
66
84
|
items.compact.count
|
67
85
|
end
|
68
86
|
|
87
|
+
# Return the smallest non-nil item in the column. Works with numeric,
|
88
|
+
# string, and datetime columns.
|
69
89
|
def min
|
70
90
|
only_with('min', 'NilClass', 'Numeric', 'String', 'DateTime')
|
71
91
|
items.compact.min
|
72
92
|
end
|
73
93
|
|
94
|
+
# Return the largest non-nil item in the column. Works with numeric,
|
95
|
+
# string, and datetime columns.
|
74
96
|
def max
|
75
97
|
only_with('max', 'NilClass', 'Numeric', 'String', 'DateTime')
|
76
98
|
items.compact.max
|
77
99
|
end
|
78
100
|
|
101
|
+
# Return the average value of the non-nil items in the column. Works with
|
102
|
+
# numeric and datetime columns. For datetime columns, it converts each date
|
103
|
+
# to its Julian day number, computes the average, and then converts the
|
104
|
+
# average back to a DateTime.
|
79
105
|
def avg
|
80
106
|
only_with('avg', 'DateTime', 'Numeric')
|
81
107
|
if type == 'DateTime'
|
@@ -86,21 +112,58 @@ module FatCore
|
|
86
112
|
end
|
87
113
|
end
|
88
114
|
|
115
|
+
# Return the variance, the average squared deviation from the mean, of the
|
116
|
+
# non-nil items in the column. Works with numeric and datetime columns.
|
117
|
+
# For datetime columns, it converts each date to its Julian day number and
|
118
|
+
# computes the variance of those numbers.
|
119
|
+
def var
|
120
|
+
only_with('var', 'DateTime', 'Numeric')
|
121
|
+
all_items =
|
122
|
+
if type == 'DateTime'
|
123
|
+
items.compact.map(&:jd)
|
124
|
+
else
|
125
|
+
items.compact
|
126
|
+
end
|
127
|
+
mu = Column.new(header: :mu, items: all_items).avg
|
128
|
+
sq_dev = 0.0
|
129
|
+
all_items.compact.each do |itm|
|
130
|
+
sq_dev += (itm - mu) * (itm - mu)
|
131
|
+
end
|
132
|
+
sq_dev / items.compact.size.to_d
|
133
|
+
end
|
134
|
+
|
135
|
+
# Return the standard deviation, the square root of the variance, of the
|
136
|
+
# non-nil items in the column. Works with numeric and datetime columns.
|
137
|
+
# For datetime columns, it converts each date to its Julian day number and
|
138
|
+
# computes the standard deviation of those numbers.
|
139
|
+
def dev
|
140
|
+
only_with('dev', 'DateTime', 'Numeric')
|
141
|
+
Math.sqrt(var)
|
142
|
+
end
|
143
|
+
|
144
|
+
# Return true if any of the items in the column are true; otherwise return
|
145
|
+
# false. Works only with boolean columns.
|
89
146
|
def any?
|
90
147
|
only_with('any?', 'Boolean')
|
91
148
|
items.compact.any?
|
92
149
|
end
|
93
150
|
|
151
|
+
# Return true if all of the items in the column are true; otherwise return
|
152
|
+
# false. Works only with boolean columns.
|
94
153
|
def all?
|
95
154
|
only_with('all?', 'Boolean')
|
96
155
|
items.compact.all?
|
97
156
|
end
|
98
157
|
|
158
|
+
# Return true if none of the items in the column are true; otherwise return
|
159
|
+
# false. Works only with boolean columns.
|
99
160
|
def none?
|
100
161
|
only_with('any?', 'Boolean')
|
101
162
|
items.compact.none?
|
102
163
|
end
|
103
164
|
|
165
|
+
# Return true if precisely one of the items in the column is true;
|
166
|
+
# otherwise return false. Works only with boolean columns.
|
104
167
|
def one?
|
105
168
|
only_with('any?', 'Boolean')
|
106
169
|
items.compact.one?
|
@@ -108,10 +171,9 @@ module FatCore
|
|
108
171
|
|
109
172
|
private
|
110
173
|
|
111
|
-
def only_with(agg, *
|
112
|
-
|
113
|
-
|
114
|
-
end
|
174
|
+
def only_with(agg, *valid_types)
|
175
|
+
return self if valid_types.include?(type)
|
176
|
+
raise "Aggregate '#{agg}' cannot be applied to a #{type} column"
|
115
177
|
end
|
116
178
|
|
117
179
|
public
|
data/lib/fat_core/date.rb
CHANGED
@@ -609,7 +609,7 @@ class Date
|
|
609
609
|
month = month.to_i
|
610
610
|
raise ArgumentError, 'illegal month number' if month < 1 || month > 12
|
611
611
|
n = n.to_i
|
612
|
-
if n
|
612
|
+
if n.positive?
|
613
613
|
# Set d to the 1st wday in month
|
614
614
|
d = Date.new(year, month, 1)
|
615
615
|
d += 1 while d.wday != wday
|
@@ -620,7 +620,7 @@ class Date
|
|
620
620
|
nd += 1
|
621
621
|
end
|
622
622
|
d
|
623
|
-
elsif n
|
623
|
+
elsif n.negative?
|
624
624
|
n = -n
|
625
625
|
# Set d to the last wday in month
|
626
626
|
d = Date.new(year, month, 1).end_of_month
|
@@ -975,9 +975,9 @@ class Date
|
|
975
975
|
def add_fed_business_days(n)
|
976
976
|
d = dup
|
977
977
|
return d if n.zero?
|
978
|
-
incr = n
|
978
|
+
incr = n.negative? ? -1 : 1
|
979
979
|
n = n.abs
|
980
|
-
while n
|
980
|
+
while n.positive?
|
981
981
|
d += incr
|
982
982
|
n -= 1 if d.fed_workday?
|
983
983
|
end
|
@@ -995,9 +995,9 @@ class Date
|
|
995
995
|
def add_nyse_business_days(n)
|
996
996
|
d = dup
|
997
997
|
return d if n.zero?
|
998
|
-
incr = n
|
998
|
+
incr = n.negative? ? -1 : 1
|
999
999
|
n = n.abs
|
1000
|
-
while n
|
1000
|
+
while n.positive?
|
1001
1001
|
d += incr
|
1002
1002
|
n -= 1 if d.nyse_workday?
|
1003
1003
|
end
|
data/lib/fat_core/enumerable.rb
CHANGED
@@ -1,7 +1,18 @@
|
|
1
1
|
module Enumerable
|
2
|
-
#
|
2
|
+
# Yield item in groups of n
|
3
3
|
def groups_of(n)
|
4
4
|
k = -1
|
5
5
|
group_by { k += 1; k.div(n) }
|
6
6
|
end
|
7
|
+
|
8
|
+
# Yield each item together with booleans that indicate whether the item is the
|
9
|
+
# first or last in the Enumerable.
|
10
|
+
def each_with_flags
|
11
|
+
last_k = size - 1
|
12
|
+
each_with_index do |v, k|
|
13
|
+
first = (k == 0 ? true : false)
|
14
|
+
last = (k == last_k ? true : false)
|
15
|
+
yield(v, first, last)
|
16
|
+
end
|
17
|
+
end
|
7
18
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module FatCore
|
2
|
+
class AoaFormatter < Formatter
|
3
|
+
def evaluate?
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def pre_table
|
8
|
+
'['
|
9
|
+
end
|
10
|
+
|
11
|
+
def post_table
|
12
|
+
']'
|
13
|
+
end
|
14
|
+
|
15
|
+
def pre_header(_widths)
|
16
|
+
''
|
17
|
+
end
|
18
|
+
|
19
|
+
def post_header(_widths)
|
20
|
+
''
|
21
|
+
end
|
22
|
+
|
23
|
+
def pre_row
|
24
|
+
'['
|
25
|
+
end
|
26
|
+
|
27
|
+
def pre_cell(_h)
|
28
|
+
"'"
|
29
|
+
end
|
30
|
+
|
31
|
+
# Because the cell, after conversion to a single-quoted string will be
|
32
|
+
# eval'ed, we need to escape any single-quotes (') that appear in the
|
33
|
+
# string.
|
34
|
+
def quote_cell(v)
|
35
|
+
if v =~ /'/
|
36
|
+
# Use a negative look-behind to only quote single-quotes that are not
|
37
|
+
# already preceded by a backslash
|
38
|
+
v.gsub(/(?<!\\)'/, "'" => "\\'")
|
39
|
+
else
|
40
|
+
v
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def post_cell
|
45
|
+
"'"
|
46
|
+
end
|
47
|
+
|
48
|
+
def inter_cell
|
49
|
+
','
|
50
|
+
end
|
51
|
+
|
52
|
+
def post_row
|
53
|
+
"],\n"
|
54
|
+
end
|
55
|
+
|
56
|
+
def hline(_widths)
|
57
|
+
"nil,\n"
|
58
|
+
end
|
59
|
+
|
60
|
+
def pre_group
|
61
|
+
''
|
62
|
+
end
|
63
|
+
|
64
|
+
def post_group
|
65
|
+
''
|
66
|
+
end
|
67
|
+
|
68
|
+
def pre_gfoot
|
69
|
+
''
|
70
|
+
end
|
71
|
+
|
72
|
+
def post_gfoot
|
73
|
+
''
|
74
|
+
end
|
75
|
+
|
76
|
+
def pre_foot
|
77
|
+
''
|
78
|
+
end
|
79
|
+
|
80
|
+
def post_foot
|
81
|
+
''
|
82
|
+
end
|
83
|
+
end
|
84
|
+
end
|
@@ -0,0 +1,82 @@
|
|
1
|
+
module FatCore
|
2
|
+
class AohFormatter < Formatter
|
3
|
+
def evaluate?
|
4
|
+
true
|
5
|
+
end
|
6
|
+
|
7
|
+
def pre_table
|
8
|
+
'['
|
9
|
+
end
|
10
|
+
|
11
|
+
def post_table
|
12
|
+
']'
|
13
|
+
end
|
14
|
+
|
15
|
+
# We include no row for the header because the keys of each hash serve as
|
16
|
+
# the headers.
|
17
|
+
def include_header_row?
|
18
|
+
false
|
19
|
+
end
|
20
|
+
|
21
|
+
def pre_row
|
22
|
+
'{'
|
23
|
+
end
|
24
|
+
|
25
|
+
def pre_cell(h)
|
26
|
+
":#{h.as_sym} => '"
|
27
|
+
end
|
28
|
+
|
29
|
+
# Because the cell, after conversion to a single-quoted string will be
|
30
|
+
# eval'ed, we need to escape any single-quotes (') that appear in the
|
31
|
+
# string.
|
32
|
+
def quote_cell(v)
|
33
|
+
if v =~ /'/
|
34
|
+
# Use a negative look-behind to only quote single-quotes that are not
|
35
|
+
# already preceded by a backslash
|
36
|
+
v.gsub(/(?<!\\)'/, "'" => "\\'")
|
37
|
+
else
|
38
|
+
v
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
def post_cell
|
43
|
+
"'"
|
44
|
+
end
|
45
|
+
|
46
|
+
def inter_cell
|
47
|
+
','
|
48
|
+
end
|
49
|
+
|
50
|
+
def post_row
|
51
|
+
"},\n"
|
52
|
+
end
|
53
|
+
|
54
|
+
def hline(_widths)
|
55
|
+
"nil,\n"
|
56
|
+
end
|
57
|
+
|
58
|
+
def pre_group
|
59
|
+
''
|
60
|
+
end
|
61
|
+
|
62
|
+
def post_group
|
63
|
+
''
|
64
|
+
end
|
65
|
+
|
66
|
+
def pre_gfoot
|
67
|
+
''
|
68
|
+
end
|
69
|
+
|
70
|
+
def post_gfoot
|
71
|
+
''
|
72
|
+
end
|
73
|
+
|
74
|
+
def pre_foot
|
75
|
+
''
|
76
|
+
end
|
77
|
+
|
78
|
+
def post_foot
|
79
|
+
''
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|