fat_table 0.2.6 → 0.2.7

Sign up to get free protection for your applications and to get access to all the features.
@@ -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