fat_table 0.2.6 → 0.2.7

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.
@@ -1,5 +1,6 @@
1
+ # Set and access a database by module-level methods.
1
2
  module FatTable
2
- class << self;
3
+ class << self
3
4
  # The +Sequel+ database handle to use in calls to +FatTable.from_sql+.
4
5
  attr_accessor :handle
5
6
  end
@@ -18,20 +19,21 @@ module FatTable
18
19
  # http://sequel.jeremyevans.net/rdoc/files/doc/opening_databases_rdoc.html
19
20
  #
20
21
  # +driver+::
21
- # One of 'pg' (for Postgresql), 'mysql' or 'mysql2' (for Mysql), or 'sqlite' (for
22
- # SQLite3) to specify the +Sequel+ driver to use. You may have to install the
23
- # driver to make this work. By default use 'Pg'.
22
+ # One of 'pg' (for Postgresql), 'mysql' or 'mysql2' (for Mysql), or
23
+ # 'sqlite' (for SQLite3) to specify the +Sequel+ driver to use. You may
24
+ # have to install the driver to make this work. By default use 'Pg'.
24
25
  #
25
26
  # +database+::
26
27
  # The name of the database to access. There is no default for this.
27
28
  #
28
29
  # +user+::
29
- # The user name to use for accessing the database. It defaults to nil,
30
- # which may be interpreted as a default user by the Sequel driver being used.
30
+ # The user name to use for accessing the database. It defaults to nil,
31
+ # which may be interpreted as a default user by the Sequel driver being
32
+ # used.
31
33
  #
32
34
  # +password+::
33
- # The password to use for accessing the database. It defaults to nil,
34
- # which may be interpreted as a default password by the Sequel driver being used.
35
+ # The password to use for accessing the database. It defaults to nil, which
36
+ # may be interpreted as a default password by the Sequel driver being used.
35
37
  #
36
38
  # +host+::
37
39
  # The name of the host on which to look for the database connection,
@@ -39,57 +41,66 @@ module FatTable
39
41
  #
40
42
  # +port+::
41
43
  # The port number as a string or integer on which to access the database on
42
- # the given host. Defaults to '5432'. Only used if host is not 'localhost'.
44
+ # the given host. Defaults to '5432'. Only used if host is not 'localhost'.
43
45
  #
44
46
  # +socket+::
45
47
  # The socket to use to access the database if the host is 'localhost'.
46
48
  # Defaults to the standard socket for the Pg driver, '/tmp/.s.PGSQL.5432'.
47
49
  #
48
- # If successful the database handle for Sequel is return.
49
- # Once called successfully, this establishes the database handle to use for
50
- # all subsequent calls to FatTable.from_sql or FatTable::Table.from_sql. You
51
- # can then access the handle if needed with FatTable.db.
52
- def self.set_db(db: nil,
53
- driver: 'postgres',
54
- database:,
55
- user: ENV['LOGNAME'],
56
- password: nil,
57
- host: 'localhost',
58
- port: '5432',
59
- socket: '/tmp/.s.PGSQL.5432')
60
- if db
61
- self.handle = db
62
- else
63
- raise UserError, 'must supply database name to set_db' unless database
64
-
65
- valid_drivers = ['postgres', 'mysql', 'mysql2', 'sqlite']
66
- unless valid_drivers.include?(driver)
67
- raise UserError, "'#{driver}' driver must be one of #{valid_drivers.join(' or ')}"
68
- end
69
- if database.blank?
70
- raise UserError, "must supply database parameter to set_db"
71
- end
72
-
73
- if driver == 'sqlite'
74
- dsn = "sqlite://#{database}"
75
- else
76
- pw_part = password ? ":#{password}" : ''
77
- hst_part = host ? "@#{host}" : ''
78
- prt_part = port ? ":#{port}" : ''
79
- dsn = "#{driver}:://#{user}#{pw_part}#{hst_part}#{prt_part}/#{database}"
80
- end
81
-
82
- # Set the dsn for Sequel
83
- begin
84
- # DB = Sequel.connect(dsn)
85
- self.handle = Sequel.connect(dsn)
86
- rescue => ex
87
- raise TransientError, "#{dsn}: #{ex}"
88
- end
50
+ # If successful the database handle for Sequel is return. Once called
51
+ # successfully, this establishes the database handle to use for all subsequent
52
+ # calls to FatTable.from_sql or FatTable::Table.from_sql. You can then access
53
+ # the handle if needed with FatTable.db.
54
+ def self.set_db(args)
55
+ # Set the dsn for Sequel
56
+ begin
57
+ self.handle = Sequel.connect(args)
58
+ rescue Sequel::Error => ex
59
+ raise TransientError, "#{args}: #{ex}"
89
60
  end
90
61
  handle
91
62
  end
92
63
 
64
+ # def self.set_db(adapter: 'postgres',
65
+ # database:,
66
+ # user: ENV['LOGNAME'],
67
+ # password: nil,
68
+ # host: 'localhost',
69
+ # port: nil,
70
+ # socket: '/tmp/.s.PGSQL.5432')
71
+ # if db
72
+ # self.handle = db
73
+ # else
74
+ # raise UserError, 'must supply database name to set_db' unless database
75
+
76
+ # valid_drivers = %w[postgres mysql mysql2 sqlite]
77
+ # unless valid_drivers.include?(driver)
78
+ # msg = "'#{driver}' driver must be one of #{valid_drivers.join(' or ')}"
79
+ # raise UserError, msg
80
+ # end
81
+ # if database.blank?
82
+ # raise UserError, 'must supply database parameter to set_db'
83
+ # end
84
+
85
+ # if driver == 'sqlite'
86
+ # dsn = "sqlite://#{database}"
87
+ # else
88
+ # pw_part = password ? ":#{password}" : ''
89
+ # hst_part = host ? "@#{host}" : ''
90
+ # prt_part = port ? ":#{port}" : ''
91
+ # dsn = "#{driver}:://#{user}#{pw_part}#{hst_part}#{prt_part}/#{database}"
92
+ # end
93
+
94
+ # # Set the dsn for Sequel
95
+ # begin
96
+ # self.handle = Sequel.connect(dsn)
97
+ # rescue Sequel::Error => ex
98
+ # raise TransientError, "#{dsn}: #{ex}"
99
+ # end
100
+ # end
101
+ # handle
102
+ # end
103
+
93
104
  # Return the +Sequel+ database handle.
94
105
  def self.db
95
106
  handle
@@ -12,10 +12,10 @@ module FatTable
12
12
  # update values of instance variables for use in subsequent calls to
13
13
  # #evaluate.
14
14
  class Evaluator
15
- # Return a new Evaluator object in which the Hash +vars+ defines the
15
+ # Return a new Evaluator object in which the Hash +ivars+ defines the
16
16
  # bindings for instance variables to be available and maintained across all
17
17
  # subsequent calls to Evaluator.evaluate. The strings +before+ and +after+
18
- # are string expressions that will be evaluated before and after each
18
+ # are string Ruby expressions that will be evaluated before and after each
19
19
  # subsequent call to Evaluator.evaluate.
20
20
  def initialize(ivars: {}, before: nil, after: nil)
21
21
  @before = before
@@ -23,31 +23,28 @@ module FatTable
23
23
  set_instance_vars(ivars)
24
24
  end
25
25
 
26
- # Run the before hook after setting the @group to grp, passed in as a
27
- # parameter. This is run before any column has been evaluated with the
28
- # evaluate method.
29
- def eval_before_hook(vars)
30
- bdg = binding
31
- set_local_vars(vars, bdg)
32
- @group = vars[:__group]
33
- eval(@before, bdg) if @before
26
+ # Set the @group instance variable to the given value.
27
+ def update_ivars(ivars)
28
+ set_instance_vars(ivars)
29
+ end
30
+
31
+ # Run any before hook in the context of the given local variables.
32
+ def eval_before_hook(locals: {})
33
+ return if @before.blank?
34
+ evaluate(@before, locals: locals)
34
35
  end
35
36
 
36
- # Run the after hook. This is run after each column in the row has been
37
- # evaluated with the evaluate method.
38
- def eval_after_hook(vars)
39
- bdg = binding
40
- set_local_vars(vars, bdg)
41
- eval(@after, bdg) if @after
37
+ # Run any after hook in the context of the given local variables.
38
+ def eval_after_hook(locals: {})
39
+ return if @after.blank?
40
+ evaluate(@after, locals: locals)
42
41
  end
43
42
 
44
43
  # Return the result of evaluating +expr+ as a Ruby expression in which the
45
44
  # instance variables set in Evaluator.new and any local variables set in the
46
- # Hash parameter +vars+ are available to the expression.
47
- def evaluate(expr = '', vars: {})
48
- bdg = binding
49
- set_local_vars(vars, bdg)
50
- eval(expr, bdg)
45
+ # Hash parameter +locals+ are available to the expression.
46
+ def evaluate(expr = '', locals: {})
47
+ eval(expr, set_local_vars(binding, locals))
51
48
  end
52
49
 
53
50
  private
@@ -59,10 +56,11 @@ module FatTable
59
56
  end
60
57
  end
61
58
 
62
- def set_local_vars(vars = {}, bnd)
59
+ def set_local_vars(bnd, vars = {})
63
60
  vars.each_pair do |name, val|
64
61
  bnd.local_variable_set(name, val)
65
62
  end
63
+ bnd
66
64
  end
67
65
  end
68
66
  end
@@ -4,7 +4,6 @@ module FatTable
4
4
  # directives. All footers are included as extra Arrays of the output.
5
5
  # AoaFormatter supports no +options+
6
6
  class AoaFormatter < Formatter
7
-
8
7
  private
9
8
 
10
9
  def evaluate?
@@ -39,7 +38,7 @@ module FatTable
39
38
  # eval'ed, we need to escape any single-quotes (') that appear in the
40
39
  # string.
41
40
  def quote_cell(v)
42
- if v =~ /'/
41
+ if v.match?(/'/)
43
42
  # Use a negative look-behind to only quote single-quotes that are not
44
43
  # already preceded by a backslash
45
44
  v.gsub(/(?<!\\)'/, "'" => "\\'")
@@ -6,7 +6,6 @@ module FatTable
6
6
  # footers are included as extra Hashes of the output. AoaFormatter supports no
7
7
  # +options+
8
8
  class AohFormatter < Formatter
9
-
10
9
  private
11
10
 
12
11
  def evaluate?
@@ -39,7 +38,7 @@ module FatTable
39
38
  # eval'ed, we need to escape any single-quotes (') that appear in the
40
39
  # string.
41
40
  def quote_cell(v)
42
- if v =~ /'/
41
+ if v.match?(/'/)
43
42
  # Use a negative look-behind to only quote single-quotes that are not
44
43
  # already preceded by a backslash
45
44
  v.gsub(/(?<!\\)'/, "'" => "\\'")
@@ -12,7 +12,7 @@ module FatTable
12
12
  # provided by subclasses will override these for different output targets.
13
13
  class Formatter
14
14
  # Valid locations in a Table as an array of symbols.
15
- LOCATIONS = [:header, :body, :bfirst, :gfirst, :gfooter, :footer].freeze
15
+ LOCATIONS = %i[header body bfirst gfirst gfooter footer].freeze
16
16
 
17
17
  # The table that is the subject of the Formatter.
18
18
  attr_reader :table
@@ -45,8 +45,9 @@ module FatTable
45
45
  # footer content. The value is Hash in which the keys are column symbols and
46
46
  # the values are symbols for the aggregate method to be applied to the
47
47
  # group's column to provide a value in the group footer for that column.
48
- # Thus, +gfooters['Average'][:shares]+ might be set to +:avg+ to indicate that
49
- # the +:shares+ column is to be averaged in the group footer labeled 'Average'.
48
+ # Thus, +gfooters['Average'][:shares]+ might be set to +:avg+ to indicate
49
+ # that the +:shares+ column is to be averaged in the group footer labeled
50
+ # 'Average'.
50
51
  attr_reader :gfooters
51
52
 
52
53
  class_attribute :default_format
@@ -98,13 +99,13 @@ module FatTable
98
99
  @options = options
99
100
  @footers = {}
100
101
  @gfooters = {}
101
- # Formatting instructions for various "locations" within the Table, as
102
- # a hash of hashes. The outer hash is keyed on the location, and each
103
- # inner hash is keyed on either a column sym or a type sym, :string, :numeric,
104
- # :datetime, :boolean, or :nil. The value of the inner hashes are
102
+ # Formatting instructions for various "locations" within the Table, as a
103
+ # hash of hashes. The outer hash is keyed on the location, and each inner
104
+ # hash is keyed on either a column sym or a type sym, :string, :numeric,
105
+ # :datetime, :boolean, or :nil. The value of the inner hashes are
105
106
  # OpenStruct structs.
106
107
  @format_at = {}
107
- [:header, :bfirst, :gfirst, :body, :footer, :gfooter].each do |loc|
108
+ %i[header bfirst gfirst body footer gfooter].each do |loc|
108
109
  @format_at[loc] = {}
109
110
  table.headers.each do |h|
110
111
  fmt_hash = self.class.default_format
@@ -205,13 +206,13 @@ module FatTable
205
206
  foot = {}
206
207
  sum_cols.each do |h|
207
208
  unless table.headers.include?(h)
208
- raise UserError, "No '#{h}' column in table to sum in the group footer"
209
+ raise UserError, "No '#{h}' column in table for group sum footer"
209
210
  end
210
211
  foot[h] = :sum
211
212
  end
212
213
  agg_cols.each do |h, agg|
213
214
  unless table.headers.include?(h)
214
- raise UserError, "No '#{h}' column in table to #{agg} in the group footer"
215
+ raise UserError, "No '#{h}' column in table for #{agg} group footer"
215
216
  end
216
217
  foot[h] = agg
217
218
  end
@@ -411,7 +412,7 @@ module FatTable
411
412
  #
412
413
  # \n\[niltext\]:: render a nil item with the given text.
413
414
  def format(**fmts)
414
- [:header, :bfirst, :gfirst, :body, :footer, :gfooter].each do |loc|
415
+ %i[header bfirst gfirst body footer gfooter].each do |loc|
415
416
  format_for(loc, fmts)
416
417
  end
417
418
  self
@@ -465,7 +466,7 @@ module FatTable
465
466
  unless LOCATIONS.include?(location)
466
467
  raise UserError, "unknown format location '#{location}'"
467
468
  end
468
- valid_keys = table.headers + [:string, :numeric, :datetime, :boolean, :nil]
469
+ valid_keys = table.headers + %i[string numeric datetime boolean nil]
469
470
  invalid_keys = (fmts.keys - valid_keys).uniq
470
471
  unless invalid_keys.empty?
471
472
  msg = "invalid #{location} column or type: #{invalid_keys.join(',')}"
@@ -504,14 +505,15 @@ module FatTable
504
505
  end
505
506
  if fmts[h]
506
507
  # Merge in column formatting
507
- col_fmt = send(parse_typ_method_name, fmts[h], strict: location != :header)
508
+ col_fmt = send(parse_typ_method_name, fmts[h],
509
+ strict: location != :header)
508
510
  format_h = format_h.merge(col_fmt)
509
511
  end
510
512
 
511
513
  if location == :body
512
514
  # Copy :body formatting for column h to :bfirst and :gfirst if they
513
- # still have the default formatting. Can be overridden with a format_for
514
- # call with those locations.
515
+ # still have the default formatting. Can be overridden with a
516
+ # format_for call with those locations.
515
517
  format_h.each_pair do |k, v|
516
518
  if format_at[:bfirst][h].send(k) == default_format[k]
517
519
  format_at[:bfirst][h].send("#{k}=", v)
@@ -538,9 +540,9 @@ module FatTable
538
540
  self
539
541
  end
540
542
 
541
- ###############################################################################
543
+ ############################################################################
542
544
  # Parsing and validation routines
543
- ###############################################################################
545
+ ############################################################################
544
546
 
545
547
  private
546
548
 
@@ -591,11 +593,11 @@ module FatTable
591
593
  fmt = fmt.sub($&, '')
592
594
  end
593
595
  if fmt =~ /(~\s*)?B/
594
- fmt_hash[:bold] = !!!$1
596
+ fmt_hash[:bold] = !$1
595
597
  fmt = fmt.sub($&, '')
596
598
  end
597
599
  if fmt =~ /(~\s*)?I/
598
- fmt_hash[:italic] = !!!$1
600
+ fmt_hash[:italic] = !$1
599
601
  fmt = fmt.sub($&, '')
600
602
  end
601
603
  if fmt =~ /R/
@@ -611,11 +613,11 @@ module FatTable
611
613
  fmt = fmt.sub($&, '')
612
614
  end
613
615
  if fmt =~ /(~\s*)?_/
614
- fmt_hash[:underline] = !!!$1
616
+ fmt_hash[:underline] = !$1
615
617
  fmt = fmt.sub($&, '')
616
618
  end
617
619
  if fmt =~ /(~\s*)?\*/
618
- fmt_hash[:blink] = !!!$1
620
+ fmt_hash[:blink] = !$1
619
621
  fmt = fmt.sub($&, '')
620
622
  end
621
623
  [fmt_hash, fmt]
@@ -652,15 +654,15 @@ module FatTable
652
654
  fmt = fmt.sub($&, '')
653
655
  end
654
656
  if fmt =~ /(~\s*)?,/
655
- fmt_hash[:commas] = !!!$1
657
+ fmt_hash[:commas] = !$1
656
658
  fmt = fmt.sub($&, '')
657
659
  end
658
660
  if fmt =~ /(~\s*)?\$/
659
- fmt_hash[:currency] = !!!$1
661
+ fmt_hash[:currency] = !$1
660
662
  fmt = fmt.sub($&, '')
661
663
  end
662
664
  if fmt =~ /(~\s*)?H/
663
- fmt_hash[:hms] = !!!$1
665
+ fmt_hash[:hms] = !$1
664
666
  fmt = fmt.sub($&, '')
665
667
  end
666
668
  unless fmt.blank? || !strict
@@ -687,7 +689,8 @@ module FatTable
687
689
  fmt = fmt.sub($&, '')
688
690
  end
689
691
  unless fmt.blank? || !strict
690
- raise UserError, "unrecognized datetime formatting instructions '#{fmt}'"
692
+ msg = "unrecognized datetime formatting instructions '#{fmt}'"
693
+ raise UserError, msg
691
694
  end
692
695
  fmt_hash
693
696
  end
@@ -708,7 +711,8 @@ module FatTable
708
711
  end
709
712
  # Since true_text, false_text and nil_text may want to have internal
710
713
  # spaces, defer removing extraneous spaces until after they are parsed.
711
- if fmt =~ /c\[(#{CLR_RE})(\.(#{CLR_RE}))?,\s*(#{CLR_RE})(\.(#{CLR_RE}))?\]/
714
+ if fmt =~ /c\[(#{CLR_RE})(\.(#{CLR_RE}))?,
715
+ \s*(#{CLR_RE})(\.(#{CLR_RE}))?\]/x
712
716
  fmt_hash[:true_color] = $1 unless $1.blank?
713
717
  fmt_hash[:true_bgcolor] = $3 unless $3.blank?
714
718
  fmt_hash[:false_color] = $4 unless $4.blank?
@@ -738,9 +742,9 @@ module FatTable
738
742
  fmt_hash
739
743
  end
740
744
 
741
- ###############################################################################
745
+ ############################################################################
742
746
  # Applying formatting
743
- ###############################################################################
747
+ ############################################################################
744
748
 
745
749
  public
746
750
 
@@ -836,7 +840,7 @@ module FatTable
836
840
  result = val.secs_to_hms
837
841
  istruct.commas = false
838
842
  elsif istruct.currency
839
- prec = istruct.post_digits == 0 ? 2 : istruct.post_digits
843
+ prec = istruct.post_digits.zero? ? 2 : istruct.post_digits
840
844
  delim = istruct.commas ? ',' : ''
841
845
  result = val.to_s(:currency, precision: prec, delimiter: delim,
842
846
  unit: FatTable.currency_symbol)
@@ -903,9 +907,9 @@ module FatTable
903
907
  val
904
908
  end
905
909
 
906
- ###############################################################################
910
+ ############################################################################
907
911
  # Output routines
908
- ###############################################################################
912
+ ############################################################################
909
913
 
910
914
  public
911
915
 
@@ -1016,7 +1020,7 @@ module FatTable
1016
1020
  # Return a hash mapping the table's headers to their formatted versions. If
1017
1021
  # a hash of column widths is given, perform alignment within the given field
1018
1022
  # widths.
1019
- def build_formatted_headers(widths = {})
1023
+ def build_formatted_headers(_widths = {})
1020
1024
  # Don't decorate if this Formatter calls for alignment. It will be done
1021
1025
  # in the second pass.
1022
1026
  decorate = !aligned?
@@ -1058,7 +1062,8 @@ module FatTable
1058
1062
  grp_col[h] ||= Column.new(header: h)
1059
1063
  grp_col[h] << row[h]
1060
1064
  istruct = format_at[location][h]
1061
- new_row[h] = [row[h], format_cell(row[h], istruct, decorate: decorate)]
1065
+ new_row[h] = [row[h], format_cell(row[h], istruct,
1066
+ decorate: decorate)]
1062
1067
  end
1063
1068
  new_rows << [location, new_row]
1064
1069
  tbl_row_k += 1