write_xlsx 0.85.11 → 0.86.0
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/Changes +17 -0
- data/examples/colors.rb +47 -0
- data/examples/comments2.rb +1 -1
- data/examples/conditional_format.rb +60 -9
- data/examples/data_validate.rb +7 -7
- data/examples/panes.rb +1 -1
- data/examples/tab_colors.rb +1 -1
- data/lib/write_xlsx/format.rb +1 -1
- data/lib/write_xlsx/package/app.rb +12 -0
- data/lib/write_xlsx/package/comments.rb +4 -2
- data/lib/write_xlsx/package/conditional_format.rb +6 -0
- data/lib/write_xlsx/package/table.rb +17 -5
- data/lib/write_xlsx/package/xml_writer_simple.rb +3 -2
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +12 -11
- data/lib/write_xlsx/worksheet.rb +20 -4
- data/lib/write_xlsx/worksheet/data_validation.rb +22 -10
- data/lib/write_xlsx/worksheet/hyperlink.rb +12 -8
- data/test/regression/images/red_208.png +0 -0
- data/test/regression/test_data_validation08.rb +24 -0
- data/test/regression/test_hyperlink22.rb +24 -0
- data/test/regression/test_hyperlink23.rb +24 -0
- data/test/regression/test_hyperlink24.rb +24 -0
- data/test/regression/test_image28.rb +27 -0
- data/test/regression/test_image29.rb +27 -0
- data/test/regression/test_image30.rb +27 -0
- data/test/regression/test_image31.rb +30 -0
- data/test/regression/test_image32.rb +28 -0
- data/test/regression/test_image33.rb +32 -0
- data/test/regression/test_properties02.rb +28 -0
- data/test/regression/xlsx_files/data_validation08.xlsx +0 -0
- data/test/regression/xlsx_files/hyperlink22.xlsx +0 -0
- data/test/regression/xlsx_files/hyperlink23.xlsx +0 -0
- data/test/regression/xlsx_files/hyperlink24.xlsx +0 -0
- data/test/regression/xlsx_files/image28.xlsx +0 -0
- data/test/regression/xlsx_files/image29.xlsx +0 -0
- data/test/regression/xlsx_files/image30.xlsx +0 -0
- data/test/regression/xlsx_files/image31.xlsx +0 -0
- data/test/regression/xlsx_files/image32.xlsx +0 -0
- data/test/regression/xlsx_files/image33.xlsx +0 -0
- data/test/regression/xlsx_files/properties02.xlsx +0 -0
- data/test/regression/xlsx_files/table18.xlsx +0 -0
- data/test/regression/xlsx_files/table19.xlsx +0 -0
- data/test/worksheet/test_cond_format_21.rb +90 -0
- data/test/worksheet/test_sparkline_12.rb +94 -0
- data/test/worksheet/test_write_data_validation_02.rb +14 -1
- metadata +56 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 794b9b3028ff50abeab1e2c85d951fdc38526887ef6e2d64c6125afe697b4f92
|
4
|
+
data.tar.gz: 0a460f71a4cb05d4f72d7ad77308dbcda504b06f0e56ceceb7d0a9a6e0c0514f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b51f580ca37d7586f3faa6bafebeb76f2b14129070a0e7e70fe9d648e75e504983ad2ad97976ba49b3a8bb5af598826f54aa982dd73a7044132f32044bac6469
|
7
|
+
data.tar.gz: 661206fe8a1eeb9878329559ee9bf5f2a8f12db9515fba264368fe2f9df8711bffe4bb2457a51fb993dcb7aa74ce1c1fcd9740b6b05c6666edebae9288e2e66c
|
data/Changes
CHANGED
@@ -1,5 +1,22 @@
|
|
1
1
|
Change history of write_xlsx rubygem.
|
2
2
|
|
3
|
+
2020-11-01 v0.86.0
|
4
|
+
Fix for images with negative offsets.
|
5
|
+
|
6
|
+
Allow hyperlinks longer than 255 characters when the link and anchor
|
7
|
+
are each less than or equal to 255 characters.
|
8
|
+
|
9
|
+
Added hyperlink_base document property.
|
10
|
+
|
11
|
+
Added option to allow data validation input messages with the ‘any’
|
12
|
+
validate parameter.
|
13
|
+
|
14
|
+
Added "stop if true" feature to conditional formatting.
|
15
|
+
|
16
|
+
Added better support and documentation for html colours throughout
|
17
|
+
the module. The use of the Excel97 colour palette is supported for
|
18
|
+
backward compatibility but deprecated.
|
19
|
+
|
3
20
|
2020-10-23 v0.85.11
|
4
21
|
Added Worksheet#update_range_format_with_params
|
5
22
|
|
data/examples/colors.rb
CHANGED
@@ -126,4 +126,51 @@
|
|
126
126
|
end
|
127
127
|
end
|
128
128
|
|
129
|
+
|
130
|
+
#
|
131
|
+
# Demonstrate the Html colors.
|
132
|
+
#
|
133
|
+
|
134
|
+
colors = {
|
135
|
+
'#000000' => 'black',
|
136
|
+
'#0000FF' => 'blue',
|
137
|
+
'#800000' => 'brown',
|
138
|
+
'#00FFFF' => 'cyan',
|
139
|
+
'#808080' => 'gray',
|
140
|
+
'#008000' => 'green',
|
141
|
+
'#00FF00' => 'lime',
|
142
|
+
'#FF00FF' => 'magenta',
|
143
|
+
'#000080' => 'navy',
|
144
|
+
'#FF6600' => 'orange',
|
145
|
+
'#FF00FF' => 'pink',
|
146
|
+
'#800080' => 'purple',
|
147
|
+
'#FF0000' => 'red',
|
148
|
+
'#C0C0C0' => 'silver',
|
149
|
+
'#FFFFFF' => 'white',
|
150
|
+
'#FFFF00' => 'yellow'
|
151
|
+
}
|
152
|
+
|
153
|
+
worksheet3 = workbook.add_worksheet('Html colors')
|
154
|
+
|
155
|
+
worksheet3.set_column(0, 3, 15)
|
156
|
+
|
157
|
+
worksheet3.write(0, 0, "Html", heading)
|
158
|
+
worksheet3.write(0, 1, "Name", heading)
|
159
|
+
worksheet3.write(0, 2, "Color", heading)
|
160
|
+
|
161
|
+
i = 1
|
162
|
+
|
163
|
+
colors.each do |html_color, color|
|
164
|
+
format = workbook.add_format(
|
165
|
+
:fg_color => html_color,
|
166
|
+
:pattern => 1,
|
167
|
+
:border => 1
|
168
|
+
)
|
169
|
+
|
170
|
+
worksheet3.write(i + 1, 1, html_color, center)
|
171
|
+
worksheet3.write(i + 1, 2, color, center)
|
172
|
+
worksheet3.write(i + 1, 3, '', format)
|
173
|
+
i += 1
|
174
|
+
end
|
175
|
+
|
129
176
|
workbook.close
|
data/examples/comments2.rb
CHANGED
@@ -247,7 +247,7 @@
|
|
247
247
|
comment = 'Hello.'
|
248
248
|
|
249
249
|
worksheet6.write( 'C9', cell_text, text_wrap )
|
250
|
-
worksheet6.write_comment( 'C9', comment, :color =>
|
250
|
+
worksheet6.write_comment( 'C9', comment, :color => '#FF6600' )
|
251
251
|
|
252
252
|
|
253
253
|
###############################################################################
|
@@ -12,6 +12,7 @@
|
|
12
12
|
worksheet6 = workbook.add_worksheet
|
13
13
|
worksheet7 = workbook.add_worksheet
|
14
14
|
worksheet8 = workbook.add_worksheet
|
15
|
+
worksheet9 = workbook.add_worksheet
|
15
16
|
|
16
17
|
# Light red fill with dark red text.
|
17
18
|
format1 = workbook.add_format(
|
@@ -25,6 +26,12 @@
|
|
25
26
|
:color => '#006100'
|
26
27
|
)
|
27
28
|
|
29
|
+
# Blue fill with dark blue text.
|
30
|
+
format3 = workbook.add_format(
|
31
|
+
:bg_color => '#C6CEFF',
|
32
|
+
:color => '#0000FF'
|
33
|
+
)
|
34
|
+
|
28
35
|
# Some sample data to run the conditional formatting against.
|
29
36
|
data = [
|
30
37
|
[ 34, 72, 38, 30, 75, 48, 75, 66, 84, 86 ],
|
@@ -219,18 +226,19 @@
|
|
219
226
|
#
|
220
227
|
caption = 'Examples of color scales and data bars. Default colors.'
|
221
228
|
|
222
|
-
data
|
229
|
+
# Use different sample data for examples 7 and 8
|
230
|
+
data7 = 1 .. 12
|
223
231
|
|
224
232
|
worksheet7.write('A1', caption)
|
225
233
|
|
226
234
|
worksheet7.write('B2', "2 Color Scale")
|
227
|
-
worksheet7.write_col('B3',
|
235
|
+
worksheet7.write_col('B3', data7)
|
228
236
|
|
229
237
|
worksheet7.write('D2', "3 Color Scale")
|
230
|
-
worksheet7.write_col('D3',
|
238
|
+
worksheet7.write_col('D3', data7)
|
231
239
|
|
232
240
|
worksheet7.write('F2', "Data Bars")
|
233
|
-
worksheet7.write_col('F3',
|
241
|
+
worksheet7.write_col('F3', data7)
|
234
242
|
|
235
243
|
|
236
244
|
worksheet7.conditional_formatting('B3:B14',
|
@@ -258,18 +266,16 @@
|
|
258
266
|
#
|
259
267
|
caption = 'Examples of color scales and data bars. Modified colors.'
|
260
268
|
|
261
|
-
data = 1 .. 12
|
262
|
-
|
263
269
|
worksheet8.write('A1', caption)
|
264
270
|
|
265
271
|
worksheet8.write('B2', "2 Color Scale")
|
266
|
-
worksheet8.write_col('B3',
|
272
|
+
worksheet8.write_col('B3', data7)
|
267
273
|
|
268
274
|
worksheet8.write('D2', "3 Color Scale")
|
269
|
-
worksheet8.write_col('D3',
|
275
|
+
worksheet8.write_col('D3', data7)
|
270
276
|
|
271
277
|
worksheet8.write('F2', "Data Bars")
|
272
|
-
worksheet8.write_col('F3',
|
278
|
+
worksheet8.write_col('F3', data7)
|
273
279
|
|
274
280
|
|
275
281
|
worksheet8.conditional_formatting('B3:B14',
|
@@ -296,4 +302,49 @@
|
|
296
302
|
}
|
297
303
|
)
|
298
304
|
|
305
|
+
###############################################################################
|
306
|
+
#
|
307
|
+
# Example 9
|
308
|
+
#
|
309
|
+
caption = 'Cells with values >= 100 are always in blue. ' +
|
310
|
+
'Otherwise, cells with values >= 50 are in light red ' +
|
311
|
+
'and values < 50 are in light green.'
|
312
|
+
|
313
|
+
# Write the data.
|
314
|
+
worksheet9.write('A1', caption)
|
315
|
+
worksheet9.write_col('B3', data)
|
316
|
+
|
317
|
+
# Write a conditional format over a range.
|
318
|
+
# Use stopIfTrue to prevent previous formats from being used
|
319
|
+
# if the conditions of this format are met.
|
320
|
+
worksheet9.conditional_formatting('B3:K12',
|
321
|
+
{
|
322
|
+
:type => 'cell',
|
323
|
+
:criteria => '>=',
|
324
|
+
:value => 100,
|
325
|
+
:format => format3,
|
326
|
+
:stop_if_true => 1
|
327
|
+
}
|
328
|
+
)
|
329
|
+
|
330
|
+
# Write another conditional format over the same range.
|
331
|
+
worksheet9.conditional_formatting('B3:K12',
|
332
|
+
{
|
333
|
+
:type => 'cell',
|
334
|
+
:criteria => '>=',
|
335
|
+
:value => 50,
|
336
|
+
:format => format1
|
337
|
+
}
|
338
|
+
)
|
339
|
+
|
340
|
+
# Write another conditional format over the same range.
|
341
|
+
worksheet9.conditional_formatting('B3:K12',
|
342
|
+
{
|
343
|
+
:type => 'cell',
|
344
|
+
:criteria => '<',
|
345
|
+
:value => 50,
|
346
|
+
:format => format2
|
347
|
+
}
|
348
|
+
)
|
349
|
+
|
299
350
|
workbook.close
|
data/examples/data_validate.rb
CHANGED
@@ -19,13 +19,13 @@
|
|
19
19
|
|
20
20
|
# Add a format for the header cells.
|
21
21
|
header_format = workbook.add_format(
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
22
|
+
:border => 1,
|
23
|
+
:bg_color => '#C6EFCE',
|
24
|
+
:bold => 1,
|
25
|
+
:text_wrap => 1,
|
26
|
+
:valign => 'vcenter',
|
27
|
+
:indent => 1
|
28
|
+
)
|
29
29
|
|
30
30
|
# Set up layout of the worksheet.
|
31
31
|
worksheet.set_column('A:A', 68)
|
data/examples/panes.rb
CHANGED
data/examples/tab_colors.rb
CHANGED
data/lib/write_xlsx/format.rb
CHANGED
@@ -582,7 +582,7 @@ def set_border_color(color)
|
|
582
582
|
def set_rotation(rotation)
|
583
583
|
if rotation == 270
|
584
584
|
rotation = 255
|
585
|
-
elsif rotation >= -90
|
585
|
+
elsif rotation >= -90 && rotation <= 90
|
586
586
|
rotation = -rotation + 90 if rotation < 0
|
587
587
|
else
|
588
588
|
raise "Rotation #{rotation} outside range: -90 <= angle <= 90"
|
@@ -32,6 +32,7 @@ def assemble_xml_file
|
|
32
32
|
write_company
|
33
33
|
write_links_up_to_date
|
34
34
|
write_shared_doc
|
35
|
+
write_hyperlink_base
|
35
36
|
write_hyperlinks_changed
|
36
37
|
write_app_version
|
37
38
|
end
|
@@ -220,6 +221,17 @@ def write_shared_doc
|
|
220
221
|
@writer.data_element('SharedDoc', data)
|
221
222
|
end
|
222
223
|
|
224
|
+
#
|
225
|
+
# Write the <HyperlinkBase> element.
|
226
|
+
#
|
227
|
+
def write_hyperlink_base
|
228
|
+
data = @properties[:hyperlink_base]
|
229
|
+
|
230
|
+
return unless data
|
231
|
+
|
232
|
+
@writer.data_element('HyperlinkBase', data)
|
233
|
+
end
|
234
|
+
|
223
235
|
#
|
224
236
|
# Write the <HyperlinksChanged> element.
|
225
237
|
#
|
@@ -41,11 +41,13 @@ def initialize(workbook, worksheet, row, col, string, options = {})
|
|
41
41
|
def backgrount_color(color)
|
42
42
|
color_id = Format.color(color)
|
43
43
|
|
44
|
-
if color_id
|
44
|
+
if color_id.to_s =~ /^#[0-9A-F]{6}/i
|
45
|
+
@color = color_id.to_s
|
46
|
+
elsif color_id == 0
|
45
47
|
@color = '#ffffe1'
|
46
48
|
else
|
47
49
|
rgb = @workbook.palette[color_id - 8]
|
48
|
-
@color = "##{rgb_color(rgb)} [#{color_id}]
|
50
|
+
@color = "##{rgb_color(rgb)} [#{color_id}]"
|
49
51
|
end
|
50
52
|
end
|
51
53
|
|
@@ -71,6 +71,7 @@ def attributes
|
|
71
71
|
attr << ['type' , type]
|
72
72
|
attr << ['dxfId', format] if format
|
73
73
|
attr << ['priority', priority]
|
74
|
+
attr << ['stopIfTrue', 1] if stop_if_true
|
74
75
|
attr
|
75
76
|
end
|
76
77
|
|
@@ -86,6 +87,10 @@ def priority
|
|
86
87
|
@param[:priority]
|
87
88
|
end
|
88
89
|
|
90
|
+
def stop_if_true
|
91
|
+
@param[:stop_if_true]
|
92
|
+
end
|
93
|
+
|
89
94
|
def criteria
|
90
95
|
@param[:criteria]
|
91
96
|
end
|
@@ -401,6 +406,7 @@ def valid_parameter_for_conditional_formatting
|
|
401
406
|
:value,
|
402
407
|
:minimum,
|
403
408
|
:maximum,
|
409
|
+
:stop_if_true,
|
404
410
|
:min_type,
|
405
411
|
:mid_type,
|
406
412
|
:max_type,
|
@@ -10,7 +10,7 @@ class Table
|
|
10
10
|
|
11
11
|
class ColumnData
|
12
12
|
attr_reader :id
|
13
|
-
attr_accessor :name, :format, :formula
|
13
|
+
attr_accessor :name, :format, :formula, :name_format
|
14
14
|
attr_accessor :total_string, :total_function
|
15
15
|
|
16
16
|
def initialize(id, param = {})
|
@@ -20,6 +20,7 @@ def initialize(id, param = {})
|
|
20
20
|
@total_function = ''
|
21
21
|
@formula = ''
|
22
22
|
@format = nil
|
23
|
+
@name_format = nil
|
23
24
|
@user_data = param[id-1] if param
|
24
25
|
end
|
25
26
|
end
|
@@ -93,10 +94,14 @@ def overrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
|
|
93
94
|
if user_data[:header] && !user_data[:header].empty?
|
94
95
|
col_data.name = user_data[:header]
|
95
96
|
end
|
97
|
+
|
98
|
+
# Get the header format if defined.
|
99
|
+
col_data.name_format = user_data[:header_format]
|
100
|
+
|
96
101
|
# Handle the column formula.
|
97
102
|
handle_the_column_formula(
|
98
|
-
|
99
|
-
|
103
|
+
col_data, col_num, user_data[:formula], user_data[:format]
|
104
|
+
)
|
100
105
|
|
101
106
|
# Handle the function for the total row.
|
102
107
|
if user_data[:total_function]
|
@@ -123,7 +128,9 @@ def overrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
|
|
123
128
|
|
124
129
|
def write_the_column_headers_to_the_worksheet(col_num, col_data)
|
125
130
|
if @param[:header_row] != 0
|
126
|
-
@worksheet.write_string(
|
131
|
+
@worksheet.write_string(
|
132
|
+
@row1, col_num, col_data.name, col_data.name_format
|
133
|
+
)
|
127
134
|
end
|
128
135
|
end
|
129
136
|
|
@@ -268,7 +275,12 @@ def set_the_table_style
|
|
268
275
|
end
|
269
276
|
|
270
277
|
def set_the_table_name
|
271
|
-
|
278
|
+
if @param[:name]
|
279
|
+
name = @param[:name]
|
280
|
+
|
281
|
+
raise "Name '#{name} in add_table cannot contain spaces" if name =~ /\s/
|
282
|
+
@name = @param[:name]
|
283
|
+
end
|
272
284
|
end
|
273
285
|
|
274
286
|
def set_the_table_and_autofilter_ranges
|
@@ -118,13 +118,14 @@ def key_vals(attribute)
|
|
118
118
|
end
|
119
119
|
|
120
120
|
def escape_attributes(str = '')
|
121
|
-
return str if !(str.to_s =~ /["
|
121
|
+
return str if !(str.to_s =~ /["&<>\n]/)
|
122
122
|
|
123
123
|
str.
|
124
124
|
gsub(/&/, "&").
|
125
125
|
gsub(/"/, """).
|
126
126
|
gsub(/</, "<").
|
127
|
-
gsub(/>/, ">")
|
127
|
+
gsub(/>/, ">").
|
128
|
+
gsub(/\n/, "
")
|
128
129
|
end
|
129
130
|
|
130
131
|
def escape_data(str = '')
|
data/lib/write_xlsx/version.rb
CHANGED
@@ -1 +1 @@
|
|
1
|
-
WriteXLSX_VERSION = "0.
|
1
|
+
WriteXLSX_VERSION = "0.86.0"
|
data/lib/write_xlsx/workbook.rb
CHANGED
@@ -786,17 +786,18 @@ def set_properties(params)
|
|
786
786
|
|
787
787
|
# List of valid input parameters.
|
788
788
|
valid = {
|
789
|
-
:title
|
790
|
-
:subject
|
791
|
-
:author
|
792
|
-
:keywords
|
793
|
-
:comments
|
794
|
-
:last_author
|
795
|
-
:created
|
796
|
-
:category
|
797
|
-
:manager
|
798
|
-
:company
|
799
|
-
:status
|
789
|
+
:title => 1,
|
790
|
+
:subject => 1,
|
791
|
+
:author => 1,
|
792
|
+
:keywords => 1,
|
793
|
+
:comments => 1,
|
794
|
+
:last_author => 1,
|
795
|
+
:created => 1,
|
796
|
+
:category => 1,
|
797
|
+
:manager => 1,
|
798
|
+
:company => 1,
|
799
|
+
:status => 1,
|
800
|
+
:hyperlink_base => 1
|
800
801
|
}
|
801
802
|
|
802
803
|
# Check for valid input parameters.
|
data/lib/write_xlsx/worksheet.rb
CHANGED
@@ -296,6 +296,7 @@ class Worksheet
|
|
296
296
|
attr_reader :comments, :comments_author # :nodoc:
|
297
297
|
attr_accessor :dxf_priority # :nodoc:
|
298
298
|
attr_reader :vba_codename # :nodoc:
|
299
|
+
attr_writer :excel_version
|
299
300
|
|
300
301
|
def initialize(workbook, index, name) #:nodoc:
|
301
302
|
@writer = Package::XMLWriterSimple.new
|
@@ -4288,7 +4289,7 @@ def conditional_formatting(*args)
|
|
4288
4289
|
# :header
|
4289
4290
|
# :formula
|
4290
4291
|
# :total_string
|
4291
|
-
# :
|
4292
|
+
# :
|
4292
4293
|
# :format
|
4293
4294
|
#
|
4294
4295
|
# The column data must be specified as an array of hash. For example to
|
@@ -4916,9 +4917,8 @@ def insert_button(*args)
|
|
4916
4917
|
# :custom
|
4917
4918
|
#
|
4918
4919
|
# +:any+ is used to specify that the type of data is unrestricted.
|
4919
|
-
# This is
|
4920
|
-
#
|
4921
|
-
# context of WriteXLSX.
|
4920
|
+
# This is usefl to display an input message without restricting the data
|
4921
|
+
# that can be entered.
|
4922
4922
|
#
|
4923
4923
|
# +:integer+ restricts the cell to integer values. Excel refers to this
|
4924
4924
|
# as 'whole number'.
|
@@ -5802,6 +5802,22 @@ def get_range_data(row_start, col_start, row_end, col_end) # :nodoc:
|
|
5802
5802
|
# width # Width of object frame.
|
5803
5803
|
# height # Height of object frame.
|
5804
5804
|
def position_object_pixels(col_start, row_start, x1, y1, width, height) #:nodoc:
|
5805
|
+
# Adjust start column for negative offsets.
|
5806
|
+
while x1 < 0 && col_start > 0
|
5807
|
+
x1 += size_col(col_start - 1)
|
5808
|
+
col_start -= 1
|
5809
|
+
end
|
5810
|
+
|
5811
|
+
# Adjust start row for negative offsets.
|
5812
|
+
while y1 < 0 && row_start > 0
|
5813
|
+
y1 += size_row(row_start - 1)
|
5814
|
+
row_start -= 1
|
5815
|
+
end
|
5816
|
+
|
5817
|
+
# Ensure that the image isn't shifted off the page at top left.
|
5818
|
+
x1 = 0 if x1 < 0
|
5819
|
+
y1 = 0 if y1 < 0
|
5820
|
+
|
5805
5821
|
# Calculate the absolute x offset of the top-left vertex.
|
5806
5822
|
if @col_size_changed
|
5807
5823
|
x_abs = (0 .. col_start-1).inject(0) {|sum, col| sum += size_col(col)}
|