fat_table 0.4.0 → 0.5.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.rdoc CHANGED
@@ -888,8 +888,7 @@ will raise an exception.
888
888
 
889
889
  +last+:: the last non-nil item in the column,
890
890
 
891
- +rng+:: form a string of the form "#{first}..#{last}" to show the range of
892
- values in the column,
891
+ +range+- :: form a Range ~~{min}..{max}~ to show the range of values in the column,
893
892
 
894
893
  +sum+:: for Numeric and String columns, apply '+' to all the non-nil values,
895
894
 
data/TODO.org CHANGED
@@ -1,3 +1,20 @@
1
+ * TODO Conversion to Spreadsheets
2
+ - State "TODO" from [2017-04-21 Fri 10:36]
3
+ This is a [[https://github.com/westonganger/spreadsheet_architect][gem]] that I can include into the Table model to convert a table into
4
+ a spread-sheet, or even a sheet in a multi-sheet spreadsheet file.
5
+
6
+ * TODO Add from_yql for fetching from Yahoo
7
+ - State "TODO" from [2017-04-21 Fri 10:35]
8
+ Add a constructor to allow fetching stock data from yql. Perhaps grab all
9
+ available fields, then allow a select of those of interest.
10
+
11
+ * DONE Allow sorting by expression
12
+ CLOSED: [2022-01-20 Thu 12:47]
13
+ Either by a single string argument as the sole argument to order_by, or use
14
+ another method, such a order_with. Note that this can be done now by creating
15
+ a new column having the sort expression with select and then just order_by
16
+ that column. Perhaps that is an easy way to implement it.
17
+
1
18
  * DONE Ensure that columns resulting from aggregates have proper type
2
19
  CLOSED: [2017-12-29 Fri 05:34]
3
20
  - State "WAIT" from "TODO" [2017-12-29 Fri 05:34]
@@ -5,11 +22,6 @@ CLOSED: [2017-12-29 Fri 05:34]
5
22
  After applying avg, does the column have the proper Numeric or Date, or DateTime
6
23
  type. How about Boolean aggregates?
7
24
 
8
- * TODO Conversion to Spreadsheets
9
- - State "TODO" from [2017-04-21 Fri 10:36]
10
- This is a [[https://github.com/westonganger/spreadsheet_architect][gem]] that I can include into the Table model to convert a table into
11
- a spread-sheet, or even a sheet in a multi-sheet spreadsheet file.
12
-
13
25
  * DONE Formatters
14
26
  CLOSED: [2017-04-21 Fri 10:36]
15
27
  - State "WAIT" from "TODO" [2017-04-21 Fri 10:36]
@@ -31,8 +43,3 @@ CLOSED: [2017-03-02 Thu 15:54]
31
43
  - State "TODO" from [2017-03-02 Thu 15:54]
32
44
  For tables, add a method that eliminates any duplicate rows. Perhaps just apply
33
45
  Array#uniq to the columns?
34
-
35
- * TODO Add from_yql for fetching from Yahoo
36
- - State "TODO" from [2017-04-21 Fri 10:35]
37
- Add a constructor to allow fetching stock data from yql. Perhaps grab all
38
- available fields, then allow a select of those of interest.
@@ -0,0 +1,14 @@
1
+ drop table trans;
2
+ create table trans(date text, code text, raw, shares, price, info text, ok text);
3
+ insert into trans values('2013-05-29', 'S', 15700.00, 6601.85, 24.7790, 'ENTITY3', 'F');
4
+ insert into trans values('2013-05-02', 'P', 118186.40, 118186.4, 11.8500, 'ENTITY1', 'T');
5
+ insert into trans values('2013-05-20', 'S', 12000.00, 5046.00, 28.2804, 'ENTITY3', 'F');
6
+ insert into trans values('2013-05-23', 'S', 8000.00, 3364.00, 27.1083, 'ENTITY3', 'T');
7
+ insert into trans values('2013-05-23', 'S', 39906.00, 16780.47, 25.1749, 'ENTITY3', 'T');
8
+ insert into trans values('2013-05-20', 'S', 85000.00, 35742.50, 28.3224, 'ENTITY3', 'T');
9
+ insert into trans values('2013-05-02', 'P', 795546.20, 795546.2, 1.1850, 'ENTITY1', 'T');
10
+ insert into trans values('2013-05-29', 'S', 13459.00, 5659.51, 24.7464, 'ENTITY3', 'T');
11
+ insert into trans values('2013-05-20', 'S', 33302.00, 14003.49, 28.6383, 'ENTITY3', 'T');
12
+ insert into trans values('2013-05-29', 'S', 15900.00, 6685.95, 24.5802, 'ENTITY3', 'T');
13
+ insert into trans values('2013-05-30', 'S', 6679.00, 2808.52, 25.0471, 'ENTITY3', 'T');
14
+ insert into trans values('2013-05-23', 'S', 23054.00, 9694.21, 26.8015, 'ENTITY3', 'F');
Binary file
Binary file
Binary file
@@ -0,0 +1,8 @@
1
+ \documentclass{article}
2
+
3
+ \usepackage{longtable}
4
+ \usepackage[pdftex,table,x11names]{xcolor}
5
+
6
+ \begin{document}
7
+ \include{quicktable.tex}
8
+ \end{document}
Binary file
@@ -0,0 +1,123 @@
1
+ \begin{longtable}{clcrrc}
2
+ \bfseries{Ref}&
3
+ \multicolumn{1}{c}{\bfseries{Date}}&
4
+ \bfseries{Code}&
5
+ \multicolumn{1}{c}{\bfseries{Shares}}&
6
+ \multicolumn{1}{c}{\bfseries{Price}}&
7
+ \bfseries{Ok}\\
8
+ \endhead
9
+ \bfseries{1}&
10
+ 2013-05-02&
11
+ P&
12
+ \cellcolor{lightgray}{\textcolor{blue}{118,186.4}}&
13
+ \$11.8500&
14
+ Y\\
15
+ \bfseries{2}&
16
+ 2013-05-02&
17
+ P&
18
+ \cellcolor{lightgray}{\textcolor{blue}{795,546.2}}&
19
+ 1.1850&
20
+ Y\\
21
+ \bfseries{Avg}&
22
+ &
23
+ \multicolumn{1}{l}{}&
24
+ \bfseries{456,866.3}&
25
+ \bfseries{6.5175}&
26
+ \\
27
+ \bfseries{3}&
28
+ 2013-05-20&
29
+ S&
30
+ \cellcolor{lightgray}{\textcolor{blue}{5,046.0}}&
31
+ 28.2804&
32
+ N\\
33
+ \bfseries{4}&
34
+ 2013-05-20&
35
+ S&
36
+ \cellcolor{lightgray}{\textcolor{blue}{35,742.5}}&
37
+ 28.3224&
38
+ Y\\
39
+ \bfseries{5}&
40
+ 2013-05-20&
41
+ S&
42
+ \cellcolor{lightgray}{\textcolor{blue}{14,003.5}}&
43
+ 28.6383&
44
+ Y\\
45
+ \bfseries{Avg}&
46
+ &
47
+ \multicolumn{1}{l}{}&
48
+ \bfseries{18,264.0}&
49
+ \bfseries{28.4137}&
50
+ \\
51
+ \bfseries{6}&
52
+ 2013-05-23&
53
+ S&
54
+ \cellcolor{lightgray}{\textcolor{blue}{3,364.0}}&
55
+ 27.1083&
56
+ Y\\
57
+ \bfseries{7}&
58
+ 2013-05-23&
59
+ S&
60
+ \cellcolor{lightgray}{\textcolor{blue}{16,780.5}}&
61
+ 25.1749&
62
+ Y\\
63
+ \bfseries{8}&
64
+ 2013-05-23&
65
+ S&
66
+ \cellcolor{lightgray}{\textcolor{blue}{9,694.2}}&
67
+ 26.8015&
68
+ N\\
69
+ \bfseries{Avg}&
70
+ &
71
+ \multicolumn{1}{l}{}&
72
+ \bfseries{9,946.2}&
73
+ \bfseries{26.3616}&
74
+ \\
75
+ \bfseries{9}&
76
+ 2013-05-29&
77
+ S&
78
+ \cellcolor{lightgray}{\textcolor{blue}{6,601.9}}&
79
+ 24.7790&
80
+ N\\
81
+ \bfseries{10}&
82
+ 2013-05-29&
83
+ S&
84
+ \cellcolor{lightgray}{\textcolor{blue}{5,659.5}}&
85
+ 24.7464&
86
+ Y\\
87
+ \bfseries{11}&
88
+ 2013-05-29&
89
+ S&
90
+ \cellcolor{lightgray}{\textcolor{blue}{6,686.0}}&
91
+ 24.5802&
92
+ Y\\
93
+ \bfseries{Avg}&
94
+ &
95
+ \multicolumn{1}{l}{}&
96
+ \bfseries{6,315.8}&
97
+ \bfseries{24.7019}&
98
+ \\
99
+ \bfseries{12}&
100
+ 2013-05-30&
101
+ S&
102
+ \cellcolor{lightgray}{\textcolor{blue}{2,808.5}}&
103
+ 25.0471&
104
+ Y\\
105
+ \bfseries{Avg}&
106
+ &
107
+ \multicolumn{1}{l}{}&
108
+ \bfseries{2,808.5}&
109
+ \bfseries{25.0471}&
110
+ \\
111
+ \bfseries{Average}&
112
+ &
113
+ \multicolumn{1}{l}{}&
114
+ \bfseries{85,009.9}&
115
+ \bfseries{23.0428}&
116
+ \\
117
+ \bfseries{Total}&
118
+ &
119
+ \multicolumn{1}{l}{}&
120
+ \bfseries{1,020,119.1}&
121
+ \bfseries{}&
122
+ \\
123
+ \end{longtable}
Binary file
@@ -0,0 +1,13 @@
1
+ 'Date', 'Code', 'Raw', 'Shares', 'Price', 'Info', 'Ok',
2
+ '2013-05-29', 'S', 15700.00, 6601.85, 24.7790, 'ENTITY3', FALSE,
3
+ '2013-05-02', 'P', 118186.40, 118186.4, 11.8500, 'ENTITY1', TRUE,
4
+ '2013-05-20', 'S', 12000.00, 5046.00, 28.2804, 'ENTITY3', FALSE,
5
+ '2013-05-23', 'S', 8000.00, 3364.00, 27.1083, 'ENTITY3', TRUE,
6
+ '2013-05-23', 'S', 39906.00, 16780.47, 25.1749, 'ENTITY3', TRUE,
7
+ '2013-05-20', 'S', 85000.00, 35742.50, 28.3224, 'ENTITY3', TRUE,
8
+ '2013-05-02', 'P', 795546.20, 795546.2, 1.1850, 'ENTITY1', TRUE,
9
+ '2013-05-29', 'S', 13459.00, 5659.51, 24.7464, 'ENTITY3', TRUE,
10
+ '2013-05-20', 'S', 33302.00, 14003.49, 28.6383, 'ENTITY3', TRUE,
11
+ '2013-05-29', 'S', 15900.00, 6685.95, 24.5802, 'ENTITY3', TRUE,
12
+ '2013-05-30', 'S', 6679.00, 2808.52, 25.0471, 'ENTITY3', TRUE,
13
+ '2013-05-23', 'S', 23054.00, 9694.21, 26.8015, 'ENTITY3', FALSE
data/fat_table.gemspec CHANGED
@@ -70,6 +70,7 @@ Gem::Specification.new do |spec|
70
70
  spec.add_development_dependency 'rake', '~> 13.0'
71
71
  spec.add_development_dependency 'redcarpet'
72
72
  spec.add_development_dependency 'pg'
73
+ spec.add_development_dependency 'sqlite3'
73
74
  spec.add_development_dependency 'rspec', '~> 3.0'
74
75
  spec.add_development_dependency 'rubocop-rspec'
75
76
  spec.add_development_dependency 'rubocop-performance'
data/lib/ext/array.rb ADDED
@@ -0,0 +1,15 @@
1
+ class Array
2
+ # Map booleans true to 1 and false to 0 so they can be compared in a sort
3
+ # with the <=> operator.
4
+ def map_booleans
5
+ map do |v|
6
+ if v == true
7
+ 1
8
+ elsif v == false
9
+ 0
10
+ else
11
+ v
12
+ end
13
+ end
14
+ end
15
+ end
@@ -83,7 +83,7 @@ module FatTable
83
83
  # col.type #=> 'Numeric'
84
84
  # col.header #=> :prices
85
85
  # col.sum #=> 18376.75
86
- def initialize(header:, items: [], type: 'NilClass')
86
+ def initialize(header:, items: [], type: 'NilClass', tolerant: false)
87
87
  @raw_header = header
88
88
  @header =
89
89
  if @raw_header.is_a?(Symbol)
@@ -92,6 +92,7 @@ module FatTable
92
92
  @raw_header.to_s.as_sym
93
93
  end
94
94
  @type = type
95
+ @tolerant = tolerant
95
96
  msg = "unknown column type '#{type}"
96
97
  raise UserError, msg unless TYPES.include?(@type.to_s)
97
98
 
@@ -141,9 +142,17 @@ module FatTable
141
142
 
142
143
  # :category: Attributes
143
144
 
145
+ # Is this column tolerant of type incompatibilities? If so, the Column
146
+ # type will be forced to String if an incompatible type is found.
147
+ def tolerant?
148
+ @tolerant
149
+ end
150
+
151
+ # :category: Attributes
152
+
144
153
  # Force the column to have String type and then convert all items to
145
154
  # strings.
146
- def force_to_string_type
155
+ def force_string!
147
156
  # msg = "Can only force an empty column to String type"
148
157
  # raise UserError, msg unless empty?
149
158
  @type = 'String'
@@ -175,66 +184,92 @@ module FatTable
175
184
 
176
185
  # The names of the known aggregate operations that can be performed on a
177
186
  # Column.
178
- VALID_AGGREGATES = %s(first last rng
179
- sum count min max avg var dev
187
+ VALID_AGGREGATES = %s(first last range
188
+ sum count min max
189
+ avg var pvar dev pdev
180
190
  any? all? none? one?)
181
191
 
182
192
  # :category: Aggregates
183
193
 
184
194
  # Return the first non-nil item in the Column. Works with any Column type.
185
195
  def first
186
- items.compact.first
196
+ if type == 'String'
197
+ items.reject(&:blank?).first
198
+ else
199
+ items.compact.first
200
+ end
187
201
  end
188
202
 
189
203
  # :category: Aggregates
190
204
 
191
205
  # Return the last non-nil item in the Column. Works with any Column type.
192
206
  def last
193
- items.compact.last
207
+ if type == 'String'
208
+ items.reject(&:blank?).last
209
+ else
210
+ items.compact.last
211
+ end
194
212
  end
195
213
 
196
214
  # :category: Aggregates
197
215
 
198
- # Return a string of the #first and #last non-nil values in the Column.
199
- # Works with any Column type.
200
- def rng
201
- "#{first}..#{last}"
216
+ # Return a count of the non-nil items in the Column. Works with any Column
217
+ # type.
218
+ def count
219
+ if type == 'String'
220
+ items.reject(&:blank?).count.to_d
221
+ else
222
+ items.compact.count.to_d
223
+ end
202
224
  end
203
225
 
204
226
  # :category: Aggregates
205
227
 
206
- # Return the sum of the non-nil items in the Column. Works with numeric and
207
- # string Columns. For a string Column, it will return the concatenation of
208
- # the non-nil items.
209
- def sum
210
- only_with('sum', 'Numeric', 'String')
211
- items.compact.sum
228
+ # Return the smallest non-nil, non-blank item in the Column. Works with
229
+ # numeric, string, and datetime Columns.
230
+ def min
231
+ only_with('min', 'NilClass', 'Numeric', 'String', 'DateTime')
232
+ if type == 'String'
233
+ items.reject(&:blank?).min
234
+ else
235
+ items.compact.min
236
+ end
212
237
  end
213
238
 
214
239
  # :category: Aggregates
215
240
 
216
- # Return a count of the non-nil items in the Column. Works with any Column
217
- # type.
218
- def count
219
- items.compact.count.to_d
241
+ # Return the largest non-nil, non-blank item in the Column. Works with
242
+ # numeric, string, and datetime Columns.
243
+ def max
244
+ only_with('max', 'NilClass', 'Numeric', 'String', 'DateTime')
245
+ if type == 'String'
246
+ items.reject(&:blank?).max
247
+ else
248
+ items.compact.max
249
+ end
220
250
  end
221
251
 
222
252
  # :category: Aggregates
223
253
 
224
- # Return the smallest non-nil item in the Column. Works with numeric,
225
- # string, and datetime Columns.
226
- def min
227
- only_with('min', 'NilClass', 'Numeric', 'String', 'DateTime')
228
- items.compact.min
254
+ # Return a Range object for the smallest to largest value in the column.
255
+ # Works with numeric, string, and datetime Columns.
256
+ def range
257
+ only_with('range', 'NilClass', 'Numeric', 'String', 'DateTime')
258
+ Range.new(min, max)
229
259
  end
230
260
 
231
261
  # :category: Aggregates
232
262
 
233
- # Return the largest non-nil item in the Column. Works with numeric,
234
- # string, and datetime Columns.
235
- def max
236
- only_with('max', 'NilClass', 'Numeric', 'String', 'DateTime')
237
- items.compact.max
263
+ # Return the sum of the non-nil items in the Column. Works with numeric and
264
+ # string Columns. For a string Column, it will return the concatenation of
265
+ # the non-nil items.
266
+ def sum
267
+ only_with('sum', 'Numeric', 'String')
268
+ if type == 'String'
269
+ items.reject(&:blank?).join(' ')
270
+ else
271
+ items.compact.sum
272
+ end
238
273
  end
239
274
 
240
275
  # :category: Aggregates
@@ -374,9 +409,18 @@ module FatTable
374
409
 
375
410
  # Append +itm+ to end of the Column after converting it to the Column's
376
411
  # type. If the Column's type is still open, i.e. NilClass, attempt to fix
377
- # the Column's type based on the type of +itm+ as with Column.new.
412
+ # the Column's type based on the type of +itm+ as with Column.new. If its
413
+ # a tolerant column, respond to type errors by converting the column to a
414
+ # String type.
378
415
  def <<(itm)
379
416
  items << convert_to_type(itm)
417
+ rescue IncompatibleTypeError => ex
418
+ if tolerant?
419
+ force_string!
420
+ retry
421
+ else
422
+ raise ex
423
+ end
380
424
  end
381
425
 
382
426
  # :category: Constructors
@@ -392,187 +436,24 @@ module FatTable
392
436
 
393
437
  private
394
438
 
395
- # Convert val to the type of key, a ruby class constant, such as Date,
396
- # Numeric, etc. If type is NilClass, the type is open, and a non-blank val
397
- # will attempt conversion to one of the allowed types, typing it as a String
398
- # if no other type is recognized. If the val is blank, and the type is nil,
399
- # the Column type remains open. If the val is nil or a blank and the type is
400
- # already determined, the val is set to nil, and should be filtered from any
401
- # Column computations. If the val is non-blank and the Column type
402
- # determined, raise an error if the val cannot be converted to the Column
403
- # type. Otherwise, returns the converted val as an object of the correct
404
- # class.
405
439
  def convert_to_type(val)
406
- case type
407
- when 'NilClass'
408
- if val != false && val.blank?
409
- # Leave the type of the Column open. Unfortunately, false counts as
410
- # blank and we don't want it to. It should be classified as a boolean.
411
- new_val = nil
412
- else
413
- # Only non-blank values are allowed to set the type of the Column
414
- bool_val = convert_to_boolean(val)
415
- new_val =
416
- if bool_val.nil?
417
- convert_to_date_time(val) ||
418
- convert_to_numeric(val) ||
419
- convert_to_string(val)
420
- else
421
- bool_val
422
- end
423
- @type =
424
- if [true, false].include?(new_val)
425
- 'Boolean'
426
- elsif new_val.is_a?(Date) || new_val.is_a?(DateTime)
427
- 'DateTime'
428
- elsif new_val.is_a?(Numeric)
429
- 'Numeric'
430
- elsif new_val.is_a?(String)
431
- 'String'
432
- else
433
- msg = "can't add #{val} of type #{new_val.class.name} to a column"
434
- raise UserError, msg
435
- end
436
- end
437
- new_val
438
- when 'Boolean'
439
- if val.is_a?(String) && val.blank? || val.nil?
440
- nil
441
- else
442
- new_val = convert_to_boolean(val)
443
- if new_val.nil?
444
- msg = "attempt to add '#{val}' to a column already typed as #{type}"
445
- raise UserError, msg
446
- end
447
- new_val
448
- end
449
- when 'DateTime'
450
- if val.blank?
451
- nil
452
- else
453
- new_val = convert_to_date_time(val)
454
- if new_val.nil?
455
- msg = "attempt to add '#{val}' to a column already typed as #{type}"
456
- raise UserError, msg
457
- end
458
- new_val
459
- end
460
- when 'Numeric'
461
- if val.blank?
462
- nil
463
- else
464
- new_val = convert_to_numeric(val)
465
- if new_val.nil?
466
- msg = "attempt to add '#{val}' to a column already typed as #{type}"
467
- raise UserError, msg
468
- end
469
- new_val
470
- end
471
- when 'String'
472
- if val.nil?
473
- nil
474
- else
475
- new_val = convert_to_string(val)
476
- if new_val.nil?
477
- msg = "attempt to add '#{val}' to a column already typed as #{type}"
440
+ new_val = Convert.convert_to_type(val, type)
441
+ if new_val && type == 'NilClass'
442
+ @type =
443
+ if [true, false].include?(new_val)
444
+ 'Boolean'
445
+ elsif new_val.is_a?(Date) || new_val.is_a?(DateTime)
446
+ 'DateTime'
447
+ elsif new_val.is_a?(Numeric)
448
+ 'Numeric'
449
+ elsif new_val.is_a?(String)
450
+ 'String'
451
+ else
452
+ msg = "can't add value '#{val}' of type #{new_val.class.name} to a column"
478
453
  raise UserError, msg
479
454
  end
480
- new_val
481
- end
482
- else
483
- raise UserError, "Mysteriously, column has unknown type '#{type}'"
484
- end
485
- end
486
-
487
- # Convert the val to a boolean if it looks like one, otherwise return nil.
488
- # Any boolean or a string of t, f, true, false, y, n, yes, or no, regardless
489
- # of case is assumed to be a boolean.
490
- def convert_to_boolean(val)
491
- return val if val.is_a?(TrueClass) || val.is_a?(FalseClass)
492
- val = val.to_s.clean
493
- return nil if val.blank?
494
- if val.match?(/\A(false|f|n|no)\z/i)
495
- false
496
- elsif val.match?(/\A(true|t|y|yes)\z/i)
497
- true
498
- end
499
- end
500
-
501
- ISO_DATE_RE = %r{(?<yr>\d\d\d\d)[-\/]
502
- (?<mo>\d\d?)[-\/]
503
- (?<dy>\d\d?)\s*
504
- (T?\s*\d\d:\d\d(:\d\d)?
505
- ([-+](\d\d?)(:\d\d?))?)?}x
506
-
507
- AMR_DATE_RE = %r{(?<dy>\d\d?)[-/](?<mo>\d\d?)[-/](?<yr>\d\d\d\d)\s*
508
- (?<tm>T\d\d:\d\d:\d\d(\+\d\d:\d\d)?)?}x
509
-
510
- # A Date like 'Tue, 01 Nov 2016' or 'Tue 01 Nov 2016' or '01 Nov 2016'.
511
- # These are emitted by Postgresql, so it makes from_sql constructor
512
- # possible without special formatting of the dates.
513
- INV_DATE_RE = %r{((mon|tue|wed|thu|fri|sat|sun)[a-zA-z]*,?)?\s+ # looks like dow
514
- (?<dy>\d\d?)\s+ # one or two-digit day
515
- (?<mo_name>[jfmasondJFMASOND][A-Za-z]{2,})\s+ # looks like a month name
516
- (?<yr>\d\d\d\d) # and a 4-digit year
517
- }xi
518
-
519
- # Convert the val to a DateTime if it is either a DateTime, a Date, a Time, or a
520
- # String that can be parsed as a DateTime, otherwise return nil. It only
521
- # recognizes strings that contain a something like '2016-01-14' or '2/12/1985'
522
- # within them, otherwise DateTime.parse would treat many bare numbers as dates,
523
- # such as '2841381', which it would recognize as a valid date, but the user
524
- # probably does not intend it to be so treated.
525
- def convert_to_date_time(val)
526
- return val if val.is_a?(DateTime)
527
- return val if val.is_a?(Date)
528
- return val.to_datetime if val.is_a?(Time)
529
- begin
530
- str = val.to_s.clean
531
- return nil if str.blank?
532
-
533
- if str.match(ISO_DATE_RE)
534
- date = DateTime.parse(val)
535
- elsif str =~ AMR_DATE_RE
536
- date = DateTime.new(Regexp.last_match[:yr].to_i,
537
- Regexp.last_match[:mo].to_i,
538
- Regexp.last_match[:dy].to_i)
539
- elsif str =~ INV_DATE_RE
540
- mo = Date.mo_name_to_num(last_match[:mo_name])
541
- date = DateTime.new(Regexp.last_match[:yr].to_i, mo,
542
- Regexp.last_match[:dy].to_i)
543
- else
544
- return nil
545
- end
546
- # val = val.to_date if
547
- date.seconds_since_midnight.zero? ? date.to_date : date
548
- rescue ArgumentError
549
- nil
550
455
  end
551
- end
552
-
553
- # Convert the val to a Numeric if is already a Numeric or is a String that
554
- # looks like one. Any Float is promoted to a BigDecimal. Otherwise return
555
- # nil.
556
- def convert_to_numeric(val)
557
- return BigDecimal(val, Float::DIG) if val.is_a?(Float)
558
- return val if val.is_a?(Numeric)
559
- # Eliminate any commas, $'s (or other currency symbol), or _'s.
560
- cursym = Regexp.quote(FatTable.currency_symbol)
561
- clean_re = /[,_#{cursym}]/
562
- val = val.to_s.clean.gsub(clean_re, '')
563
- return nil if val.blank?
564
- case val
565
- when /(\A[-+]?\d+\.\d*\z)|(\A[-+]?\d*\.\d+\z)/
566
- BigDecimal(val.to_s.clean)
567
- when /\A[-+]?[\d]+\z/
568
- val.to_i
569
- when %r{\A(?<nm>[-+]?\d+)\s*[:/]\s*(?<dn>[-+]?\d+)\z}
570
- Rational(Regexp.last_match[:nm], Regexp.last_match[:dn])
571
- end
572
- end
573
-
574
- def convert_to_string(val)
575
- val.to_s
456
+ new_val
576
457
  end
577
458
  end
578
459
  end