write_xlsx 1.10.2 → 1.11.1
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/.rubocop.yml +10 -1
- data/Changes +18 -0
- data/examples/autofit.rb +37 -0
- data/examples/chart_radar.rb +3 -9
- data/lib/write_xlsx/chart/area.rb +1 -0
- data/lib/write_xlsx/chart/axis.rb +1 -0
- data/lib/write_xlsx/chart/bar.rb +1 -0
- data/lib/write_xlsx/chart/caption.rb +1 -0
- data/lib/write_xlsx/chart/column.rb +1 -0
- data/lib/write_xlsx/chart/doughnut.rb +1 -0
- data/lib/write_xlsx/chart/legend.rb +1 -0
- data/lib/write_xlsx/chart/line.rb +1 -0
- data/lib/write_xlsx/chart/pie.rb +1 -0
- data/lib/write_xlsx/chart/radar.rb +1 -0
- data/lib/write_xlsx/chart/scatter.rb +1 -0
- data/lib/write_xlsx/chart/series.rb +8 -4
- data/lib/write_xlsx/chart/stock.rb +1 -0
- data/lib/write_xlsx/chart.rb +45 -14
- data/lib/write_xlsx/colors.rb +20 -19
- data/lib/write_xlsx/format.rb +13 -9
- data/lib/write_xlsx/package/comments.rb +2 -1
- data/lib/write_xlsx/package/conditional_format.rb +4 -4
- data/lib/write_xlsx/package/shared_strings.rb +5 -3
- data/lib/write_xlsx/package/styles.rb +27 -30
- data/lib/write_xlsx/package/table.rb +9 -0
- data/lib/write_xlsx/utility.rb +40 -7
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +20 -11
- data/lib/write_xlsx/worksheet/cell_data.rb +11 -4
- data/lib/write_xlsx/worksheet.rb +264 -81
- metadata +4 -3
data/lib/write_xlsx/worksheet.rb
CHANGED
@@ -23,6 +23,7 @@ module Writexlsx
|
|
23
23
|
|
24
24
|
MAX_DIGIT_WIDTH = 7 # For Calabri 11. # :nodoc:
|
25
25
|
PADDING = 5 # :nodoc:
|
26
|
+
COLINFO = Struct.new('ColInfo', :width, :format, :hidden, :level, :collapsed, :autofit)
|
26
27
|
|
27
28
|
attr_reader :index # :nodoc:
|
28
29
|
attr_reader :charts, :images, :tables, :shapes, :drawings # :nodoc:
|
@@ -31,20 +32,25 @@ module Writexlsx
|
|
31
32
|
attr_reader :vml_data_id # :nodoc:
|
32
33
|
attr_reader :vml_header_id # :nodoc:
|
33
34
|
attr_reader :autofilter_area # :nodoc:
|
34
|
-
attr_reader :writer, :set_rows, :
|
35
|
+
attr_reader :writer, :set_rows, :col_info # :nodoc:
|
35
36
|
attr_reader :vml_shape_id # :nodoc:
|
36
37
|
attr_reader :comments, :comments_author # :nodoc:
|
37
38
|
attr_accessor :data_bars_2010, :dxf_priority # :nodoc:
|
38
39
|
attr_reader :vba_codename # :nodoc:
|
39
|
-
attr_writer :excel_version
|
40
|
+
attr_writer :excel_version # :nodoc:
|
41
|
+
attr_reader :filter_cells # :nodoc:
|
40
42
|
|
41
43
|
def initialize(workbook, index, name) # :nodoc:
|
44
|
+
rowmax = 1_048_576
|
45
|
+
colmax = 16_384
|
46
|
+
strmax = 32_767
|
47
|
+
|
42
48
|
@writer = Package::XMLWriterSimple.new
|
43
49
|
|
44
50
|
@workbook = workbook
|
45
51
|
@index = index
|
46
52
|
@name = name
|
47
|
-
@
|
53
|
+
@col_info = {}
|
48
54
|
@cell_data_table = []
|
49
55
|
@excel_version = 2007
|
50
56
|
@palette = workbook.palette
|
@@ -55,6 +61,10 @@ module Writexlsx
|
|
55
61
|
|
56
62
|
@screen_gridlines = true
|
57
63
|
@show_zeros = true
|
64
|
+
|
65
|
+
@xls_rowmax = rowmax
|
66
|
+
@xls_colmax = colmax
|
67
|
+
@xls_strmax = strmax
|
58
68
|
@dim_rowmin = nil
|
59
69
|
@dim_rowmax = nil
|
60
70
|
@dim_colmin = nil
|
@@ -77,11 +87,10 @@ module Writexlsx
|
|
77
87
|
@filter_on = false
|
78
88
|
@filter_range = []
|
79
89
|
@filter_cols = {}
|
90
|
+
@filter_cells = {}
|
80
91
|
@filter_type = {}
|
81
92
|
|
82
|
-
@col_sizes = {}
|
83
93
|
@row_sizes = {}
|
84
|
-
@col_formats = {}
|
85
94
|
|
86
95
|
@last_shape_id = 1
|
87
96
|
@rel_count = 0
|
@@ -90,8 +99,8 @@ module Writexlsx
|
|
90
99
|
@external_drawing_links = []
|
91
100
|
@external_comment_links = []
|
92
101
|
@external_vml_links = []
|
93
|
-
@external_table_links = []
|
94
102
|
@external_background_links = []
|
103
|
+
@external_table_links = []
|
95
104
|
@drawing_links = []
|
96
105
|
@vml_drawing_links = []
|
97
106
|
@charts = []
|
@@ -121,6 +130,7 @@ module Writexlsx
|
|
121
130
|
@default_col_width = 8.43
|
122
131
|
@default_col_pixels = 64
|
123
132
|
@default_row_rezoed = 0
|
133
|
+
@default_date_pixels = 68
|
124
134
|
|
125
135
|
@merge = []
|
126
136
|
|
@@ -305,7 +315,8 @@ module Writexlsx
|
|
305
315
|
#
|
306
316
|
def set_column(*args)
|
307
317
|
# Check for a cell reference in A1 notation and substitute row and column
|
308
|
-
|
318
|
+
# ruby 3.2 no longer handles =~ for various types
|
319
|
+
if args[0].respond_to?(:=~) && args[0].to_s =~ /^\D/
|
309
320
|
_row1, firstcol, _row2, lastcol, *data = substitute_cellref(*args)
|
310
321
|
else
|
311
322
|
firstcol, lastcol, *data = args
|
@@ -321,6 +332,7 @@ module Writexlsx
|
|
321
332
|
firstcol, lastcol = lastcol, firstcol if firstcol > lastcol
|
322
333
|
|
323
334
|
width, format, hidden, level, collapsed = data
|
335
|
+
autofit = 0
|
324
336
|
|
325
337
|
# Check that cols are valid and store max and min values with default row.
|
326
338
|
# NOTE: The check shouldn't modify the row dimensions and should only modify
|
@@ -338,22 +350,19 @@ module Writexlsx
|
|
338
350
|
level = 0 if level < 0
|
339
351
|
level = 7 if level > 7
|
340
352
|
|
353
|
+
# Excel has a maximum column width of 255 characters.
|
354
|
+
width = 255.0 if width && width > 255.0
|
355
|
+
|
341
356
|
@outline_col_level = level if level > @outline_col_level
|
342
357
|
|
343
358
|
# Store the column data based on the first column. Padded for sorting.
|
344
|
-
|
359
|
+
(firstcol..lastcol).each do |col|
|
360
|
+
@col_info[col] =
|
361
|
+
COLINFO.new(width, format, hidden, level, collapsed, autofit)
|
362
|
+
end
|
345
363
|
|
346
364
|
# Store the column change to allow optimisations.
|
347
365
|
@col_size_changed = 1
|
348
|
-
|
349
|
-
# Store the col sizes for use when calculating image vertices taking
|
350
|
-
# hidden columns into account. Also store the column formats.
|
351
|
-
width ||= @default_col_width
|
352
|
-
|
353
|
-
(firstcol..lastcol).each do |col|
|
354
|
-
@col_sizes[col] = [width, hidden]
|
355
|
-
@col_formats[col] = format if format
|
356
|
-
end
|
357
366
|
end
|
358
367
|
|
359
368
|
#
|
@@ -387,6 +396,112 @@ module Writexlsx
|
|
387
396
|
set_column(first_col, last_col, width, format, hidden, level)
|
388
397
|
end
|
389
398
|
|
399
|
+
#
|
400
|
+
# autofit()
|
401
|
+
#
|
402
|
+
# Simulate autofit based on the data, and datatypes in each column. We do this
|
403
|
+
# by estimating a pixel width for each cell data.
|
404
|
+
#
|
405
|
+
def autofit
|
406
|
+
col_width = {}
|
407
|
+
|
408
|
+
# Iterate through all the data in the worksheet.
|
409
|
+
(@dim_rowmin..@dim_rowmax).each do |row_num|
|
410
|
+
# Skip row if it doesn't contain cell data.
|
411
|
+
next unless @cell_data_table[row_num]
|
412
|
+
|
413
|
+
(@dim_colmin..@dim_colmax).each do |col_num|
|
414
|
+
length = 0
|
415
|
+
case (cell_data = @cell_data_table[row_num][col_num])
|
416
|
+
when StringCellData, RichStringCellData
|
417
|
+
# Handle strings and rich strings.
|
418
|
+
#
|
419
|
+
# For standard shared strings we do a reverse lookup
|
420
|
+
# from the shared string id to the actual string. For
|
421
|
+
# rich strings we use the unformatted string. We also
|
422
|
+
# split multiline strings and handle each part
|
423
|
+
# separately.
|
424
|
+
string = cell_data.raw_string
|
425
|
+
|
426
|
+
if string =~ /\n/
|
427
|
+
# Handle multiline strings.
|
428
|
+
length = max = string.split("\n").collect do |str|
|
429
|
+
xl_string_pixel_width(str)
|
430
|
+
end.max
|
431
|
+
else
|
432
|
+
length = xl_string_pixel_width(string)
|
433
|
+
end
|
434
|
+
when DateTimeCellData
|
435
|
+
|
436
|
+
# Handle dates.
|
437
|
+
#
|
438
|
+
# The following uses the default width for mm/dd/yyyy
|
439
|
+
# dates. It isn't feasible to parse the number format
|
440
|
+
# to get the actual string width for all format types.
|
441
|
+
length = @default_date_pixels
|
442
|
+
when NumberCellData
|
443
|
+
|
444
|
+
# Handle numbers.
|
445
|
+
#
|
446
|
+
# We use a workaround/optimization for numbers since
|
447
|
+
# digits all have a pixel width of 7. This gives a
|
448
|
+
# slightly greater width for the decimal place and
|
449
|
+
# minus sign but only by a few pixels and
|
450
|
+
# over-estimation is okay.
|
451
|
+
length = 7 * cell_data.token.to_s.length
|
452
|
+
when BooleanCellData
|
453
|
+
|
454
|
+
# Handle boolean values.
|
455
|
+
#
|
456
|
+
# Use the Excel standard widths for TRUE and FALSE.
|
457
|
+
if ptrue?(cell_data.token)
|
458
|
+
length = 31
|
459
|
+
else
|
460
|
+
length = 36
|
461
|
+
end
|
462
|
+
when FormulaCellData, FormulaArrayCellData, DynamicFormulaArrayCellData
|
463
|
+
# Handle formulas.
|
464
|
+
#
|
465
|
+
# We only try to autofit a formula if it has a
|
466
|
+
# non-zero value.
|
467
|
+
if ptrue?(cell_data.data)
|
468
|
+
length = xl_string_pixel_width(cell_data.data)
|
469
|
+
end
|
470
|
+
end
|
471
|
+
|
472
|
+
# If the cell is in an autofilter header we add an
|
473
|
+
# additional 16 pixels for the dropdown arrow.
|
474
|
+
if length > 0 &&
|
475
|
+
@filter_cells["#{row_num}:#{col_num}"]
|
476
|
+
length += 16
|
477
|
+
end
|
478
|
+
|
479
|
+
# Add the string lenght to the lookup hash.
|
480
|
+
max = col_width[col_num] || 0
|
481
|
+
col_width[col_num] = length if length > max
|
482
|
+
end
|
483
|
+
end
|
484
|
+
|
485
|
+
# Apply the width to the column.
|
486
|
+
col_width.each do |col_num, pixel_width|
|
487
|
+
# Convert the string pixel width to a character width using an
|
488
|
+
# additional padding of 7 pixels, like Excel.
|
489
|
+
width = pixels_to_width(pixel_width + 7)
|
490
|
+
|
491
|
+
# The max column character width in Excel is 255.
|
492
|
+
width = 255.0 if width > 255.0
|
493
|
+
|
494
|
+
# Add the width to an existing col info structure or add a new one.
|
495
|
+
if @col_info[col_num]
|
496
|
+
@col_info[col_num].width = width
|
497
|
+
@col_info[col_num].autofit = 1
|
498
|
+
else
|
499
|
+
@col_info[col_num] =
|
500
|
+
COLINFO.new(width, nil, 0, 0, 0, 1)
|
501
|
+
end
|
502
|
+
end
|
503
|
+
end
|
504
|
+
|
390
505
|
#
|
391
506
|
# :call-seq:
|
392
507
|
# set_selection(cell_or_cell_range)
|
@@ -936,31 +1051,35 @@ module Writexlsx
|
|
936
1051
|
write_row(_row, _col, _token, _format, _value1, _value2)
|
937
1052
|
elsif _token.respond_to?(:coerce) # Numeric
|
938
1053
|
write_number(_row, _col, _token, _format)
|
939
|
-
|
940
|
-
|
941
|
-
|
942
|
-
|
943
|
-
|
944
|
-
|
945
|
-
|
946
|
-
|
947
|
-
|
948
|
-
|
949
|
-
|
950
|
-
|
951
|
-
|
952
|
-
|
953
|
-
|
954
|
-
|
955
|
-
|
956
|
-
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
961
|
-
|
962
|
-
|
963
|
-
|
1054
|
+
elsif _token.respond_to?(:=~) # String
|
1055
|
+
# Match integer with leading zero(s)
|
1056
|
+
if @leading_zeros && _token =~ /^0\d*$/
|
1057
|
+
write_string(_row, _col, _token, _format)
|
1058
|
+
elsif _token =~ /\A([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?\Z/
|
1059
|
+
write_number(_row, _col, _token, _format)
|
1060
|
+
# Match formula
|
1061
|
+
elsif _token =~ /^=/
|
1062
|
+
write_formula(_row, _col, _token, _format, _value1)
|
1063
|
+
# Match array formula
|
1064
|
+
elsif _token =~ /^\{=.*\}$/
|
1065
|
+
write_formula(_row, _col, _token, _format, _value1)
|
1066
|
+
# Match blank
|
1067
|
+
elsif _token == ''
|
1068
|
+
# row_col_args.delete_at(2) # remove the empty string from the parameter list
|
1069
|
+
write_blank(_row, _col, _format)
|
1070
|
+
elsif @workbook.strings_to_urls
|
1071
|
+
# Match http, https or ftp URL
|
1072
|
+
if _token =~ %r{\A[fh]tt?ps?://}
|
1073
|
+
write_url(_row, _col, _token, _format, _value1, _value2)
|
1074
|
+
# Match mailto:
|
1075
|
+
elsif _token =~ /\Amailto:/
|
1076
|
+
write_url(_row, _col, _token, _format, _value1, _value2)
|
1077
|
+
# Match internal or external sheet link
|
1078
|
+
elsif _token =~ /\A(?:in|ex)ternal:/
|
1079
|
+
write_url(_row, _col, _token, _format, _value1, _value2)
|
1080
|
+
else
|
1081
|
+
write_string(_row, _col, _token, _format)
|
1082
|
+
end
|
964
1083
|
else
|
965
1084
|
write_string(_row, _col, _token, _format)
|
966
1085
|
end
|
@@ -1114,7 +1233,7 @@ module Writexlsx
|
|
1114
1233
|
|
1115
1234
|
index = shared_string_index(_string.length > STR_MAX ? _string[0, STR_MAX] : _string)
|
1116
1235
|
|
1117
|
-
store_data_to_table(StringCellData.new(index, _format), _row, _col)
|
1236
|
+
store_data_to_table(StringCellData.new(index, _format, _string), _row, _col)
|
1118
1237
|
end
|
1119
1238
|
|
1120
1239
|
#
|
@@ -1143,13 +1262,16 @@ module Writexlsx
|
|
1143
1262
|
check_dimensions(_row, _col)
|
1144
1263
|
store_row_col_max_min_values(_row, _col)
|
1145
1264
|
|
1146
|
-
_fragments,
|
1265
|
+
_fragments, _raw_string = rich_strings_fragments(_rich_strings)
|
1147
1266
|
# can't allow 2 formats in a row
|
1148
1267
|
return -4 unless _fragments
|
1149
1268
|
|
1269
|
+
# Check that the string si < 32767 chars.
|
1270
|
+
return 3 if _raw_string.size > @xls_strmax
|
1271
|
+
|
1150
1272
|
index = shared_string_index(xml_str_of_rich_string(_fragments))
|
1151
1273
|
|
1152
|
-
store_data_to_table(
|
1274
|
+
store_data_to_table(RichStringCellData.new(index, _xf, _raw_string), _row, _col)
|
1153
1275
|
end
|
1154
1276
|
|
1155
1277
|
#
|
@@ -1679,7 +1801,7 @@ module Writexlsx
|
|
1679
1801
|
date_time = convert_date_time(_str)
|
1680
1802
|
|
1681
1803
|
if date_time
|
1682
|
-
store_data_to_table(
|
1804
|
+
store_data_to_table(DateTimeCellData.new(date_time, _format), _row, _col)
|
1683
1805
|
else
|
1684
1806
|
# If the date isn't valid then write it as a string.
|
1685
1807
|
write_string(_row, _col, _str, _format)
|
@@ -2164,6 +2286,11 @@ module Writexlsx
|
|
2164
2286
|
@autofilter_area = convert_name_area(_row1, _col1, _row2, _col2)
|
2165
2287
|
@autofilter_ref = xl_range(_row1, _row2, _col1, _col2)
|
2166
2288
|
@filter_range = [_col1, _col2]
|
2289
|
+
|
2290
|
+
# Store the filter cell positions for use in the autofit calculation.
|
2291
|
+
(_col1.._col2).each do |col|
|
2292
|
+
@filter_cells["#{_row1}:#{col}"] = 1
|
2293
|
+
end
|
2167
2294
|
end
|
2168
2295
|
|
2169
2296
|
#
|
@@ -2506,8 +2633,8 @@ module Writexlsx
|
|
2506
2633
|
@external_hyper_links,
|
2507
2634
|
@external_drawing_links,
|
2508
2635
|
@external_vml_links,
|
2509
|
-
@external_table_links,
|
2510
2636
|
@external_background_links,
|
2637
|
+
@external_table_links,
|
2511
2638
|
@external_comment_links
|
2512
2639
|
].reject { |a| a.empty? }
|
2513
2640
|
end
|
@@ -2634,6 +2761,33 @@ module Writexlsx
|
|
2634
2761
|
|
2635
2762
|
private
|
2636
2763
|
|
2764
|
+
#
|
2765
|
+
# Compare adjacent column information structures.
|
2766
|
+
#
|
2767
|
+
def compare_col_info(col_options, previous_options)
|
2768
|
+
if !col_options.width.nil? != !previous_options.width.nil?
|
2769
|
+
return nil
|
2770
|
+
end
|
2771
|
+
if col_options.width && previous_options.width &&
|
2772
|
+
col_options.width != previous_options.width
|
2773
|
+
return nil
|
2774
|
+
end
|
2775
|
+
|
2776
|
+
if !col_options.format.nil? != !previous_options.format.nil?
|
2777
|
+
return nil
|
2778
|
+
end
|
2779
|
+
if col_options.format && previous_options.format &&
|
2780
|
+
col_options.format != previous_options.format
|
2781
|
+
return nil
|
2782
|
+
end
|
2783
|
+
|
2784
|
+
return nil if col_options.hidden != previous_options.hidden
|
2785
|
+
return nil if col_options.level != previous_options.level
|
2786
|
+
return nil if col_options.collapsed != previous_options.collapsed
|
2787
|
+
|
2788
|
+
true
|
2789
|
+
end
|
2790
|
+
|
2637
2791
|
#
|
2638
2792
|
# Get the index used to address a drawing rel link.
|
2639
2793
|
#
|
@@ -2685,9 +2839,9 @@ module Writexlsx
|
|
2685
2839
|
# Create a temp format with the default font for unformatted fragments.
|
2686
2840
|
default = Format.new(0)
|
2687
2841
|
|
2688
|
-
length = 0 # String length.
|
2689
2842
|
last = 'format'
|
2690
2843
|
pos = 0
|
2844
|
+
raw_string = ''
|
2691
2845
|
|
2692
2846
|
fragments = []
|
2693
2847
|
rich_strings.each do |token|
|
@@ -2708,12 +2862,12 @@ module Writexlsx
|
|
2708
2862
|
fragments << default << token
|
2709
2863
|
end
|
2710
2864
|
|
2711
|
-
|
2865
|
+
raw_string += token # Keep track of actual string length.
|
2712
2866
|
last = 'string'
|
2713
2867
|
end
|
2714
2868
|
pos += 1
|
2715
2869
|
end
|
2716
|
-
[fragments,
|
2870
|
+
[fragments, raw_string]
|
2717
2871
|
end
|
2718
2872
|
|
2719
2873
|
def xml_str_of_rich_string(fragments)
|
@@ -2944,8 +3098,9 @@ module Writexlsx
|
|
2944
3098
|
#
|
2945
3099
|
def size_col(col, anchor = 0) # :nodoc:
|
2946
3100
|
# Look up the cell value to see if it has been changed.
|
2947
|
-
if @
|
2948
|
-
width
|
3101
|
+
if @col_info[col]
|
3102
|
+
width = @col_info[col].width || @default_col_width
|
3103
|
+
hidden = @col_info[col].hidden
|
2949
3104
|
|
2950
3105
|
# Convert to pixels.
|
2951
3106
|
pixels = if hidden == 1 && anchor != 4
|
@@ -3276,28 +3431,22 @@ EOS
|
|
3276
3431
|
end
|
3277
3432
|
|
3278
3433
|
#
|
3279
|
-
# Based on the algorithm
|
3280
|
-
#
|
3434
|
+
# Hash a worksheet password. Based on the algorithm in ECMA-376-4:2016,
|
3435
|
+
# Office Open XML File Foemats -- Transitional Migration Features,
|
3436
|
+
# Additional attributes for workbookProtection element (Part 1, §18.2.29). #
|
3281
3437
|
def encode_password(password) # :nodoc:
|
3282
|
-
|
3283
|
-
chars = password.split(//)
|
3284
|
-
count = chars.size
|
3438
|
+
hash = 0
|
3285
3439
|
|
3286
|
-
|
3287
|
-
|
3288
|
-
|
3289
|
-
low_15 = char & 0x7fff
|
3290
|
-
high_15 = char & (0x7fff << 15)
|
3291
|
-
high_15 = high_15 >> 15
|
3292
|
-
char = low_15 | high_15
|
3440
|
+
password.reverse.split(//).each do |char|
|
3441
|
+
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff)
|
3442
|
+
hash ^= char.ord
|
3293
3443
|
end
|
3294
3444
|
|
3295
|
-
|
3296
|
-
|
3297
|
-
|
3298
|
-
encoded_password ^= 0xCE4B
|
3445
|
+
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff)
|
3446
|
+
hash ^= password.length
|
3447
|
+
hash ^= 0xCE4B
|
3299
3448
|
|
3300
|
-
sprintf("%X",
|
3449
|
+
sprintf("%X", hash)
|
3301
3450
|
end
|
3302
3451
|
|
3303
3452
|
#
|
@@ -3475,10 +3624,42 @@ EOS
|
|
3475
3624
|
#
|
3476
3625
|
def write_cols # :nodoc:
|
3477
3626
|
# Exit unless some column have been formatted.
|
3478
|
-
return if @
|
3627
|
+
return if @col_info.empty?
|
3479
3628
|
|
3480
3629
|
@writer.tag_elements('cols') do
|
3481
|
-
|
3630
|
+
# Use the first element of the column informatin structure to set
|
3631
|
+
# the initial/previous properties.
|
3632
|
+
first_col = @col_info.keys.min
|
3633
|
+
last_col = first_col
|
3634
|
+
previous_options = @col_info[first_col]
|
3635
|
+
deleted_col = first_col
|
3636
|
+
deleted_col_options = previous_options
|
3637
|
+
|
3638
|
+
@col_info.delete(first_col)
|
3639
|
+
|
3640
|
+
@col_info.keys.sort.each do |col|
|
3641
|
+
col_options = @col_info[col]
|
3642
|
+
|
3643
|
+
# Check if the column number is contiguous with the previous
|
3644
|
+
# column and if the properties are the same.
|
3645
|
+
if (col == last_col + 1) &&
|
3646
|
+
compare_col_info(col_options, previous_options)
|
3647
|
+
last_col = col
|
3648
|
+
else
|
3649
|
+
# If not contiguous/equal then we write out the current range
|
3650
|
+
# of columns and start again.
|
3651
|
+
write_col_info([first_col, last_col, previous_options])
|
3652
|
+
first_col = col
|
3653
|
+
last_col = first_col
|
3654
|
+
previous_options = col_options
|
3655
|
+
end
|
3656
|
+
end
|
3657
|
+
|
3658
|
+
# We will exit the previous loop with one unhandled column range.
|
3659
|
+
write_col_info([first_col, last_col, previous_options])
|
3660
|
+
|
3661
|
+
# Put back the deleted first column information structure:
|
3662
|
+
@col_info[deleted_col] = deleted_col_options
|
3482
3663
|
end
|
3483
3664
|
end
|
3484
3665
|
|
@@ -3490,13 +3671,14 @@ EOS
|
|
3490
3671
|
end
|
3491
3672
|
|
3492
3673
|
def col_info_attributes(args)
|
3493
|
-
min
|
3494
|
-
max
|
3495
|
-
width
|
3496
|
-
format
|
3497
|
-
hidden
|
3498
|
-
level
|
3499
|
-
collapsed = args[
|
3674
|
+
min = args[0] || 0 # First formatted column.
|
3675
|
+
max = args[1] || 0 # Last formatted column.
|
3676
|
+
width = args[2].width # Col width in user units.
|
3677
|
+
format = args[2].format # Format index.
|
3678
|
+
hidden = args[2].hidden || 0 # Hidden flag.
|
3679
|
+
level = args[2].level || 0 # Outline level.
|
3680
|
+
collapsed = args[2].collapsed || 0 # Outline Collapsed
|
3681
|
+
autofit = args[2].autofit || 0 # Best fit for autofit numbers.
|
3500
3682
|
xf_index = format ? format.get_xf_index : 0
|
3501
3683
|
|
3502
3684
|
custom_width = true
|
@@ -3519,10 +3701,11 @@ EOS
|
|
3519
3701
|
['width', width]
|
3520
3702
|
]
|
3521
3703
|
|
3522
|
-
attributes << ['style', xf_index] if xf_index
|
3523
|
-
attributes << ['hidden', 1] if hidden
|
3704
|
+
attributes << ['style', xf_index] if xf_index != 0
|
3705
|
+
attributes << ['hidden', 1] if hidden != 0
|
3706
|
+
attributes << ['bestFit', 1] if autofit != 0
|
3524
3707
|
attributes << ['customWidth', 1] if custom_width
|
3525
|
-
attributes << ['outlineLevel', level] if level
|
3708
|
+
attributes << ['outlineLevel', level] if level != 0
|
3526
3709
|
attributes << ['collapsed', 1] if collapsed != 0
|
3527
3710
|
attributes
|
3528
3711
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: write_xlsx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.11.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Hideo NAKAMURA
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-
|
11
|
+
date: 2023-08-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -130,6 +130,7 @@ files:
|
|
130
130
|
- examples/add_vba_project.rb
|
131
131
|
- examples/array_formula.rb
|
132
132
|
- examples/autofilter.rb
|
133
|
+
- examples/autofit.rb
|
133
134
|
- examples/background.rb
|
134
135
|
- examples/chart_area.rb
|
135
136
|
- examples/chart_bar.rb
|
@@ -275,7 +276,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
275
276
|
- !ruby/object:Gem::Version
|
276
277
|
version: '0'
|
277
278
|
requirements: []
|
278
|
-
rubygems_version: 3.4.
|
279
|
+
rubygems_version: 3.4.10
|
279
280
|
signing_key:
|
280
281
|
specification_version: 4
|
281
282
|
summary: write_xlsx is a gem to create a new file in the Excel 2007+ XLSX format.
|