fat_core 1.6.0 → 1.7.1

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
  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