fat_table 0.2.8 → 0.2.9

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