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