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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +2 -0
- data/README.md +2168 -0
- data/README.org +230 -212
- data/TODO.org +7 -0
- data/bin/ft_console +82 -79
- data/fat_table.gemspec +45 -43
- data/lib/fat_table.rb +1 -1
- data/lib/fat_table/column.rb +31 -22
- data/lib/fat_table/db_handle.rb +61 -50
- data/lib/fat_table/evaluator.rb +20 -22
- data/lib/fat_table/formatters/aoa_formatter.rb +1 -2
- data/lib/fat_table/formatters/aoh_formatter.rb +1 -2
- data/lib/fat_table/formatters/formatter.rb +38 -33
- data/lib/fat_table/formatters/latex_formatter.rb +2 -2
- data/lib/fat_table/formatters/org_formatter.rb +5 -6
- data/lib/fat_table/formatters/term_formatter.rb +3 -5
- data/lib/fat_table/formatters/text_formatter.rb +3 -4
- data/lib/fat_table/patches.rb +29 -1
- data/lib/fat_table/table.rb +81 -77
- data/lib/fat_table/version.rb +1 -1
- metadata +80 -82
@@ -25,7 +25,7 @@ module FatTable
|
|
25
25
|
end
|
26
26
|
|
27
27
|
# Taken from the Rainbow gem's list of valid colors.
|
28
|
-
self.valid_colors = %w
|
28
|
+
self.valid_colors = %w[
|
29
29
|
none black blue brown cyan darkgray gray green lightgray lime magenta
|
30
30
|
olive orange pink purple red teal violet white yellow AntiqueWhite1
|
31
31
|
AntiqueWhite2 AntiqueWhite3 AntiqueWhite4 Aquamarine1 Aquamarine2
|
@@ -76,7 +76,7 @@ module FatTable
|
|
76
76
|
Turquoise1 Turquoise2 Turquoise3 Turquoise4 VioletRed1 VioletRed2
|
77
77
|
VioletRed3 VioletRed4 Wheat1 Wheat2 Wheat3 Wheat4 Yellow1 Yellow2 Yellow3
|
78
78
|
Yellow4
|
79
|
-
|
79
|
+
]
|
80
80
|
|
81
81
|
# LaTeX commands to load the needed packages based on the :environement
|
82
82
|
# option. For now, just handles the default 'longtable' :environment. The
|
@@ -4,10 +4,9 @@ module FatTable
|
|
4
4
|
# timestamps and the connector at the beginning of hlines is a '|' rather than
|
5
5
|
# a '+' as for text tables.
|
6
6
|
class OrgFormatter < Formatter
|
7
|
-
|
8
7
|
self.default_format = default_format.dup
|
9
|
-
|
10
|
-
|
8
|
+
default_format[:date_fmt] = '[%F]'
|
9
|
+
default_format[:datetime_fmt] = '[%F %a %H:%M:%S]'
|
11
10
|
|
12
11
|
private
|
13
12
|
|
@@ -20,7 +19,7 @@ module FatTable
|
|
20
19
|
|
21
20
|
def pre_header(widths)
|
22
21
|
result = '|'
|
23
|
-
widths.
|
22
|
+
widths.each_value do |w|
|
24
23
|
result += '-' * (w + 2) + '+'
|
25
24
|
end
|
26
25
|
result[-1] = '|'
|
@@ -53,7 +52,7 @@ module FatTable
|
|
53
52
|
|
54
53
|
def hline(widths)
|
55
54
|
result = '|'
|
56
|
-
widths.
|
55
|
+
widths.each_value do |w|
|
57
56
|
result += '-' * (w + 2) + '+'
|
58
57
|
end
|
59
58
|
result[-1] = '|'
|
@@ -62,7 +61,7 @@ module FatTable
|
|
62
61
|
|
63
62
|
def post_footers(widths)
|
64
63
|
result = '|'
|
65
|
-
widths.
|
64
|
+
widths.each_value do |w|
|
66
65
|
result += '-' * (w + 2) + '+'
|
67
66
|
end
|
68
67
|
result[-1] = '|'
|
@@ -1,5 +1,3 @@
|
|
1
|
-
# -*- coding: utf-8 -*-
|
2
|
-
|
3
1
|
require 'rainbow'
|
4
2
|
|
5
3
|
module FatTable
|
@@ -219,7 +217,7 @@ module FatTable
|
|
219
217
|
|
220
218
|
def pre_header(widths)
|
221
219
|
result = upper_left
|
222
|
-
widths.
|
220
|
+
widths.each_value do |w|
|
223
221
|
result += double_rule * (w + 2) + upper_tee
|
224
222
|
end
|
225
223
|
result[-1] = upper_right
|
@@ -253,7 +251,7 @@ module FatTable
|
|
253
251
|
|
254
252
|
def hline(widths)
|
255
253
|
result = left_tee
|
256
|
-
widths.
|
254
|
+
widths.each_value do |w|
|
257
255
|
result += horizontal_rule * (w + 2) + single_cross
|
258
256
|
end
|
259
257
|
result[-1] = right_tee
|
@@ -287,7 +285,7 @@ module FatTable
|
|
287
285
|
|
288
286
|
def post_footers(widths)
|
289
287
|
result = lower_left
|
290
|
-
widths.
|
288
|
+
widths.each_value do |w|
|
291
289
|
result += double_rule * (w + 2) + lower_tee
|
292
290
|
end
|
293
291
|
result[-1] = lower_right
|
@@ -4,7 +4,6 @@ module FatTable
|
|
4
4
|
# connector at the beginning of hlines is a '+' rather than a '|' as for org
|
5
5
|
# tables.
|
6
6
|
class TextFormatter < Formatter
|
7
|
-
|
8
7
|
private
|
9
8
|
|
10
9
|
# Does this Formatter require a second pass over the cells to align the
|
@@ -16,7 +15,7 @@ module FatTable
|
|
16
15
|
|
17
16
|
def pre_header(widths)
|
18
17
|
result = '+'
|
19
|
-
widths.
|
18
|
+
widths.each_value do |w|
|
20
19
|
result += '=' * (w + 2) + '+'
|
21
20
|
end
|
22
21
|
result[-1] = '+'
|
@@ -49,7 +48,7 @@ module FatTable
|
|
49
48
|
|
50
49
|
def hline(widths)
|
51
50
|
result = '+'
|
52
|
-
widths.
|
51
|
+
widths.each_value do |w|
|
53
52
|
result += '-' * (w + 2) + '+'
|
54
53
|
end
|
55
54
|
result[-1] = '+'
|
@@ -82,7 +81,7 @@ module FatTable
|
|
82
81
|
|
83
82
|
def post_footers(widths)
|
84
83
|
result = '+'
|
85
|
-
widths.
|
84
|
+
widths.each_value do |w|
|
86
85
|
result += '=' * (w + 2) + '+'
|
87
86
|
end
|
88
87
|
result[-1] = '+'
|
data/lib/fat_table/patches.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
unless {a: 1}.respond_to?(:fetch_values)
|
1
|
+
unless { a: 1 }.respond_to?(:fetch_values)
|
2
|
+
# Add fetch_values if this version of ruby does not define it.
|
2
3
|
class Hash
|
3
4
|
def fetch_values(*keys)
|
4
5
|
result = []
|
@@ -14,3 +15,30 @@ unless {a: 1}.respond_to?(:fetch_values)
|
|
14
15
|
end
|
15
16
|
end
|
16
17
|
end
|
18
|
+
|
19
|
+
unless ''.respond_to?(:match?)
|
20
|
+
# Add String#match? to pre-2.4 ruby
|
21
|
+
class String
|
22
|
+
def match?(re)
|
23
|
+
self =~ re
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
unless //.respond_to?(:match?)
|
29
|
+
# Add Regexp#match? to pre-2.4 ruby
|
30
|
+
class Regexp
|
31
|
+
def match?(str)
|
32
|
+
self =~ str
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
unless ''.respond_to?(:strip_heredoc)
|
38
|
+
class String
|
39
|
+
def strip_heredoc
|
40
|
+
indent = chomp.scan(/^\s*/).min.size
|
41
|
+
gsub(/^\s{#{indent}}/, '')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/fat_table/table.rb
CHANGED
@@ -49,9 +49,9 @@ module FatTable
|
|
49
49
|
# spaces converted to underscore and everything down-cased. So, the heading,
|
50
50
|
# 'Two Words' becomes the header +:two_words+.
|
51
51
|
class Table
|
52
|
-
|
53
52
|
# An Array of FatTable::Columns that constitute the table.
|
54
53
|
attr_reader :columns
|
54
|
+
attr_accessor :boundaries
|
55
55
|
|
56
56
|
###########################################################################
|
57
57
|
# Constructors
|
@@ -140,8 +140,8 @@ module FatTable
|
|
140
140
|
|
141
141
|
# :category: Constructors
|
142
142
|
|
143
|
-
# Construct a new table from another FatTable::Table object +table+. Inherit
|
144
|
-
# group boundaries from the input table.
|
143
|
+
# Construct a new table from another FatTable::Table object +table+. Inherit
|
144
|
+
# any group boundaries from the input table.
|
145
145
|
def self.from_table(table)
|
146
146
|
table.deep_dup
|
147
147
|
end
|
@@ -151,7 +151,8 @@ module FatTable
|
|
151
151
|
# Construct a Table by running a SQL +query+ against the database set up
|
152
152
|
# with FatTable.set_db, with the rows of the query result as rows.
|
153
153
|
def self.from_sql(query)
|
154
|
-
|
154
|
+
msg = 'FatTable.db must be set with FatTable.set_db'
|
155
|
+
raise UserError, msg if FatTable.db.nil?
|
155
156
|
result = Table.new
|
156
157
|
FatTable.db[query].each do |h|
|
157
158
|
result << h
|
@@ -166,15 +167,16 @@ module FatTable
|
|
166
167
|
class << self
|
167
168
|
private
|
168
169
|
|
169
|
-
# Construct table from an array of hashes or an array of any object that
|
170
|
-
# respond to #to_h.
|
170
|
+
# Construct table from an array of hashes or an array of any object that
|
171
|
+
# can respond to #to_h. If an array element is a nil, mark it as a group
|
171
172
|
# boundary in the Table.
|
172
173
|
def from_array_of_hashes(hashes, hlines: false)
|
173
174
|
result = new
|
174
175
|
hashes.each do |hsh|
|
175
176
|
if hsh.nil?
|
176
177
|
unless hlines
|
177
|
-
|
178
|
+
msg = 'found an hline in input: try setting hlines true'
|
179
|
+
raise UserError, msg
|
178
180
|
end
|
179
181
|
result.mark_boundary
|
180
182
|
next
|
@@ -219,7 +221,8 @@ module FatTable
|
|
219
221
|
rows[first_data_row..-1].each do |row|
|
220
222
|
if row.nil?
|
221
223
|
unless hlines
|
222
|
-
|
224
|
+
msg = 'found an hline in input: try setting hlines true'
|
225
|
+
raise UserError, msg
|
223
226
|
end
|
224
227
|
result.mark_boundary
|
225
228
|
next
|
@@ -253,15 +256,15 @@ module FatTable
|
|
253
256
|
io.each do |line|
|
254
257
|
unless table_found
|
255
258
|
# Skip through the file until a table is found
|
256
|
-
next unless line
|
257
|
-
unless line
|
259
|
+
next unless line.match?(table_re)
|
260
|
+
unless line.match?(hrule_re)
|
258
261
|
line = line.sub(/\A\s*\|/, '').sub(/\|\s*\z/, '')
|
259
262
|
rows << line.split('|').map(&:clean)
|
260
263
|
end
|
261
264
|
table_found = true
|
262
265
|
next
|
263
266
|
end
|
264
|
-
break unless line
|
267
|
+
break unless line.match?(table_re)
|
265
268
|
if !header_found && line =~ hrule_re
|
266
269
|
rows << nil
|
267
270
|
header_found = true
|
@@ -311,13 +314,16 @@ module FatTable
|
|
311
314
|
def [](key)
|
312
315
|
case key
|
313
316
|
when Integer
|
314
|
-
|
317
|
+
msg = "index '#{key}' out of range"
|
318
|
+
raise UserError, msg unless (0..size - 1).cover?(key.abs)
|
315
319
|
rows[key]
|
316
320
|
when String
|
317
|
-
|
321
|
+
msg = "header '#{key}' not in table"
|
322
|
+
raise UserError, msg unless headers.include?(key)
|
318
323
|
column(key).items
|
319
324
|
when Symbol
|
320
|
-
|
325
|
+
msg = "header ':#{key}' not in table"
|
326
|
+
raise UserError, msg unless headers.include?(key)
|
321
327
|
column(key).items
|
322
328
|
else
|
323
329
|
raise UserError, "cannot index table with a #{key.class}"
|
@@ -413,9 +419,9 @@ module FatTable
|
|
413
419
|
rows
|
414
420
|
end
|
415
421
|
|
416
|
-
|
422
|
+
############################################################################
|
417
423
|
# Enumerable
|
418
|
-
|
424
|
+
############################################################################
|
419
425
|
|
420
426
|
public
|
421
427
|
|
@@ -430,9 +436,6 @@ module FatTable
|
|
430
436
|
end
|
431
437
|
end
|
432
438
|
|
433
|
-
|
434
|
-
public
|
435
|
-
|
436
439
|
# :category: Attributes
|
437
440
|
|
438
441
|
# Boundaries mark the last row in each "group" within the table. The last
|
@@ -505,16 +508,6 @@ module FatTable
|
|
505
508
|
|
506
509
|
# :stopdoc:
|
507
510
|
|
508
|
-
# Reader for boundaries, but not public.
|
509
|
-
def boundaries
|
510
|
-
@boundaries
|
511
|
-
end
|
512
|
-
|
513
|
-
# Writer for boundaries, but not public.
|
514
|
-
def boundaries=(bounds)
|
515
|
-
@boundaries = bounds
|
516
|
-
end
|
517
|
-
|
518
511
|
# Make sure size - 1 is last boundary and that they are unique and sorted.
|
519
512
|
def normalize_boundaries
|
520
513
|
unless empty?
|
@@ -682,9 +675,8 @@ module FatTable
|
|
682
675
|
ivars = ivars.merge(new_cols[:ivars])
|
683
676
|
new_cols.delete(:ivars)
|
684
677
|
end
|
685
|
-
before_hook = '@row += 1'
|
686
678
|
if new_cols.key?(:before_hook)
|
687
|
-
before_hook
|
679
|
+
before_hook = new_cols[:before_hook].to_s
|
688
680
|
new_cols.delete(:before_hook)
|
689
681
|
end
|
690
682
|
after_hook = nil
|
@@ -702,32 +694,35 @@ module FatTable
|
|
702
694
|
# Set the group number in the before hook and run the hook with the
|
703
695
|
# local variables set to the row before the new row is evaluated.
|
704
696
|
grp = row_index_to_group_index(old_k)
|
705
|
-
|
706
|
-
ev.eval_before_hook(
|
697
|
+
ev.update_ivars(row: old_k + 1, group: grp)
|
698
|
+
ev.eval_before_hook(locals: old_row)
|
707
699
|
# Compute the new row.
|
708
700
|
new_row = {}
|
709
701
|
cols.each do |k|
|
710
702
|
h = k.as_sym
|
711
|
-
|
703
|
+
msg = "Column '#{h}' in select does not exist"
|
704
|
+
raise UserError, msg unless column?(h)
|
712
705
|
new_row[h] = old_row[h]
|
713
706
|
end
|
714
|
-
new_cols.each_pair do |key,
|
707
|
+
new_cols.each_pair do |key, expr|
|
715
708
|
key = key.as_sym
|
716
709
|
vars = old_row.merge(new_row)
|
717
|
-
case
|
710
|
+
case expr
|
718
711
|
when Symbol
|
719
|
-
|
720
|
-
|
712
|
+
msg = "Column '#{expr}' in select does not exist"
|
713
|
+
raise UserError, msg unless vars.keys.include?(expr)
|
714
|
+
new_row[key] = vars[expr]
|
721
715
|
when String
|
722
|
-
new_row[key] = ev.evaluate(
|
716
|
+
new_row[key] = ev.evaluate(expr, locals: vars)
|
723
717
|
else
|
724
|
-
|
718
|
+
msg = "Hash parameter '#{key}' to select must be a symbol or string"
|
719
|
+
raise UserError, msg
|
725
720
|
end
|
726
721
|
end
|
727
722
|
# Set the group number and run the hook with the local variables set to
|
728
723
|
# the row after the new row is evaluated.
|
729
|
-
vars = new_row.merge(__group: grp)
|
730
|
-
ev.eval_after_hook(
|
724
|
+
# vars = new_row.merge(__group: grp)
|
725
|
+
ev.eval_after_hook(locals: new_row)
|
731
726
|
result << new_row
|
732
727
|
end
|
733
728
|
result.boundaries = boundaries
|
@@ -753,14 +748,13 @@ module FatTable
|
|
753
748
|
col = Column.new(header: h)
|
754
749
|
result.add_column(col)
|
755
750
|
end
|
756
|
-
ev = Evaluator.new(ivars: { row: 0, group: 0 }
|
757
|
-
before: '@row += 1')
|
751
|
+
ev = Evaluator.new(ivars: { row: 0, group: 0 })
|
758
752
|
rows.each_with_index do |row, k|
|
759
753
|
grp = row_index_to_group_index(k)
|
760
|
-
|
761
|
-
ev.eval_before_hook(
|
762
|
-
result << row if ev.evaluate(expr,
|
763
|
-
ev.eval_after_hook(
|
754
|
+
ev.update_ivars(row: k + 1, group: grp)
|
755
|
+
ev.eval_before_hook(locals: row)
|
756
|
+
result << row if ev.evaluate(expr, locals: row)
|
757
|
+
ev.eval_after_hook(locals: row)
|
764
758
|
end
|
765
759
|
result.normalize_boundaries
|
766
760
|
result
|
@@ -878,10 +872,12 @@ module FatTable
|
|
878
872
|
add_boundaries: true,
|
879
873
|
inherit_boundaries: false)
|
880
874
|
unless columns.size == other.columns.size
|
881
|
-
|
875
|
+
msg = "can't apply set ops to tables with a different number of columns"
|
876
|
+
raise UserError, msg
|
882
877
|
end
|
883
878
|
unless columns.map(&:type) == other.columns.map(&:type)
|
884
|
-
|
879
|
+
msg = "can't apply a set ops to tables with different column types."
|
880
|
+
raise UserError, msg
|
885
881
|
end
|
886
882
|
other_rows = other.rows.map { |r| r.replace_keys(headers) }
|
887
883
|
result = Table.new
|
@@ -902,7 +898,7 @@ module FatTable
|
|
902
898
|
public
|
903
899
|
|
904
900
|
# An Array of symbols for the valid join types.
|
905
|
-
JOIN_TYPES = [
|
901
|
+
JOIN_TYPES = %i[inner left right full cross].freeze
|
906
902
|
|
907
903
|
# :category: Operators
|
908
904
|
#
|
@@ -982,7 +978,8 @@ module FatTable
|
|
982
978
|
# These may be needed for outer joins.
|
983
979
|
self_row_nils = headers.map { |h| [h, nil] }.to_h
|
984
980
|
other_row_nils = other.headers.map { |h| [h, nil] }.to_h
|
985
|
-
|
981
|
+
join_exp, other_common_heads =
|
982
|
+
build_join_expression(exps, other, join_type)
|
986
983
|
ev = Evaluator.new
|
987
984
|
result = Table.new
|
988
985
|
other_rows = other.rows
|
@@ -993,7 +990,7 @@ module FatTable
|
|
993
990
|
# Same as other_row, but with keys that are common with self and equal
|
994
991
|
# in value, removed, so the output table need not repeat them.
|
995
992
|
locals = build_locals_hash(row_a: self_row, row_b: other_row)
|
996
|
-
matches = ev.evaluate(
|
993
|
+
matches = ev.evaluate(join_exp, locals: locals)
|
997
994
|
next unless matches
|
998
995
|
self_row_matched = other_row_matches[k] = true
|
999
996
|
out_row = build_out_row(row_a: self_row, row_b: other_row,
|
@@ -1001,19 +998,18 @@ module FatTable
|
|
1001
998
|
type: join_type)
|
1002
999
|
result << out_row
|
1003
1000
|
end
|
1004
|
-
|
1005
|
-
|
1006
|
-
|
1007
|
-
|
1008
|
-
|
1009
|
-
end
|
1001
|
+
next unless %i[left full].include?(join_type)
|
1002
|
+
next if self_row_matched
|
1003
|
+
result << build_out_row(row_a: self_row,
|
1004
|
+
row_b: other_row_nils,
|
1005
|
+
type: join_type)
|
1010
1006
|
end
|
1011
|
-
if
|
1007
|
+
if %i[right full].include?(join_type)
|
1012
1008
|
other_rows.each_with_index do |other_row, k|
|
1013
|
-
|
1014
|
-
|
1015
|
-
|
1016
|
-
|
1009
|
+
next if other_row_matches[k]
|
1010
|
+
result << build_out_row(row_a: self_row_nils,
|
1011
|
+
row_b: other_row,
|
1012
|
+
type: join_type)
|
1017
1013
|
end
|
1018
1014
|
end
|
1019
1015
|
result.normalize_boundaries
|
@@ -1100,8 +1096,8 @@ module FatTable
|
|
1100
1096
|
b_common_heads = []
|
1101
1097
|
if exps.empty?
|
1102
1098
|
if common_heads.empty?
|
1103
|
-
|
1104
|
-
|
1099
|
+
msg = "#{type}-join with no common column names needs join expression"
|
1100
|
+
raise UserError, msg
|
1105
1101
|
else
|
1106
1102
|
# A Natural join on all common heads
|
1107
1103
|
common_heads.each do |h|
|
@@ -1126,7 +1122,9 @@ module FatTable
|
|
1126
1122
|
end
|
1127
1123
|
if partial_result
|
1128
1124
|
# Second of a pair
|
1129
|
-
ensure_common_types!(self_h: a_head,
|
1125
|
+
ensure_common_types!(self_h: a_head,
|
1126
|
+
other_h: last_sym,
|
1127
|
+
other: other)
|
1130
1128
|
partial_result << "#{a_head}_a)"
|
1131
1129
|
and_conds << partial_result
|
1132
1130
|
partial_result = nil
|
@@ -1142,7 +1140,9 @@ module FatTable
|
|
1142
1140
|
end
|
1143
1141
|
if partial_result
|
1144
1142
|
# Second of a pair
|
1145
|
-
ensure_common_types!(self_h: last_sym,
|
1143
|
+
ensure_common_types!(self_h: last_sym,
|
1144
|
+
other_h: b_head,
|
1145
|
+
other: other)
|
1146
1146
|
partial_result << "#{b_head}_b)"
|
1147
1147
|
and_conds << partial_result
|
1148
1148
|
partial_result = nil
|
@@ -1158,12 +1158,13 @@ module FatTable
|
|
1158
1158
|
# We were expecting the second of a modified pair, but got an
|
1159
1159
|
# unmodified symbol instead.
|
1160
1160
|
msg =
|
1161
|
-
"
|
1161
|
+
"follow '#{last_sym}' by qualified exp from the other table"
|
1162
1162
|
raise UserError, msg
|
1163
1163
|
end
|
1164
1164
|
# We have an unqualified symbol that must appear in both tables
|
1165
1165
|
unless common_heads.include?(exp)
|
1166
|
-
|
1166
|
+
msg = "unqualified column '#{exp}' must occur in both tables"
|
1167
|
+
raise UserError, msg
|
1167
1168
|
end
|
1168
1169
|
ensure_common_types!(self_h: exp, other_h: exp, other: other)
|
1169
1170
|
and_conds << "(#{exp}_a == #{exp}_b)"
|
@@ -1174,7 +1175,8 @@ module FatTable
|
|
1174
1175
|
# qualified.
|
1175
1176
|
and_conds << "(#{exp})"
|
1176
1177
|
else
|
1177
|
-
|
1178
|
+
msg = "invalid join expression '#{exp}' of class #{exp.class}"
|
1179
|
+
raise UserError, msg
|
1178
1180
|
end
|
1179
1181
|
end
|
1180
1182
|
[and_conds.join(' && '), b_common_heads]
|
@@ -1185,15 +1187,15 @@ module FatTable
|
|
1185
1187
|
# have the same types.
|
1186
1188
|
def ensure_common_types!(self_h:, other_h:, other:)
|
1187
1189
|
unless column(self_h).type == other.column(other_h).type
|
1188
|
-
|
1189
|
-
|
1190
|
+
msg = "column '#{self_h}' type does not match column '#{other_h}"
|
1191
|
+
raise UserError, msg
|
1190
1192
|
end
|
1191
1193
|
self
|
1192
1194
|
end
|
1193
1195
|
|
1194
|
-
|
1196
|
+
############################################################################
|
1195
1197
|
# Group By
|
1196
|
-
|
1198
|
+
############################################################################
|
1197
1199
|
|
1198
1200
|
public
|
1199
1201
|
|
@@ -1277,7 +1279,8 @@ module FatTable
|
|
1277
1279
|
|
1278
1280
|
# Add a FatTable::Column object +col+ to the table.
|
1279
1281
|
def add_column(col)
|
1280
|
-
|
1282
|
+
msg = "Table already has a column with header '#{col.header}'"
|
1283
|
+
raise msg if column?(col.header)
|
1281
1284
|
columns << col
|
1282
1285
|
self
|
1283
1286
|
end
|
@@ -1324,7 +1327,8 @@ module FatTable
|
|
1324
1327
|
#
|
1325
1328
|
def to_any(fmt_type, options = {})
|
1326
1329
|
fmt = fmt_type.as_sym
|
1327
|
-
|
1330
|
+
msg = "unknown format '#{fmt}'"
|
1331
|
+
raise UserError, msg unless FatTable::FORMATS.include?(fmt)
|
1328
1332
|
method = "to_#{fmt}"
|
1329
1333
|
if block_given?
|
1330
1334
|
send method, options, &Proc.new
|