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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: f2a1154179dc04fcdfca93f7e883ead5572b5ea4
4
- data.tar.gz: 0b93b77f79888904d940124f51c00afb50beae61
3
+ metadata.gz: dee8f90ed96b24c51a40eaaf816cda967450ed78
4
+ data.tar.gz: 83fe257ef4ceba08a7bf11e6ed281a17f452b26f
5
5
  SHA512:
6
- metadata.gz: caf9a264b140596a98fcbeaaea71f01890c1677b941c1b0e9118c446b9e81190ca83366a0e967df76e5f2d9b3ceb0f024bf36f75370ce8c6770be9c7e569c865
7
- data.tar.gz: 1f032a4c6fade3021ae2c9beb6a16ec15b06eaec9d16c75cd070d5526cd1cae71b305562e353d6f3747665d7ffcff641146b81ee1d6232c9c582190bccc60d77
6
+ metadata.gz: 6f7c36cf04a7b5c0b36c8cdd84014f8b31481834dd674869ff1993af8024e2b42fd8cd5e07685173b236f0c16610972f61eb5c996e71c5fa9360f8f36aa3dee9
7
+ data.tar.gz: a41b43ff052e3eddf9c46e8047f3ccf424d8070e8afc3bf1b57f5e8fa2fe063057b1800ff8718bff2719429726f9490ce439db07d89b74599e1012b795af520d
@@ -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
- @header = header.as_sym
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 that of the first and last values.
56
- def rng_s
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, *types)
112
- unless types.include?(type)
113
- raise "Aggregate '#{agg}' cannot be applied to a #{type} column"
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 > 0
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 < 0
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 < 0 ? -1 : 1
978
+ incr = n.negative? ? -1 : 1
979
979
  n = n.abs
980
- while n > 0
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 < 0 ? -1 : 1
998
+ incr = n.negative? ? -1 : 1
999
999
  n = n.abs
1000
- while n > 0
1000
+ while n.positive?
1001
1001
  d += incr
1002
1002
  n -= 1 if d.nyse_workday?
1003
1003
  end
@@ -1,7 +1,18 @@
1
1
  module Enumerable
2
- # Emit item in groups of n
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