fat_table 0.2.7 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +2 -0
- data/.rubocop.yml +18 -0
- data/.travis.yml +7 -4
- data/.yardopts +5 -1
- data/Gemfile +2 -0
- data/README.org +82 -76
- data/README.rdoc +4 -4
- data/fat_table.gemspec +8 -8
- data/lib/fat_table.rb +14 -3
- data/lib/fat_table/column.rb +39 -27
- data/lib/fat_table/db_handle.rb +19 -47
- data/lib/fat_table/errors.rb +2 -0
- data/lib/fat_table/evaluator.rb +11 -5
- data/lib/fat_table/formatters.rb +2 -0
- data/lib/fat_table/formatters/aoa_formatter.rb +7 -5
- data/lib/fat_table/formatters/aoh_formatter.rb +8 -6
- data/lib/fat_table/formatters/formatter.rb +78 -61
- data/lib/fat_table/formatters/latex_formatter.rb +7 -5
- data/lib/fat_table/formatters/org_formatter.rb +5 -3
- data/lib/fat_table/formatters/term_formatter.rb +33 -28
- data/lib/fat_table/formatters/text_formatter.rb +5 -3
- data/lib/fat_table/patches.rb +5 -2
- data/lib/fat_table/table.rb +78 -57
- data/lib/fat_table/version.rb +3 -1
- data/{README.md → md/README.md} +5 -6
- metadata +49 -39
@@ -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 &&
|
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(
|
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(
|
183
|
-
|
184
|
+
def quote_cell(val)
|
185
|
+
val
|
184
186
|
end
|
185
187
|
|
186
188
|
def post_cell
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FatTable
|
2
4
|
# Output the table in the same way as org-mode for emacs does. This is almost
|
3
5
|
# identical to TextFormatter except that dates do get formatted as inactive
|
@@ -30,12 +32,12 @@ module FatTable
|
|
30
32
|
'|'
|
31
33
|
end
|
32
34
|
|
33
|
-
def pre_cell(
|
35
|
+
def pre_cell(_head)
|
34
36
|
''
|
35
37
|
end
|
36
38
|
|
37
|
-
def quote_cell(
|
38
|
-
|
39
|
+
def quote_cell(val)
|
40
|
+
val
|
39
41
|
end
|
40
42
|
|
41
43
|
def post_cell
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
require 'rainbow'
|
2
4
|
|
3
5
|
module FatTable
|
@@ -26,9 +28,10 @@ module FatTable
|
|
26
28
|
super
|
27
29
|
@options[:unicode] = options.fetch(:unicode, true)
|
28
30
|
@options[:framecolor] = options.fetch(:framecolor, 'none.none')
|
29
|
-
return unless @options[:framecolor] =~ /([-_a-zA-Z]*)(\.([-_a-zA-Z]*))/
|
30
|
-
|
31
|
-
@options[:
|
31
|
+
return unless @options[:framecolor] =~ /(?<co>[-_a-zA-Z]*)(\.(?<bg>[-_a-zA-Z]*))/
|
32
|
+
|
33
|
+
@options[:frame_fg] = Regexp.last_match[:co].downcase unless Regexp.last_match[:co].blank?
|
34
|
+
@options[:frame_bg] = Regexp.last_match[:bg].downcase unless Regexp.last_match[:bg].blank?
|
32
35
|
end
|
33
36
|
|
34
37
|
# Valid colors for ANSI terminal using the rainbow gem's X11ColorNames.
|
@@ -59,6 +62,7 @@ module FatTable
|
|
59
62
|
|
60
63
|
def strip_ansi(str)
|
61
64
|
return '' unless str
|
65
|
+
|
62
66
|
str.gsub(/\e\[[0-9;]+m/, '')
|
63
67
|
end
|
64
68
|
|
@@ -73,18 +77,19 @@ module FatTable
|
|
73
77
|
result
|
74
78
|
end
|
75
79
|
|
76
|
-
def colorize(str,
|
77
|
-
|
78
|
-
|
79
|
-
return str unless
|
80
|
+
def colorize(str, fg_color, bg_color)
|
81
|
+
fg_color = nil if fg_color == 'none'
|
82
|
+
bg_color = nil if bg_color == 'none'
|
83
|
+
return str unless fg_color || bg_color
|
84
|
+
|
80
85
|
result = Rainbow(str)
|
81
|
-
if
|
82
|
-
|
83
|
-
result = result.color(
|
86
|
+
if fg_color
|
87
|
+
fg_color = fg_color.tr(' ', '').downcase.as_sym
|
88
|
+
result = result.color(fg_color) if fg_color
|
84
89
|
end
|
85
|
-
if
|
86
|
-
|
87
|
-
result = result.bg(
|
90
|
+
if bg_color
|
91
|
+
bg_color = bg_color.tr(' ', '').downcase.as_sym
|
92
|
+
result = result.bg(bg_color) if bg_color
|
88
93
|
end
|
89
94
|
result
|
90
95
|
end
|
@@ -98,18 +103,18 @@ module FatTable
|
|
98
103
|
# Unicode line-drawing characters. We use double lines before and after the
|
99
104
|
# table and single lines for the sides and hlines between groups and
|
100
105
|
# footers.
|
101
|
-
UPPER_LEFT = "\u2552"
|
102
|
-
UPPER_RIGHT = "\u2555"
|
103
|
-
DOUBLE_RULE = "\u2550"
|
104
|
-
UPPER_TEE = "\u2564"
|
105
|
-
VERTICAL_RULE = "\u2502"
|
106
|
-
LEFT_TEE = "\u251C"
|
107
|
-
HORIZONTAL_RULE = "\u2500"
|
108
|
-
SINGLE_CROSS = "\u253C"
|
109
|
-
RIGHT_TEE = "\u2524"
|
110
|
-
LOWER_LEFT = "\u2558"
|
111
|
-
LOWER_RIGHT = "\u255B"
|
112
|
-
LOWER_TEE = "\u2567"
|
106
|
+
UPPER_LEFT = "\u2552"
|
107
|
+
UPPER_RIGHT = "\u2555"
|
108
|
+
DOUBLE_RULE = "\u2550"
|
109
|
+
UPPER_TEE = "\u2564"
|
110
|
+
VERTICAL_RULE = "\u2502"
|
111
|
+
LEFT_TEE = "\u251C"
|
112
|
+
HORIZONTAL_RULE = "\u2500"
|
113
|
+
SINGLE_CROSS = "\u253C"
|
114
|
+
RIGHT_TEE = "\u2524"
|
115
|
+
LOWER_LEFT = "\u2558"
|
116
|
+
LOWER_RIGHT = "\u255B"
|
117
|
+
LOWER_TEE = "\u2567"
|
113
118
|
# :startdoc:
|
114
119
|
|
115
120
|
def upper_left
|
@@ -229,12 +234,12 @@ module FatTable
|
|
229
234
|
frame_colorize(vertical_rule)
|
230
235
|
end
|
231
236
|
|
232
|
-
def pre_cell(
|
237
|
+
def pre_cell(_head)
|
233
238
|
''
|
234
239
|
end
|
235
240
|
|
236
|
-
def quote_cell(
|
237
|
-
|
241
|
+
def quote_cell(val)
|
242
|
+
val
|
238
243
|
end
|
239
244
|
|
240
245
|
def post_cell
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FatTable
|
2
4
|
# Output the table as plain text. This is almost identical to OrgFormatter
|
3
5
|
# except that dates do not get formatted as inactive timestamps and the
|
@@ -26,12 +28,12 @@ module FatTable
|
|
26
28
|
'|'
|
27
29
|
end
|
28
30
|
|
29
|
-
def pre_cell(
|
31
|
+
def pre_cell(_head)
|
30
32
|
''
|
31
33
|
end
|
32
34
|
|
33
|
-
def quote_cell(
|
34
|
-
|
35
|
+
def quote_cell(val)
|
36
|
+
val
|
35
37
|
end
|
36
38
|
|
37
39
|
def post_cell
|
data/lib/fat_table/patches.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
unless { a: 1 }.respond_to?(:fetch_values)
|
2
4
|
# Add fetch_values if this version of ruby does not define it.
|
3
5
|
class Hash
|
@@ -19,8 +21,8 @@ end
|
|
19
21
|
unless ''.respond_to?(:match?)
|
20
22
|
# Add String#match? to pre-2.4 ruby
|
21
23
|
class String
|
22
|
-
def match?(
|
23
|
-
self =~
|
24
|
+
def match?(regexp)
|
25
|
+
self =~ regexp
|
24
26
|
end
|
25
27
|
end
|
26
28
|
end
|
@@ -35,6 +37,7 @@ unless //.respond_to?(:match?)
|
|
35
37
|
end
|
36
38
|
|
37
39
|
unless ''.respond_to?(:strip_heredoc)
|
40
|
+
# Patch String to provide heredocs with whitespace stripped
|
38
41
|
class String
|
39
42
|
def strip_heredoc
|
40
43
|
indent = chomp.scan(/^\s*/).min.size
|
data/lib/fat_table/table.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
1
3
|
module FatTable
|
2
4
|
# A container for a two-dimensional table. All cells in the table must be a
|
3
5
|
# String, a DateTime (or Date), a Numeric (Bignum, Integer, or BigDecimal), or
|
@@ -106,18 +108,19 @@ module FatTable
|
|
106
108
|
# :category: Constructors
|
107
109
|
|
108
110
|
# 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
|
110
|
-
# the first row as headers. With +hlines+ set true, expect +nil+
|
111
|
-
# to mark the header row and any boundaries. If the second
|
112
|
-
# array is a +nil+, interpret the first element of the
|
113
|
-
# headers. Otherwise, synthesize headers of the form
|
114
|
-
# and so forth. The remaining elements are taken
|
115
|
-
# except that if an element of the outer array
|
116
|
-
# preceding row as a group boundary. Note for Emacs
|
117
|
-
# blocks when an org-mode table is passed in as a
|
118
|
-
# as an Array of Arrays. By default (+ HEADER:
|
119
|
-
# all from the table; otherwise (+
|
120
|
-
# with nil elements in the outer
|
111
|
+
# +hlines+ set to false, do not look for separators, i.e. +nils+, just
|
112
|
+
# treat the first row as headers. With +hlines+ set true, expect +nil+
|
113
|
+
# separators to mark the header row and any boundaries. If the second
|
114
|
+
# element of the array is a +nil+, interpret the first element of the
|
115
|
+
# array as a row of headers. Otherwise, synthesize headers of the form
|
116
|
+
# +:col_1+, +:col_2+, ... and so forth. The remaining elements are taken
|
117
|
+
# as the body of the table, except that if an element of the outer array
|
118
|
+
# is a +nil+, mark the preceding row as a group boundary. Note for Emacs
|
119
|
+
# users: In org mode code blocks when an org-mode table is passed in as a
|
120
|
+
# variable it is passed in as an Array of Arrays. By default (+ HEADER:
|
121
|
+
# :hlines no +) org-mode strips all hrules from the table; otherwise (+
|
122
|
+
# HEADER: :hlines yes +) they are indicated with nil elements in the outer
|
123
|
+
# array.
|
121
124
|
def self.from_aoa(aoa, hlines: false)
|
122
125
|
from_array_of_arrays(aoa, hlines: hlines)
|
123
126
|
end
|
@@ -149,10 +152,11 @@ module FatTable
|
|
149
152
|
# :category: Constructors
|
150
153
|
|
151
154
|
# Construct a Table by running a SQL +query+ against the database set up
|
152
|
-
# with FatTable.
|
155
|
+
# with FatTable.connect, with the rows of the query result as rows.
|
153
156
|
def self.from_sql(query)
|
154
|
-
msg = 'FatTable.db must be set with FatTable.
|
157
|
+
msg = 'FatTable.db must be set with FatTable.connect'
|
155
158
|
raise UserError, msg if FatTable.db.nil?
|
159
|
+
|
156
160
|
result = Table.new
|
157
161
|
FatTable.db[query].each do |h|
|
158
162
|
result << h
|
@@ -257,6 +261,7 @@ module FatTable
|
|
257
261
|
unless table_found
|
258
262
|
# Skip through the file until a table is found
|
259
263
|
next unless line.match?(table_re)
|
264
|
+
|
260
265
|
unless line.match?(hrule_re)
|
261
266
|
line = line.sub(/\A\s*\|/, '').sub(/\|\s*\z/, '')
|
262
267
|
rows << line.split('|').map(&:clean)
|
@@ -265,6 +270,7 @@ module FatTable
|
|
265
270
|
next
|
266
271
|
end
|
267
272
|
break unless line.match?(table_re)
|
273
|
+
|
268
274
|
if !header_found && line =~ hrule_re
|
269
275
|
rows << nil
|
270
276
|
header_found = true
|
@@ -272,7 +278,7 @@ module FatTable
|
|
272
278
|
elsif header_found && line =~ hrule_re
|
273
279
|
# Mark the boundary with a nil
|
274
280
|
rows << nil
|
275
|
-
elsif line
|
281
|
+
elsif !line.match?(table_re)
|
276
282
|
# Stop reading at the second hline
|
277
283
|
break
|
278
284
|
else
|
@@ -316,14 +322,17 @@ module FatTable
|
|
316
322
|
when Integer
|
317
323
|
msg = "index '#{key}' out of range"
|
318
324
|
raise UserError, msg unless (0..size - 1).cover?(key.abs)
|
325
|
+
|
319
326
|
rows[key]
|
320
327
|
when String
|
321
328
|
msg = "header '#{key}' not in table"
|
322
329
|
raise UserError, msg unless headers.include?(key)
|
330
|
+
|
323
331
|
column(key).items
|
324
332
|
when Symbol
|
325
333
|
msg = "header ':#{key}' not in table"
|
326
334
|
raise UserError, msg unless headers.include?(key)
|
335
|
+
|
327
336
|
column(key).items
|
328
337
|
else
|
329
338
|
raise UserError, "cannot index table with a #{key.class}"
|
@@ -360,6 +369,7 @@ module FatTable
|
|
360
369
|
# Return the number of rows in the Table.
|
361
370
|
def size
|
362
371
|
return 0 if columns.empty?
|
372
|
+
|
363
373
|
columns.first.size
|
364
374
|
end
|
365
375
|
|
@@ -368,6 +378,7 @@ module FatTable
|
|
368
378
|
# Return the number of Columns in the Table.
|
369
379
|
def width
|
370
380
|
return 0 if columns.empty?
|
381
|
+
|
371
382
|
columns.size
|
372
383
|
end
|
373
384
|
|
@@ -406,6 +417,7 @@ module FatTable
|
|
406
417
|
last ||= size - 1
|
407
418
|
last = [last, 0].max
|
408
419
|
raise UserError, 'first must be <= last' unless first <= last
|
420
|
+
|
409
421
|
rows = []
|
410
422
|
unless columns.empty?
|
411
423
|
first.upto(last) do |rnum|
|
@@ -493,12 +505,12 @@ module FatTable
|
|
493
505
|
self
|
494
506
|
end
|
495
507
|
|
496
|
-
# Mark a group boundary at row +
|
497
|
-
# in the table as a group boundary. This is mainly used for internal
|
508
|
+
# Mark a group boundary at row +row+, and if +row+ is +nil+, mark the last
|
509
|
+
# row in the table as a group boundary. This is mainly used for internal
|
498
510
|
# purposes.
|
499
|
-
def mark_boundary(
|
500
|
-
if
|
501
|
-
boundaries.push(
|
511
|
+
def mark_boundary(row = nil) # :nodoc:
|
512
|
+
if row
|
513
|
+
boundaries.push(row)
|
502
514
|
else
|
503
515
|
boundaries.push(size - 1)
|
504
516
|
end
|
@@ -524,20 +536,21 @@ module FatTable
|
|
524
536
|
@boundaries += bounds.map { |k| k + shift }
|
525
537
|
end
|
526
538
|
|
527
|
-
# Return the group number to which row
|
528
|
-
# point of view are indexed starting at 1.
|
529
|
-
def row_index_to_group_index(
|
539
|
+
# Return the group number to which row ~row~ belongs. Groups, from the
|
540
|
+
# user's point of view are indexed starting at 1.
|
541
|
+
def row_index_to_group_index(row)
|
530
542
|
boundaries.each_with_index do |b_last, g_num|
|
531
|
-
return (g_num + 1) if
|
543
|
+
return (g_num + 1) if row <= b_last
|
532
544
|
end
|
533
545
|
1
|
534
546
|
end
|
535
547
|
|
536
|
-
def group_rows(
|
548
|
+
def group_rows(row) # :nodoc:
|
537
549
|
normalize_boundaries
|
538
|
-
return [] unless
|
539
|
-
|
540
|
-
|
550
|
+
return [] unless row < boundaries.size
|
551
|
+
|
552
|
+
first = row.zero? ? 0 : boundaries[row - 1] + 1
|
553
|
+
last = boundaries[row]
|
541
554
|
rows_range(first, last)
|
542
555
|
end
|
543
556
|
|
@@ -702,6 +715,7 @@ module FatTable
|
|
702
715
|
h = k.as_sym
|
703
716
|
msg = "Column '#{h}' in select does not exist"
|
704
717
|
raise UserError, msg unless column?(h)
|
718
|
+
|
705
719
|
new_row[h] = old_row[h]
|
706
720
|
end
|
707
721
|
new_cols.each_pair do |key, expr|
|
@@ -710,7 +724,8 @@ module FatTable
|
|
710
724
|
case expr
|
711
725
|
when Symbol
|
712
726
|
msg = "Column '#{expr}' in select does not exist"
|
713
|
-
raise UserError, msg unless vars.
|
727
|
+
raise UserError, msg unless vars.key?(expr)
|
728
|
+
|
714
729
|
new_row[key] = vars[expr]
|
715
730
|
when String
|
716
731
|
new_row[key] = ev.evaluate(expr, locals: vars)
|
@@ -864,13 +879,10 @@ module FatTable
|
|
864
879
|
|
865
880
|
private
|
866
881
|
|
867
|
-
# Apply the set operation given by
|
868
|
-
# given in the first argument. If distinct is true, eliminate
|
869
|
-
# from the result.
|
870
|
-
def set_operation(other,
|
871
|
-
distinct: true,
|
872
|
-
add_boundaries: true,
|
873
|
-
inherit_boundaries: false)
|
882
|
+
# Apply the set operation given by ~oper~ between this table and the other
|
883
|
+
# table given in the first argument. If distinct is true, eliminate
|
884
|
+
# duplicates from the result.
|
885
|
+
def set_operation(other, oper = :+, distinct: true, add_boundaries: true, inherit_boundaries: false)
|
874
886
|
unless columns.size == other.columns.size
|
875
887
|
msg = "can't apply set ops to tables with a different number of columns"
|
876
888
|
raise UserError, msg
|
@@ -881,7 +893,7 @@ module FatTable
|
|
881
893
|
end
|
882
894
|
other_rows = other.rows.map { |r| r.replace_keys(headers) }
|
883
895
|
result = Table.new
|
884
|
-
new_rows = rows.send(
|
896
|
+
new_rows = rows.send(oper, other_rows)
|
885
897
|
new_rows.each_with_index do |row, k|
|
886
898
|
result << row
|
887
899
|
result.mark_boundary if k == size - 1 && add_boundaries
|
@@ -975,6 +987,7 @@ module FatTable
|
|
975
987
|
unless JOIN_TYPES.include?(join_type)
|
976
988
|
raise UserError, "join_type may only be: #{JOIN_TYPES.join(', ')}"
|
977
989
|
end
|
990
|
+
|
978
991
|
# These may be needed for outer joins.
|
979
992
|
self_row_nils = headers.map { |h| [h, nil] }.to_h
|
980
993
|
other_row_nils = other.headers.map { |h| [h, nil] }.to_h
|
@@ -992,6 +1005,7 @@ module FatTable
|
|
992
1005
|
locals = build_locals_hash(row_a: self_row, row_b: other_row)
|
993
1006
|
matches = ev.evaluate(join_exp, locals: locals)
|
994
1007
|
next unless matches
|
1008
|
+
|
995
1009
|
self_row_matched = other_row_matches[k] = true
|
996
1010
|
out_row = build_out_row(row_a: self_row, row_b: other_row,
|
997
1011
|
common_heads: other_common_heads,
|
@@ -1000,6 +1014,7 @@ module FatTable
|
|
1000
1014
|
end
|
1001
1015
|
next unless %i[left full].include?(join_type)
|
1002
1016
|
next if self_row_matched
|
1017
|
+
|
1003
1018
|
result << build_out_row(row_a: self_row,
|
1004
1019
|
row_b: other_row_nils,
|
1005
1020
|
type: join_type)
|
@@ -1007,6 +1022,7 @@ module FatTable
|
|
1007
1022
|
if %i[right full].include?(join_type)
|
1008
1023
|
other_rows.each_with_index do |other_row, k|
|
1009
1024
|
next if other_row_matches[k]
|
1025
|
+
|
1010
1026
|
result << build_out_row(row_a: self_row_nils,
|
1011
1027
|
row_b: other_row,
|
1012
1028
|
type: join_type)
|
@@ -1066,10 +1082,10 @@ module FatTable
|
|
1066
1082
|
# Translate any remaining row_b heads to append '_b' if they have the
|
1067
1083
|
# same name as a row_a key.
|
1068
1084
|
a_heads = row_a.keys
|
1069
|
-
row_b = row_b.to_a.each.map
|
1085
|
+
row_b = row_b.to_a.each.map do |k, v|
|
1070
1086
|
[a_heads.include?(k) ? "#{k}_b".to_sym : k, v]
|
1071
|
-
|
1072
|
-
row_a.merge(row_b)
|
1087
|
+
end
|
1088
|
+
row_a.merge(row_b.to_h)
|
1073
1089
|
end
|
1074
1090
|
|
1075
1091
|
# Return a hash for the local variables of a join expression in which all
|
@@ -1090,6 +1106,7 @@ module FatTable
|
|
1090
1106
|
# and all the headers in the other table with '_b' appended.
|
1091
1107
|
def build_join_expression(exps, other, type)
|
1092
1108
|
return ['true', []] if type == :cross
|
1109
|
+
|
1093
1110
|
a_heads = headers
|
1094
1111
|
b_heads = other.headers
|
1095
1112
|
common_heads = a_heads & b_heads
|
@@ -1107,7 +1124,7 @@ module FatTable
|
|
1107
1124
|
[nat_exp, common_heads]
|
1108
1125
|
end
|
1109
1126
|
else
|
1110
|
-
# We have expressions to evaluate
|
1127
|
+
# We have join expressions to evaluate
|
1111
1128
|
and_conds = []
|
1112
1129
|
partial_result = nil
|
1113
1130
|
last_sym = nil
|
@@ -1115,11 +1132,12 @@ module FatTable
|
|
1115
1132
|
case exp
|
1116
1133
|
when Symbol
|
1117
1134
|
case exp.to_s.clean
|
1118
|
-
when /\A(
|
1119
|
-
a_head =
|
1135
|
+
when /\A(?<sy>.*)_a\z/
|
1136
|
+
a_head = Regexp.last_match[:sy].to_sym
|
1120
1137
|
unless a_heads.include?(a_head)
|
1121
1138
|
raise UserError, "no column '#{a_head}' in table"
|
1122
1139
|
end
|
1140
|
+
|
1123
1141
|
if partial_result
|
1124
1142
|
# Second of a pair
|
1125
1143
|
ensure_common_types!(self_h: a_head,
|
@@ -1130,14 +1148,15 @@ module FatTable
|
|
1130
1148
|
partial_result = nil
|
1131
1149
|
else
|
1132
1150
|
# First of a pair of _a or _b
|
1133
|
-
partial_result = "(#{a_head}_a == "
|
1151
|
+
partial_result = String.new("(#{a_head}_a == ")
|
1134
1152
|
end
|
1135
1153
|
last_sym = a_head
|
1136
|
-
when /\A(
|
1137
|
-
b_head =
|
1154
|
+
when /\A(?<sy>.*)_b\z/
|
1155
|
+
b_head = Regexp.last_match[:sy].to_sym
|
1138
1156
|
unless b_heads.include?(b_head)
|
1139
1157
|
raise UserError, "no column '#{b_head}' in second table"
|
1140
1158
|
end
|
1159
|
+
|
1141
1160
|
if partial_result
|
1142
1161
|
# Second of a pair
|
1143
1162
|
ensure_common_types!(self_h: last_sym,
|
@@ -1148,7 +1167,7 @@ module FatTable
|
|
1148
1167
|
partial_result = nil
|
1149
1168
|
else
|
1150
1169
|
# First of a pair of _a or _b
|
1151
|
-
partial_result = "(#{b_head}_b == "
|
1170
|
+
partial_result = String.new("(#{b_head}_b == ")
|
1152
1171
|
end
|
1153
1172
|
b_common_heads << b_head
|
1154
1173
|
last_sym = b_head
|
@@ -1270,7 +1289,7 @@ module FatTable
|
|
1270
1289
|
|
1271
1290
|
# :category: Constructors
|
1272
1291
|
|
1273
|
-
# Add a +row+ without marking it as a group boundary.
|
1292
|
+
# Add a +row+ to this Table without marking it as a group boundary.
|
1274
1293
|
def <<(row)
|
1275
1294
|
add_row(row)
|
1276
1295
|
end
|
@@ -1281,6 +1300,7 @@ module FatTable
|
|
1281
1300
|
def add_column(col)
|
1282
1301
|
msg = "Table already has a column with header '#{col.header}'"
|
1283
1302
|
raise msg if column?(col.header)
|
1303
|
+
|
1284
1304
|
columns << col
|
1285
1305
|
self
|
1286
1306
|
end
|
@@ -1329,11 +1349,12 @@ module FatTable
|
|
1329
1349
|
fmt = fmt_type.as_sym
|
1330
1350
|
msg = "unknown format '#{fmt}'"
|
1331
1351
|
raise UserError, msg unless FatTable::FORMATS.include?(fmt)
|
1352
|
+
|
1332
1353
|
method = "to_#{fmt}"
|
1333
1354
|
if block_given?
|
1334
|
-
send
|
1355
|
+
send(method, options, &Proc.new)
|
1335
1356
|
else
|
1336
|
-
send
|
1357
|
+
send(method, options)
|
1337
1358
|
end
|
1338
1359
|
end
|
1339
1360
|
|
@@ -1347,7 +1368,7 @@ module FatTable
|
|
1347
1368
|
# default format for Formatter, there is no class PsvFormatter as you might
|
1348
1369
|
# expect.
|
1349
1370
|
def to_psv(options = {})
|
1350
|
-
fmt = Formatter.new(self, options)
|
1371
|
+
fmt = Formatter.new(self, **options)
|
1351
1372
|
yield fmt if block_given?
|
1352
1373
|
fmt.output
|
1353
1374
|
end
|
@@ -1360,7 +1381,7 @@ module FatTable
|
|
1360
1381
|
# the block to which formatting instructions and footers can be added by
|
1361
1382
|
# calling methods on it.
|
1362
1383
|
def to_aoa(options = {})
|
1363
|
-
fmt = FatTable::AoaFormatter.new(self, options)
|
1384
|
+
fmt = FatTable::AoaFormatter.new(self, **options)
|
1364
1385
|
yield fmt if block_given?
|
1365
1386
|
fmt.output
|
1366
1387
|
end
|
@@ -1374,7 +1395,7 @@ module FatTable
|
|
1374
1395
|
# given, it yields an AohFormatter to the block to which formatting
|
1375
1396
|
# instructions and footers can be added by calling methods on it.
|
1376
1397
|
def to_aoh(options = {})
|
1377
|
-
fmt = AohFormatter.new(self, options)
|
1398
|
+
fmt = AohFormatter.new(self, **options)
|
1378
1399
|
yield fmt if block_given?
|
1379
1400
|
fmt.output
|
1380
1401
|
end
|
@@ -1387,7 +1408,7 @@ module FatTable
|
|
1387
1408
|
# LaTeXFormatter to the block to which formatting instructions and footers
|
1388
1409
|
# can be added by calling methods on it.
|
1389
1410
|
def to_latex(options = {})
|
1390
|
-
fmt = LaTeXFormatter.new(self, options)
|
1411
|
+
fmt = LaTeXFormatter.new(self, **options)
|
1391
1412
|
yield fmt if block_given?
|
1392
1413
|
fmt.output
|
1393
1414
|
end
|
@@ -1400,7 +1421,7 @@ module FatTable
|
|
1400
1421
|
# OrgFormatter to the block to which formatting instructions and footers can
|
1401
1422
|
# be added by calling methods on it.
|
1402
1423
|
def to_org(options = {})
|
1403
|
-
fmt = OrgFormatter.new(self, options)
|
1424
|
+
fmt = OrgFormatter.new(self, **options)
|
1404
1425
|
yield fmt if block_given?
|
1405
1426
|
fmt.output
|
1406
1427
|
end
|
@@ -1413,7 +1434,7 @@ module FatTable
|
|
1413
1434
|
# given, it yields a TermFormatter to the block to which formatting
|
1414
1435
|
# instructions and footers can be added by calling methods on it.
|
1415
1436
|
def to_term(options = {})
|
1416
|
-
fmt = TermFormatter.new(self, options)
|
1437
|
+
fmt = TermFormatter.new(self, **options)
|
1417
1438
|
yield fmt if block_given?
|
1418
1439
|
fmt.output
|
1419
1440
|
end
|
@@ -1427,7 +1448,7 @@ module FatTable
|
|
1427
1448
|
# footers can be added by calling methods on it.
|
1428
1449
|
# @return [String]
|
1429
1450
|
def to_text(options = {})
|
1430
|
-
fmt = TextFormatter.new(self, options)
|
1451
|
+
fmt = TextFormatter.new(self, **options)
|
1431
1452
|
yield fmt if block_given?
|
1432
1453
|
fmt.output
|
1433
1454
|
end
|