fat_table 0.2.8 → 0.2.9

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
  SHA256:
3
- metadata.gz: 558944c93313d81954da19744fec105b8562a4634781f77accd0fd7677dce76b
4
- data.tar.gz: e301c37c690d01a77a24679e676c35cefd0f68b01d72b4e16835e54e44223790
3
+ metadata.gz: af65227dda201238ba06b2296e548bcfbab9cc209ad66fc7e5efafe6bbcde8d5
4
+ data.tar.gz: f59e53d1ec7aa54a36e96d475f32d50e0d7b668a838476fe3e73f9cd091396f4
5
5
  SHA512:
6
- metadata.gz: 6430e39eb4261ab51eb855a0e3119e7bfae2e0f104215e637d8091d8d2ba4847f8b2e91ee1b1be08531bc69a72dc4a4b6233fbbc2d0f8fa7b43c11c73ac8c305
7
- data.tar.gz: 1eec9ab1576cdda1ebdcd0833601573f343ecab9cd16244c6fd4038b6a3dc86ba7303b693e7c7d852ef1443e9b2b3d20b9ff32ccb652fcb73a92e7337d3511c7
6
+ metadata.gz: 3e5d1f93e4c0fb505afd5f8f5e1c2cb918d31653a4c64ce2db63cd20733fdccd75649f756cb90597c761a61a26d4a76ddaf8a34f7f9f4db8029cd93db62dc70d
7
+ data.tar.gz: a6f8b68c21b13382cb6cff7b65f05ed8de120d6e1296ccf2376152da92ba30efbee5196d9b792642e8f3097ed57f11147cc5eac65a330acb4efe4719bae51a79
@@ -17,4 +17,5 @@ rvm:
17
17
  - 2.3
18
18
  - 2.4
19
19
  - 2.5
20
+ - 2.6
20
21
  - ruby-head
data/README.org CHANGED
@@ -533,7 +533,7 @@ database parameters to be used for the queries.
533
533
  #+BEGIN_SRC ruby
534
534
  # This automatically requires sequel.
535
535
  require 'fat_table'
536
- FatTable.set_db(adapter: 'postgres',
536
+ FatTable.connect(adapter: 'postgres',
537
537
  database: 'XXX_development',
538
538
  user: 'ken',
539
539
  password: 'imsecret',
@@ -541,8 +541,8 @@ database parameters to be used for the queries.
541
541
  tab = FatTable.from_sql('select * from trades;')
542
542
  #+END_SRC
543
543
 
544
- The arguments to ~set_db~ are simply passed on to ~sequel~'s connect method, so
545
- any set of arguments that work for it should work for ~set_db~. Alternatively,
544
+ The arguments to ~connect~ are simply passed on to ~sequel~'s connect method, so
545
+ any set of arguments that work for it should work for ~connect~. Alternatively,
546
546
  you can build the ~Sequel~ connection directly with ~Sequel.connect~ or with
547
547
  adapter-specific ~Sequel~ connection methods and let ~FatTable~ know to use that
548
548
  connection:
@@ -556,8 +556,8 @@ connection:
556
556
  Consult ~Sequel's~ documentation for details on its connection methods.
557
557
  [[http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html]]
558
558
 
559
- The ~.set_db~ function need only be called once, and the database handle it
560
- creates will be used for all subsequent ~.from_sql~ calls until ~.set_db~ is
559
+ The ~.connect~ function need only be called once, and the database handle it
560
+ creates will be used for all subsequent ~.from_sql~ calls until ~.connect~ is
561
561
  called again.
562
562
 
563
563
  *** Marking Groups in Input
@@ -485,7 +485,7 @@ Another way to initialize a +FatTable+ table is with the results of a SQL query.
485
485
  database parameters to be used for the queries.
486
486
 
487
487
  require 'fat_table'
488
- FatTable.set_db(driver: 'Pg',
488
+ FatTable.connect(driver: 'Pg',
489
489
  database: 'XXX_development',
490
490
  user: 'dtd',
491
491
  password: 'slflpowert',
@@ -493,15 +493,15 @@ database parameters to be used for the queries.
493
493
  socket: '/tmp/.s.PGSQL.5432')
494
494
  tab = FatTable.from_sql('select * from trades;')
495
495
 
496
- Some of the parameters to the +.set_db+ function have defaults. The driver
496
+ Some of the parameters to the +.connect+ function have defaults. The driver
497
497
  defaults to 'Pg' for postgresql and the socket defaults to +/tmp/.s.PGSQL.5432+
498
498
  if the host is 'localhost', which it is by default. If the host is not
499
499
  'localhost', the dsn uses a port rather than a socket and defaults to port
500
500
  '5432'. While user and password default to nil, the database parameter is
501
501
  required.
502
502
 
503
- The +.set_db+ function need only be called once, and the database handle it
504
- creates will be used for all subsequent +.from_sql+ calls until +.set_db+ is
503
+ The +.connect+ function need only be called once, and the database handle it
504
+ creates will be used for all subsequent +.from_sql+ calls until +.connect+ is
505
505
  called again.
506
506
 
507
507
  === Marking Groups in Input
@@ -114,7 +114,7 @@ module FatTable
114
114
  end
115
115
 
116
116
  # Construct a Table by running a SQL query against the database set up with
117
- # FatTable.set_db. Return the Table with the query results as rows and the
117
+ # FatTable.connect. Return the Table with the query results as rows and the
118
118
  # headers from the query, converted to symbols, as headers.
119
119
  def self.from_sql(query)
120
120
  Table.from_sql(query)
@@ -21,7 +21,7 @@ module FatTable
21
21
  attr_reader :type
22
22
 
23
23
  # An Array of the items of this Column, all of which must be values of the
24
- # Columns type or a nil. This Array contains the value of the item after
24
+ # Column's type or a nil. This Array contains the value of the item after
25
25
  # conversion to a native Ruby type, such as TrueClass, Date, DateTime,
26
26
  # Integer, String, etc. Thus, you can perform operations on the items,
27
27
  # perhaps after removing nils with +.items.compact+.
@@ -92,6 +92,7 @@ module FatTable
92
92
  @type = 'NilClass'
93
93
  msg = "unknown column type '#{type}"
94
94
  raise UserError, msg unless TYPES.include?(@type.to_s)
95
+
95
96
  @items = []
96
97
  items.each { |i| self << i }
97
98
  end
@@ -103,8 +104,8 @@ module FatTable
103
104
  # :category: Attributes
104
105
 
105
106
  # Return the item of the Column at the given index.
106
- def [](k)
107
- items[k]
107
+ def [](idx)
108
+ items[idx]
108
109
  end
109
110
 
110
111
  # :category: Attributes
@@ -229,11 +230,13 @@ module FatTable
229
230
  # average back to a DateTime.
230
231
  def avg
231
232
  only_with('avg', 'DateTime', 'Numeric')
233
+ itms = items.compact
234
+ size = itms.size.to_d
232
235
  if type == 'DateTime'
233
- avg_jd = items.compact.map(&:jd).sum / items.compact.size.to_d
236
+ avg_jd = itms.map(&:jd).sum / size
234
237
  DateTime.jd(avg_jd)
235
238
  else
236
- sum / items.compact.size.to_d
239
+ itms.sum / size
237
240
  end
238
241
  end
239
242
 
@@ -515,7 +518,7 @@ module FatTable
515
518
  # looks like one. Any Float is promoted to a BigDecimal. Otherwise return
516
519
  # nil.
517
520
  def convert_to_numeric(val)
518
- return BigDecimal.new(val, Float::DIG) if val.is_a?(Float)
521
+ return BigDecimal(val, Float::DIG) if val.is_a?(Float)
519
522
  return val if val.is_a?(Numeric)
520
523
  # Eliminate any commas, $'s (or other currency symbol), or _'s.
521
524
  cursym = Regexp.quote(FatTable.currency_symbol)
@@ -524,7 +527,7 @@ module FatTable
524
527
  return nil if val.blank?
525
528
  case val
526
529
  when /(\A[-+]?\d+\.\d*\z)|(\A[-+]?\d*\.\d+\z)/
527
- BigDecimal.new(val.to_s.clean)
530
+ BigDecimal(val.to_s.clean)
528
531
  when /\A[-+]?[\d]+\z/
529
532
  val.to_i
530
533
  when %r{\A([-+]?\d+)\s*[:/]\s*([-+]?\d+)\z}
@@ -51,7 +51,7 @@ module FatTable
51
51
  # successfully, this establishes the database handle to use for all subsequent
52
52
  # calls to FatTable.from_sql or FatTable::Table.from_sql. You can then access
53
53
  # the handle if needed with FatTable.db.
54
- def self.set_db(args)
54
+ def self.connect(args)
55
55
  # Set the dsn for Sequel
56
56
  begin
57
57
  self.handle = Sequel.connect(args)
@@ -67,7 +67,7 @@ module FatTable
67
67
  end
68
68
 
69
69
  # Directly set the db handle to a Sequel connection formed without
70
- # FatTable.set_db.
70
+ # FatTable.connect.
71
71
  def self.db=(db)
72
72
  self.handle = db
73
73
  end
@@ -20,23 +20,25 @@ module FatTable
20
20
  def initialize(ivars: {}, before: nil, after: nil)
21
21
  @before = before
22
22
  @after = after
23
- set_instance_vars(ivars)
23
+ instance_vars(ivars)
24
24
  end
25
25
 
26
26
  # Set the @group instance variable to the given value.
27
27
  def update_ivars(ivars)
28
- set_instance_vars(ivars)
28
+ instance_vars(ivars)
29
29
  end
30
30
 
31
31
  # Run any before hook in the context of the given local variables.
32
32
  def eval_before_hook(locals: {})
33
33
  return if @before.blank?
34
+
34
35
  evaluate(@before, locals: locals)
35
36
  end
36
37
 
37
38
  # Run any after hook in the context of the given local variables.
38
39
  def eval_after_hook(locals: {})
39
40
  return if @after.blank?
41
+
40
42
  evaluate(@after, locals: locals)
41
43
  end
42
44
 
@@ -44,19 +46,21 @@ module FatTable
44
46
  # instance variables set in Evaluator.new and any local variables set in the
45
47
  # Hash parameter +locals+ are available to the expression.
46
48
  def evaluate(expr = '', locals: {})
47
- eval(expr, set_local_vars(binding, locals))
49
+ eval(expr, local_vars(binding, locals))
48
50
  end
49
51
 
50
52
  private
51
53
 
52
- def set_instance_vars(vars = {})
54
+ # Set the instance variables according to Hash vars.
55
+ def instance_vars(vars = {})
53
56
  vars.each_pair do |name, val|
54
57
  name = "@#{name}" unless name.to_s.start_with?('@')
55
58
  instance_variable_set(name, val)
56
59
  end
57
60
  end
58
61
 
59
- def set_local_vars(bnd, vars = {})
62
+ # Set the local variables within the binding bnd according to Hash vars.
63
+ def local_vars(bnd, vars = {})
60
64
  vars.each_pair do |name, val|
61
65
  bnd.local_variable_set(name, val)
62
66
  end
@@ -30,20 +30,20 @@ module FatTable
30
30
  '['
31
31
  end
32
32
 
33
- def pre_cell(_h)
33
+ def pre_cell(_val)
34
34
  "'"
35
35
  end
36
36
 
37
37
  # Because the cell, after conversion to a single-quoted string will be
38
38
  # eval'ed, we need to escape any single-quotes (') that appear in the
39
39
  # string.
40
- def quote_cell(v)
41
- if v.match?(/'/)
40
+ def quote_cell(val)
41
+ if val.match?(/'/)
42
42
  # Use a negative look-behind to only quote single-quotes that are not
43
43
  # already preceded by a backslash
44
- v.gsub(/(?<!\\)'/, "'" => "\\'")
44
+ val.gsub(/(?<!\\)'/, "'" => "\\'")
45
45
  else
46
- v
46
+ val
47
47
  end
48
48
  end
49
49
 
@@ -30,20 +30,20 @@ module FatTable
30
30
  '{'
31
31
  end
32
32
 
33
- def pre_cell(h)
34
- ":#{h.as_sym} => '"
33
+ def pre_cell(head)
34
+ ":#{head.as_sym} => '"
35
35
  end
36
36
 
37
37
  # Because the cell, after conversion to a single-quoted string will be
38
38
  # eval'ed, we need to escape any single-quotes (') that appear in the
39
39
  # string.
40
- def quote_cell(v)
41
- if v.match?(/'/)
40
+ def quote_cell(val)
41
+ if val.match?(/'/)
42
42
  # Use a negative look-behind to only quote single-quotes that are not
43
43
  # already preceded by a backslash
44
- v.gsub(/(?<!\\)'/, "'" => "\\'")
44
+ val.gsub(/(?<!\\)'/, "'" => "\\'")
45
45
  else
46
- v
46
+ val
47
47
  end
48
48
  end
49
49
 
@@ -92,9 +92,10 @@ module FatTable
92
92
  # Formatter is yielded to the block so that methods for formatting and
93
93
  # adding footers can be called on it.
94
94
  def initialize(table = Table.new, **options)
95
- unless table && table.is_a?(Table)
95
+ unless table&.is_a?(Table)
96
96
  raise UserError, 'must initialize Formatter with a Table'
97
97
  end
98
+
98
99
  @table = table
99
100
  @options = options
100
101
  @footers = {}
@@ -170,12 +171,14 @@ module FatTable
170
171
  unless table.headers.include?(h)
171
172
  raise UserError, "No '#{h}' column in table to sum in the footer"
172
173
  end
174
+
173
175
  foot[h] = :sum
174
176
  end
175
177
  agg_cols.each do |h, agg|
176
178
  unless table.headers.include?(h)
177
179
  raise UserError, "No '#{h}' column in table to #{agg} in the footer"
178
180
  end
181
+
179
182
  foot[h] = agg
180
183
  end
181
184
  @footers[label] = foot
@@ -208,12 +211,14 @@ module FatTable
208
211
  unless table.headers.include?(h)
209
212
  raise UserError, "No '#{h}' column in table for group sum footer"
210
213
  end
214
+
211
215
  foot[h] = :sum
212
216
  end
213
217
  agg_cols.each do |h, agg|
214
218
  unless table.headers.include?(h)
215
219
  raise UserError, "No '#{h}' column in table for #{agg} group footer"
216
220
  end
221
+
217
222
  foot[h] = agg
218
223
  end
219
224
  @gfooters[label] = foot
@@ -466,6 +471,7 @@ module FatTable
466
471
  unless LOCATIONS.include?(location)
467
472
  raise UserError, "unknown format location '#{location}'"
468
473
  end
474
+
469
475
  valid_keys = table.headers + %i[string numeric datetime boolean nil]
470
476
  invalid_keys = (fmts.keys - valid_keys).uniq
471
477
  unless invalid_keys.empty?
@@ -487,18 +493,18 @@ module FatTable
487
493
  # Merge in string and nil formatting, but not in header. Header is
488
494
  # always typed a string, so it will get formatted in type-based
489
495
  # formatting below. And headers are never nil.
490
- if fmts.keys.include?(:string)
496
+ if fmts.key?(:string)
491
497
  typ_fmt = parse_string_fmt(fmts[:string])
492
498
  format_h = format_h.merge(typ_fmt)
493
499
  end
494
- if fmts.keys.include?(:nil)
500
+ if fmts.key?(:nil)
495
501
  typ_fmt = parse_nil_fmt(fmts[:nil]).first
496
502
  format_h = format_h.merge(typ_fmt)
497
503
  end
498
504
  end
499
505
  typ = location == :header ? :string : table.type(h).as_sym
500
506
  parse_typ_method_name = 'parse_' + typ.to_s + '_fmt'
501
- if fmts.keys.include?(typ)
507
+ if fmts.key?(typ)
502
508
  # Merge in type-based formatting
503
509
  typ_fmt = send(parse_typ_method_name, fmts[typ])
504
510
  format_h = format_h.merge(typ_fmt)
@@ -547,7 +553,7 @@ module FatTable
547
553
  private
548
554
 
549
555
  # Re to match a color name
550
- CLR_RE = /(?:[-_a-zA-Z0-9 ]*)/
556
+ CLR_RE = /(?:[-_a-zA-Z0-9 ]*)/.freeze
551
557
 
552
558
  # Return a hash that reflects the formatting instructions given in the
553
559
  # string fmt. Raise an error if it contains invalid formatting instructions.
@@ -558,6 +564,7 @@ module FatTable
558
564
  unless fmt.blank? || !strict
559
565
  raise UserError, "unrecognized string formatting instructions '#{fmt}'"
560
566
  end
567
+
561
568
  format
562
569
  end
563
570
 
@@ -668,6 +675,7 @@ module FatTable
668
675
  unless fmt.blank? || !strict
669
676
  raise UserError, "unrecognized numeric formatting instructions '#{fmt}'"
670
677
  end
678
+
671
679
  fmt_hash
672
680
  end
673
681
 
@@ -739,6 +747,7 @@ module FatTable
739
747
  unless fmt.blank? || !strict
740
748
  raise UserError, "unrecognized boolean formatting instructions '#{fmt}'"
741
749
  end
750
+
742
751
  fmt_hash
743
752
  end
744
753
 
@@ -810,6 +819,7 @@ module FatTable
810
819
  # specializing this method.
811
820
  def format_boolean(val, istruct)
812
821
  return istruct.nil_text if val.nil?
822
+
813
823
  val ? istruct.true_text : istruct.false_text
814
824
  end
815
825
 
@@ -820,6 +830,7 @@ module FatTable
820
830
  # specializing this method.
821
831
  def format_datetime(val, istruct)
822
832
  return istruct.nil_text if val.nil?
833
+
823
834
  if val.to_date == val
824
835
  # It is a Date, with no time component.
825
836
  val.strftime(istruct.date_fmt)
@@ -835,6 +846,7 @@ module FatTable
835
846
  # specializing this method.
836
847
  def format_numeric(val, istruct)
837
848
  return istruct.nil_text if val.nil?
849
+
838
850
  val = val.round(istruct.post_digits) if istruct.post_digits >= 0
839
851
  if istruct.hms
840
852
  result = val.secs_to_hms
@@ -998,6 +1010,7 @@ module FatTable
998
1010
  new_rows.each do |loc_row|
999
1011
  result += hline(widths) if loc_row.nil?
1000
1012
  next if loc_row.nil?
1013
+
1001
1014
  _loc, row = *loc_row
1002
1015
  result += pre_row
1003
1016
  cells = []
@@ -1140,6 +1153,7 @@ module FatTable
1140
1153
  end
1141
1154
  rows.each do |loc_row|
1142
1155
  next if loc_row.nil?
1156
+
1143
1157
  _loc, row = *loc_row
1144
1158
  row.each_pair do |h, (_v, fmt_v)|
1145
1159
  widths[h] ||= 0
@@ -1222,12 +1236,12 @@ module FatTable
1222
1236
  ''
1223
1237
  end
1224
1238
 
1225
- def pre_cell(_h)
1239
+ def pre_cell(_head)
1226
1240
  ''
1227
1241
  end
1228
1242
 
1229
- def quote_cell(v)
1230
- v
1243
+ def quote_cell(val)
1244
+ val
1231
1245
  end
1232
1246
 
1233
1247
  def post_cell
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module FatTable
2
4
  # A subclass of Formatter for rendering the table as a LaTeX table. It allows
3
5
  # foreground colors through LaTeX's xcolor package but ignores background
@@ -17,7 +19,6 @@ module FatTable
17
19
  # LaTeX tabular-like environment to use for the table. The default is good
18
20
  # for tables that might continue over multiple pages since it repeats the
19
21
  # header at the top of each continuation page.
20
-
21
22
  def initialize(table = Table.new, **options)
22
23
  super
23
24
  @options[:document] = options.fetch(:document, false)
@@ -115,7 +116,8 @@ module FatTable
115
116
  result = ''
116
117
  result += '\\bfseries{}' if istruct.bold
117
118
  result += '\\itshape{}' if istruct.italic
118
- result += "\\color{#{istruct.color}}" if istruct.color && istruct.color != 'none'
119
+ result += "\\color{#{istruct.color}}" if istruct.color &&
120
+ istruct.color != 'none'
119
121
  result = "#{result}#{str}"
120
122
  unless istruct.alignment == format_at[:body][istruct._h].alignment
121
123
  ac = alignment_code(istruct.alignment)
@@ -173,14 +175,14 @@ module FatTable
173
175
  ''
174
176
  end
175
177
 
176
- def pre_cell(_h)
178
+ def pre_cell(_head)
177
179
  ''
178
180
  end
179
181
 
180
182
  # We do quoting before applying decoration, so do not re-quote here. We
181
183
  # will have LaTeX commands in v.
182
- def quote_cell(v)
183
- v
184
+ def quote_cell(val)
185
+ val
184
186
  end
185
187
 
186
188
  def post_cell
@@ -30,12 +30,12 @@ module FatTable
30
30
  '|'
31
31
  end
32
32
 
33
- def pre_cell(_h)
33
+ def pre_cell(_head)
34
34
  ''
35
35
  end
36
36
 
37
- def quote_cell(v)
38
- v
37
+ def quote_cell(val)
38
+ val
39
39
  end
40
40
 
41
41
  def post_cell
@@ -27,6 +27,7 @@ module FatTable
27
27
  @options[:unicode] = options.fetch(:unicode, true)
28
28
  @options[:framecolor] = options.fetch(:framecolor, 'none.none')
29
29
  return unless @options[:framecolor] =~ /([-_a-zA-Z]*)(\.([-_a-zA-Z]*))/
30
+
30
31
  @options[:frame_fg] = $1.downcase unless $1.blank?
31
32
  @options[:frame_bg] = $3.downcase unless $3.blank?
32
33
  end
@@ -59,6 +60,7 @@ module FatTable
59
60
 
60
61
  def strip_ansi(str)
61
62
  return '' unless str
63
+
62
64
  str.gsub(/\e\[[0-9;]+m/, '')
63
65
  end
64
66
 
@@ -73,18 +75,19 @@ module FatTable
73
75
  result
74
76
  end
75
77
 
76
- def colorize(str, fg, bg)
77
- fg = nil if fg == 'none'
78
- bg = nil if bg == 'none'
79
- return str unless fg || bg
78
+ def colorize(str, fg_color, bg_color)
79
+ fg_color = nil if fg_color == 'none'
80
+ bg_color = nil if bg_color == 'none'
81
+ return str unless fg_color || bg_color
82
+
80
83
  result = Rainbow(str)
81
- if fg
82
- fg = fg.tr(' ', '').downcase.as_sym
83
- result = result.color(fg) if fg
84
+ if fg_color
85
+ fg_color = fg_color.tr(' ', '').downcase.as_sym
86
+ result = result.color(fg_color) if fg_color
84
87
  end
85
- if bg
86
- bg = bg.tr(' ', '').downcase.as_sym
87
- result = result.bg(bg) if bg
88
+ if bg_color
89
+ bg_color = bg_color.tr(' ', '').downcase.as_sym
90
+ result = result.bg(bg_color) if bg_color
88
91
  end
89
92
  result
90
93
  end
@@ -229,12 +232,12 @@ module FatTable
229
232
  frame_colorize(vertical_rule)
230
233
  end
231
234
 
232
- def pre_cell(_h)
235
+ def pre_cell(_head)
233
236
  ''
234
237
  end
235
238
 
236
- def quote_cell(v)
237
- v
239
+ def quote_cell(val)
240
+ val
238
241
  end
239
242
 
240
243
  def post_cell
@@ -26,12 +26,12 @@ module FatTable
26
26
  '|'
27
27
  end
28
28
 
29
- def pre_cell(_h)
29
+ def pre_cell(_head)
30
30
  ''
31
31
  end
32
32
 
33
- def quote_cell(v)
34
- v
33
+ def quote_cell(val)
34
+ val
35
35
  end
36
36
 
37
37
  def post_cell
@@ -19,8 +19,8 @@ end
19
19
  unless ''.respond_to?(:match?)
20
20
  # Add String#match? to pre-2.4 ruby
21
21
  class String
22
- def match?(re)
23
- self =~ re
22
+ def match?(regexp)
23
+ self =~ regexp
24
24
  end
25
25
  end
26
26
  end
@@ -35,6 +35,7 @@ unless //.respond_to?(:match?)
35
35
  end
36
36
 
37
37
  unless ''.respond_to?(:strip_heredoc)
38
+ # Patch String to provide heredocs with whitespace stripped
38
39
  class String
39
40
  def strip_heredoc
40
41
  indent = chomp.scan(/^\s*/).min.size
@@ -106,18 +106,19 @@ module FatTable
106
106
  # :category: Constructors
107
107
 
108
108
  # Construct a new table from an Array of Arrays +aoa+. By default, with
109
- # +hlines+ set to false, do not look for separators, i.e. +nils+, just treat
110
- # the first row as headers. With +hlines+ set true, expect +nil+ separators
111
- # to mark the header row and any boundaries. If the second element of the
112
- # array is a +nil+, interpret the first element of the array as a row of
113
- # headers. Otherwise, synthesize headers of the form +:col_1+, +:col_2+, ...
114
- # and so forth. The remaining elements are taken as the body of the table,
115
- # except that if an element of the outer array is a +nil+, mark the
116
- # preceding row as a group boundary. Note for Emacs users: In org mode code
117
- # blocks when an org-mode table is passed in as a variable it is passed in
118
- # as an Array of Arrays. By default (+ HEADER: :hlines no +) org-mode strips
119
- # all from the table; otherwise (+ HEADER: :hlines yes +) they are indicated
120
- # with nil elements in the outer array.
109
+ # +hlines+ set to false, do not look for separators, i.e. +nils+, just
110
+ # treat the first row as headers. With +hlines+ set true, expect +nil+
111
+ # separators to mark the header row and any boundaries. If the second
112
+ # element of the array is a +nil+, interpret the first element of the
113
+ # array as a row of headers. Otherwise, synthesize headers of the form
114
+ # +:col_1+, +:col_2+, ... and so forth. The remaining elements are taken
115
+ # as the body of the table, except that if an element of the outer array
116
+ # is a +nil+, mark the preceding row as a group boundary. Note for Emacs
117
+ # users: In org mode code blocks when an org-mode table is passed in as a
118
+ # variable it is passed in as an Array of Arrays. By default (+ HEADER:
119
+ # :hlines no +) org-mode strips all hrules from the table; otherwise (+
120
+ # HEADER: :hlines yes +) they are indicated with nil elements in the outer
121
+ # array.
121
122
  def self.from_aoa(aoa, hlines: false)
122
123
  from_array_of_arrays(aoa, hlines: hlines)
123
124
  end
@@ -149,10 +150,11 @@ module FatTable
149
150
  # :category: Constructors
150
151
 
151
152
  # Construct a Table by running a SQL +query+ against the database set up
152
- # with FatTable.set_db, with the rows of the query result as rows.
153
+ # with FatTable.connect, with the rows of the query result as rows.
153
154
  def self.from_sql(query)
154
- msg = 'FatTable.db must be set with FatTable.set_db'
155
+ msg = 'FatTable.db must be set with FatTable.connect'
155
156
  raise UserError, msg if FatTable.db.nil?
157
+
156
158
  result = Table.new
157
159
  FatTable.db[query].each do |h|
158
160
  result << h
@@ -257,6 +259,7 @@ module FatTable
257
259
  unless table_found
258
260
  # Skip through the file until a table is found
259
261
  next unless line.match?(table_re)
262
+
260
263
  unless line.match?(hrule_re)
261
264
  line = line.sub(/\A\s*\|/, '').sub(/\|\s*\z/, '')
262
265
  rows << line.split('|').map(&:clean)
@@ -265,6 +268,7 @@ module FatTable
265
268
  next
266
269
  end
267
270
  break unless line.match?(table_re)
271
+
268
272
  if !header_found && line =~ hrule_re
269
273
  rows << nil
270
274
  header_found = true
@@ -272,7 +276,7 @@ module FatTable
272
276
  elsif header_found && line =~ hrule_re
273
277
  # Mark the boundary with a nil
274
278
  rows << nil
275
- elsif line !~ table_re
279
+ elsif !line.match?(table_re)
276
280
  # Stop reading at the second hline
277
281
  break
278
282
  else
@@ -316,14 +320,17 @@ module FatTable
316
320
  when Integer
317
321
  msg = "index '#{key}' out of range"
318
322
  raise UserError, msg unless (0..size - 1).cover?(key.abs)
323
+
319
324
  rows[key]
320
325
  when String
321
326
  msg = "header '#{key}' not in table"
322
327
  raise UserError, msg unless headers.include?(key)
328
+
323
329
  column(key).items
324
330
  when Symbol
325
331
  msg = "header ':#{key}' not in table"
326
332
  raise UserError, msg unless headers.include?(key)
333
+
327
334
  column(key).items
328
335
  else
329
336
  raise UserError, "cannot index table with a #{key.class}"
@@ -360,6 +367,7 @@ module FatTable
360
367
  # Return the number of rows in the Table.
361
368
  def size
362
369
  return 0 if columns.empty?
370
+
363
371
  columns.first.size
364
372
  end
365
373
 
@@ -368,6 +376,7 @@ module FatTable
368
376
  # Return the number of Columns in the Table.
369
377
  def width
370
378
  return 0 if columns.empty?
379
+
371
380
  columns.size
372
381
  end
373
382
 
@@ -406,6 +415,7 @@ module FatTable
406
415
  last ||= size - 1
407
416
  last = [last, 0].max
408
417
  raise UserError, 'first must be <= last' unless first <= last
418
+
409
419
  rows = []
410
420
  unless columns.empty?
411
421
  first.upto(last) do |rnum|
@@ -493,12 +503,12 @@ module FatTable
493
503
  self
494
504
  end
495
505
 
496
- # Mark a group boundary at row +k+, and if +k+ is +nil+, mark the last row
497
- # in the table as a group boundary. This is mainly used for internal
506
+ # Mark a group boundary at row +row+, and if +row+ is +nil+, mark the last
507
+ # row in the table as a group boundary. This is mainly used for internal
498
508
  # purposes.
499
- def mark_boundary(k = nil) # :nodoc:
500
- if k
501
- boundaries.push(k)
509
+ def mark_boundary(row = nil) # :nodoc:
510
+ if row
511
+ boundaries.push(row)
502
512
  else
503
513
  boundaries.push(size - 1)
504
514
  end
@@ -524,20 +534,21 @@ module FatTable
524
534
  @boundaries += bounds.map { |k| k + shift }
525
535
  end
526
536
 
527
- # Return the group number to which row k belongs. Groups, from the user's
528
- # point of view are indexed starting at 1.
529
- def row_index_to_group_index(k)
537
+ # Return the group number to which row ~row~ belongs. Groups, from the
538
+ # user's point of view are indexed starting at 1.
539
+ def row_index_to_group_index(row)
530
540
  boundaries.each_with_index do |b_last, g_num|
531
- return (g_num + 1) if k <= b_last
541
+ return (g_num + 1) if row <= b_last
532
542
  end
533
543
  1
534
544
  end
535
545
 
536
- def group_rows(k) # :nodoc:
546
+ def group_rows(row) # :nodoc:
537
547
  normalize_boundaries
538
- return [] unless k < boundaries.size
539
- first = k.zero? ? 0 : boundaries[k - 1] + 1
540
- last = boundaries[k]
548
+ return [] unless row < boundaries.size
549
+
550
+ first = row.zero? ? 0 : boundaries[row - 1] + 1
551
+ last = boundaries[row]
541
552
  rows_range(first, last)
542
553
  end
543
554
 
@@ -702,6 +713,7 @@ module FatTable
702
713
  h = k.as_sym
703
714
  msg = "Column '#{h}' in select does not exist"
704
715
  raise UserError, msg unless column?(h)
716
+
705
717
  new_row[h] = old_row[h]
706
718
  end
707
719
  new_cols.each_pair do |key, expr|
@@ -710,7 +722,8 @@ module FatTable
710
722
  case expr
711
723
  when Symbol
712
724
  msg = "Column '#{expr}' in select does not exist"
713
- raise UserError, msg unless vars.keys.include?(expr)
725
+ raise UserError, msg unless vars.key?(expr)
726
+
714
727
  new_row[key] = vars[expr]
715
728
  when String
716
729
  new_row[key] = ev.evaluate(expr, locals: vars)
@@ -864,10 +877,10 @@ module FatTable
864
877
 
865
878
  private
866
879
 
867
- # Apply the set operation given by op between this table and the other table
868
- # given in the first argument. If distinct is true, eliminate duplicates
869
- # from the result.
870
- def set_operation(other, op = :+,
880
+ # Apply the set operation given by ~oper~ between this table and the other
881
+ # table given in the first argument. If distinct is true, eliminate
882
+ # duplicates from the result.
883
+ def set_operation(other, oper = :+,
871
884
  distinct: true,
872
885
  add_boundaries: true,
873
886
  inherit_boundaries: false)
@@ -881,7 +894,7 @@ module FatTable
881
894
  end
882
895
  other_rows = other.rows.map { |r| r.replace_keys(headers) }
883
896
  result = Table.new
884
- new_rows = rows.send(op, other_rows)
897
+ new_rows = rows.send(oper, other_rows)
885
898
  new_rows.each_with_index do |row, k|
886
899
  result << row
887
900
  result.mark_boundary if k == size - 1 && add_boundaries
@@ -975,6 +988,7 @@ module FatTable
975
988
  unless JOIN_TYPES.include?(join_type)
976
989
  raise UserError, "join_type may only be: #{JOIN_TYPES.join(', ')}"
977
990
  end
991
+
978
992
  # These may be needed for outer joins.
979
993
  self_row_nils = headers.map { |h| [h, nil] }.to_h
980
994
  other_row_nils = other.headers.map { |h| [h, nil] }.to_h
@@ -992,6 +1006,7 @@ module FatTable
992
1006
  locals = build_locals_hash(row_a: self_row, row_b: other_row)
993
1007
  matches = ev.evaluate(join_exp, locals: locals)
994
1008
  next unless matches
1009
+
995
1010
  self_row_matched = other_row_matches[k] = true
996
1011
  out_row = build_out_row(row_a: self_row, row_b: other_row,
997
1012
  common_heads: other_common_heads,
@@ -1000,6 +1015,7 @@ module FatTable
1000
1015
  end
1001
1016
  next unless %i[left full].include?(join_type)
1002
1017
  next if self_row_matched
1018
+
1003
1019
  result << build_out_row(row_a: self_row,
1004
1020
  row_b: other_row_nils,
1005
1021
  type: join_type)
@@ -1007,6 +1023,7 @@ module FatTable
1007
1023
  if %i[right full].include?(join_type)
1008
1024
  other_rows.each_with_index do |other_row, k|
1009
1025
  next if other_row_matches[k]
1026
+
1010
1027
  result << build_out_row(row_a: self_row_nils,
1011
1028
  row_b: other_row,
1012
1029
  type: join_type)
@@ -1090,6 +1107,7 @@ module FatTable
1090
1107
  # and all the headers in the other table with '_b' appended.
1091
1108
  def build_join_expression(exps, other, type)
1092
1109
  return ['true', []] if type == :cross
1110
+
1093
1111
  a_heads = headers
1094
1112
  b_heads = other.headers
1095
1113
  common_heads = a_heads & b_heads
@@ -1120,6 +1138,7 @@ module FatTable
1120
1138
  unless a_heads.include?(a_head)
1121
1139
  raise UserError, "no column '#{a_head}' in table"
1122
1140
  end
1141
+
1123
1142
  if partial_result
1124
1143
  # Second of a pair
1125
1144
  ensure_common_types!(self_h: a_head,
@@ -1138,6 +1157,7 @@ module FatTable
1138
1157
  unless b_heads.include?(b_head)
1139
1158
  raise UserError, "no column '#{b_head}' in second table"
1140
1159
  end
1160
+
1141
1161
  if partial_result
1142
1162
  # Second of a pair
1143
1163
  ensure_common_types!(self_h: last_sym,
@@ -1281,6 +1301,7 @@ module FatTable
1281
1301
  def add_column(col)
1282
1302
  msg = "Table already has a column with header '#{col.header}'"
1283
1303
  raise msg if column?(col.header)
1304
+
1284
1305
  columns << col
1285
1306
  self
1286
1307
  end
@@ -1329,6 +1350,7 @@ module FatTable
1329
1350
  fmt = fmt_type.as_sym
1330
1351
  msg = "unknown format '#{fmt}'"
1331
1352
  raise UserError, msg unless FatTable::FORMATS.include?(fmt)
1353
+
1332
1354
  method = "to_#{fmt}"
1333
1355
  if block_given?
1334
1356
  send method, options, &Proc.new
@@ -1,4 +1,4 @@
1
1
  module FatTable
2
2
  # The current version of FatTable
3
- VERSION = '0.2.8'.freeze
3
+ VERSION = '0.2.9'.freeze
4
4
  end
@@ -597,7 +597,7 @@ database parameters to be used for the queries.
597
597
 
598
598
  # This automatically requires sequel.
599
599
  require 'fat_table'
600
- FatTable.set_db(driver: 'Pg',
600
+ FatTable.connect(driver: 'Pg',
601
601
  database: 'XXX_development',
602
602
  user: 'dtd',
603
603
  password: 'slflpowert',
@@ -605,15 +605,15 @@ database parameters to be used for the queries.
605
605
  socket: '/tmp/.s.PGSQL.5432')
606
606
  tab = FatTable.from_sql('select * from trades;')
607
607
 
608
- Some of the parameters to the `.set_db` function have defaults. The driver
608
+ Some of the parameters to the `.connect` function have defaults. The driver
609
609
  defaults to `'Pg'` for postgresql and the socket defaults to
610
610
  `/tmp/.s.PGSQL.5432` if the host is &rsquo;localhost&rsquo;, which it is by default. If the
611
611
  host is not `'localhost'`, the dsn uses a port rather than a socket and defaults
612
612
  to port `'5432'`. While user and password default to nil, the database parameter
613
613
  is required.
614
614
 
615
- The `.set_db` function need only be called once, and the database handle it
616
- creates will be used for all subsequent `.from_sql` calls until `.set_db` is
615
+ The `.connect` function need only be called once, and the database handle it
616
+ creates will be used for all subsequent `.from_sql` calls until `.connect` is
617
617
  called again.
618
618
 
619
619
  Alternatively, you can build the `Sequel` connection with `Sequel.connect` or
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.2.8
4
+ version: 0.2.9
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: 2018-08-28 00:00:00.000000000 Z
11
+ date: 2019-04-04 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -338,8 +338,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
338
338
  - !ruby/object:Gem::Version
339
339
  version: '0'
340
340
  requirements: []
341
- rubyforge_project:
342
- rubygems_version: 2.7.3
341
+ rubygems_version: 3.0.3
343
342
  signing_key:
344
343
  specification_version: 4
345
344
  summary: Provides tools for working with tables as a data type.