write_xlsx 1.10.2 → 1.11.1
Sign up to get free protection for your applications and to get access to all the features.
- 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.
|