write_xlsx 1.10.2 → 1.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop.yml +9 -0
- data/Changes +15 -0
- data/examples/autofit.rb +37 -0
- data/examples/chart_radar.rb +3 -9
- data/lib/write_xlsx/chart.rb +1 -1
- data/lib/write_xlsx/format.rb +4 -2
- data/lib/write_xlsx/package/shared_strings.rb +5 -3
- data/lib/write_xlsx/package/styles.rb +16 -17
- data/lib/write_xlsx/package/table.rb +9 -0
- data/lib/write_xlsx/utility.rb +37 -4
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +21 -11
- data/lib/write_xlsx/worksheet/cell_data.rb +13 -5
- data/lib/write_xlsx/worksheet.rb +265 -81
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14a7593970ecc4db14f2accbdc1634033ac9042cdd7680a20d4400ea1eda741f
|
4
|
+
data.tar.gz: 2ec671ba25dc571f612dc5b9d4a9c4ede2e147203d2e085313ea8b4a5f774377
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 255b8f5d60623d6c9966ba1209773129d3312238df315a16564d8c950fa39ac738296a9c788d4cb707abad7e659e9eaef528749fa7f1de7f93a2152e0534fbb4
|
7
|
+
data.tar.gz: c161bd9e8cfe47754f763a874ab83b183f76d7d290ecc53db1fa7a1ea1ec4433ee1d80efda0c139417321f02069db690fc113ab54104b5922b9c942210949e60
|
data/.rubocop.yml
CHANGED
@@ -8,6 +8,9 @@ AllCops:
|
|
8
8
|
TargetRubyVersion: 2.6
|
9
9
|
NewCops: enable
|
10
10
|
|
11
|
+
Gemspec/DevelopmentDependencies:
|
12
|
+
Enabled: false
|
13
|
+
|
11
14
|
Gemspec/RequiredRubyVersion:
|
12
15
|
Enabled: false
|
13
16
|
|
@@ -33,6 +36,9 @@ Layout/HeredocIndentation:
|
|
33
36
|
Layout/LineLength:
|
34
37
|
Max: 7000
|
35
38
|
|
39
|
+
Layout/MultilineMethodCallIndentation:
|
40
|
+
Enabled: false
|
41
|
+
|
36
42
|
Lint/DuplicateBranch:
|
37
43
|
IgnoreLiteralBranches: true
|
38
44
|
Exclude:
|
@@ -60,6 +66,9 @@ Metrics/CyclomaticComplexity:
|
|
60
66
|
Metrics/MethodLength:
|
61
67
|
Max: 400
|
62
68
|
|
69
|
+
Metrics/ModuleLength:
|
70
|
+
Max: 1000
|
71
|
+
|
63
72
|
Metrics/ParameterLists:
|
64
73
|
Max: 12
|
65
74
|
MaxOptionalParameters: 6
|
data/Changes
CHANGED
@@ -1,5 +1,20 @@
|
|
1
1
|
Change history of write_xlsx rubygem.
|
2
2
|
|
3
|
+
2023-05-06 v1.11.0
|
4
|
+
Added support for simulated worksheet `autofit()`.
|
5
|
+
|
6
|
+
Refactored internal column property handling to allow column ranges
|
7
|
+
to be overridden (a common UX expectation).
|
8
|
+
|
9
|
+
Add `quote_prefix` format property.
|
10
|
+
|
11
|
+
Fix for duplicate number formats. Issue #283(excel-write-xlsx)
|
12
|
+
|
13
|
+
Add fix for worksheets with tables and background images.
|
14
|
+
|
15
|
+
Replace/fix the worksheet protection password algorithm
|
16
|
+
so that is works correctly for strings over 24 chars.
|
17
|
+
|
3
18
|
2023-02-16 v1.10.2
|
4
19
|
Fixed issue #104. Worksheet#write Ruby 3.2 removed Object#=~
|
5
20
|
making it impossible to write Date objects
|
data/examples/autofit.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
#
|
5
|
+
# An example of using simulated autofit to automatically adjust the width of
|
6
|
+
# worksheet columns based on the data in the cells.
|
7
|
+
#
|
8
|
+
# Copyright 2000-2023, John McNamara, jmcnamara@cpan.org
|
9
|
+
#
|
10
|
+
# SPDX-License-Identifier: Artistic-1.0-Perl OR GPL-1.0-or-later
|
11
|
+
#
|
12
|
+
# convert to Ruby by Hideo NAKAMURA, nakamura.hideo@gmail.com
|
13
|
+
#
|
14
|
+
require 'write_xlsx'
|
15
|
+
|
16
|
+
workbook = WriteXLSX.new('autofit.xlsx')
|
17
|
+
worksheet = workbook.add_worksheet
|
18
|
+
|
19
|
+
# Write some worksheet data to demonstrate autofitting.
|
20
|
+
worksheet.write(0, 0, "Foo")
|
21
|
+
worksheet.write(1, 0, "Food")
|
22
|
+
worksheet.write(2, 0, "Foody")
|
23
|
+
worksheet.write(3, 0, "Froody")
|
24
|
+
|
25
|
+
worksheet.write(0, 1, 12345)
|
26
|
+
worksheet.write(1, 1, 12345678)
|
27
|
+
worksheet.write(2, 1, 12345)
|
28
|
+
|
29
|
+
worksheet.write(0, 2, "Some longer text")
|
30
|
+
|
31
|
+
worksheet.write(0, 3, 'http://www.google.com')
|
32
|
+
worksheet.write(1, 3, 'https://github.com')
|
33
|
+
|
34
|
+
# Autofit the worksheet
|
35
|
+
worksheet.autofit
|
36
|
+
|
37
|
+
workbook.close
|
data/examples/chart_radar.rb
CHANGED
@@ -44,10 +44,8 @@ chart1.add_series(
|
|
44
44
|
values: ['Sheet1', 1, 6, 2, 2]
|
45
45
|
)
|
46
46
|
|
47
|
-
# Add a chart title
|
47
|
+
# Add a chart title.
|
48
48
|
chart1.set_title(name: 'Results of sample analysis')
|
49
|
-
chart1.set_x_axis(name: 'Test number')
|
50
|
-
chart1.set_y_axis(name: 'Sample length (mm)')
|
51
49
|
|
52
50
|
# Set an Excel chart style. Blue colors with white outline and shadow.
|
53
51
|
chart1.set_style(11)
|
@@ -81,10 +79,8 @@ chart2.add_series(
|
|
81
79
|
values: ['Sheet1', 1, 6, 2, 2]
|
82
80
|
)
|
83
81
|
|
84
|
-
# Add a chart title
|
82
|
+
# Add a chart title.
|
85
83
|
chart2.set_title(name: 'Stacked Chart')
|
86
|
-
chart2.set_x_axis(name: 'Test number')
|
87
|
-
chart2.set_y_axis(name: 'Sample length (mm)')
|
88
84
|
|
89
85
|
# Set an Excel chart style. Blue colors with white outline and shadow.
|
90
86
|
chart2.set_style(12)
|
@@ -118,10 +114,8 @@ chart3.add_series(
|
|
118
114
|
values: ['Sheet1', 1, 6, 2, 2]
|
119
115
|
)
|
120
116
|
|
121
|
-
# Add a chart title
|
117
|
+
# Add a chart title.
|
122
118
|
chart3.set_title(name: 'Percent Stacked Chart')
|
123
|
-
chart3.set_x_axis(name: 'Test number')
|
124
|
-
chart3.set_y_axis(name: 'Sample length (mm)')
|
125
119
|
|
126
120
|
# Set an Excel chart style. Blue colors with white outline and shadow.
|
127
121
|
chart3.set_style(13)
|
data/lib/write_xlsx/chart.rb
CHANGED
@@ -371,7 +371,7 @@ module Writexlsx
|
|
371
371
|
# Set on of the 42 built-in Excel chart styles. The default style is 2.
|
372
372
|
#
|
373
373
|
def set_style(style_id = 2)
|
374
|
-
style_id = 2 if style_id <
|
374
|
+
style_id = 2 if style_id < 1 || style_id > 48
|
375
375
|
@style_id = style_id
|
376
376
|
end
|
377
377
|
|
data/lib/write_xlsx/format.rb
CHANGED
@@ -12,7 +12,7 @@ module Writexlsx
|
|
12
12
|
attr_reader :diag_type, :diag_color, :font_only, :color_indexed # :nodoc:
|
13
13
|
attr_reader :left, :left_color, :right, :right_color, :top, :top_color, :bottom, :bottom_color # :nodoc:
|
14
14
|
attr_reader :font_scheme # :nodoc:
|
15
|
-
attr_accessor :num_format_index, :border_index, :font_index # :nodoc:
|
15
|
+
attr_accessor :quote_prefix, :num_format_index, :border_index, :font_index # :nodoc:
|
16
16
|
attr_accessor :fill_index, :font_condense, :font_extend, :diag_border # :nodoc:
|
17
17
|
attr_accessor :bg_color, :fg_color, :pattern # :nodoc:
|
18
18
|
|
@@ -84,6 +84,7 @@ module Writexlsx
|
|
84
84
|
@just_distrib = 0
|
85
85
|
@color_indexed = 0
|
86
86
|
@font_only = 0
|
87
|
+
@quote_prefix = 0
|
87
88
|
|
88
89
|
set_format_properties(params) unless params.empty?
|
89
90
|
end
|
@@ -213,7 +214,7 @@ module Writexlsx
|
|
213
214
|
# Returns a unique hash key for the Format object.
|
214
215
|
#
|
215
216
|
def get_format_key
|
216
|
-
[get_font_key, get_border_key, get_fill_key, get_alignment_key, @num_format, @locked, @hidden].join(':')
|
217
|
+
[get_font_key, get_border_key, get_fill_key, get_alignment_key, @num_format, @locked, @hidden, @quote_prefix].join(':')
|
217
218
|
end
|
218
219
|
|
219
220
|
#
|
@@ -642,6 +643,7 @@ module Writexlsx
|
|
642
643
|
['borderId', border_index],
|
643
644
|
['xfId', xf_id]
|
644
645
|
]
|
646
|
+
attributes << ['quotePrefix', 1] if ptrue?(quote_prefix)
|
645
647
|
attributes << ['applyNumberFormat', 1] if num_format_index > 0
|
646
648
|
# Add applyFont attribute if XF format uses a font element.
|
647
649
|
attributes << ['applyFont', 1] if font_index > 0 && !ptrue?(@hyperlink)
|
@@ -11,11 +11,14 @@ module Writexlsx
|
|
11
11
|
|
12
12
|
PRESERVE_SPACE_ATTRIBUTES = ['xml:space', 'preserve'].freeze
|
13
13
|
|
14
|
+
attr_reader :strings
|
15
|
+
|
14
16
|
def initialize
|
15
17
|
@writer = Package::XMLWriterSimple.new
|
16
18
|
@strings = [] # string table
|
17
19
|
@strings_index = {} # string table index
|
18
20
|
@count = 0 # count
|
21
|
+
@str_unique = 0
|
19
22
|
end
|
20
23
|
|
21
24
|
def index(string, params = {})
|
@@ -25,10 +28,9 @@ module Writexlsx
|
|
25
28
|
|
26
29
|
def add(string)
|
27
30
|
unless @strings_index[string]
|
28
|
-
# Only first time the string will be append to list
|
29
|
-
# next time we only check and not #dup it
|
30
31
|
str = string.frozen? ? string : string.freeze
|
31
32
|
@strings << str
|
33
|
+
@str_unique += 1
|
32
34
|
@strings_index[str] = @strings.size - 1
|
33
35
|
end
|
34
36
|
@count += 1
|
@@ -128,7 +130,7 @@ module Writexlsx
|
|
128
130
|
end
|
129
131
|
|
130
132
|
def unique_count
|
131
|
-
@
|
133
|
+
@str_unique
|
132
134
|
end
|
133
135
|
end
|
134
136
|
end
|
@@ -14,7 +14,7 @@ module Writexlsx
|
|
14
14
|
@xf_formats = nil
|
15
15
|
@palette = []
|
16
16
|
@font_count = 0
|
17
|
-
@
|
17
|
+
@num_formats = []
|
18
18
|
@border_count = 0
|
19
19
|
@fill_count = 0
|
20
20
|
@custom_colors = []
|
@@ -38,18 +38,18 @@ module Writexlsx
|
|
38
38
|
# Pass in the Format objects and other properties used to set the styles.
|
39
39
|
#
|
40
40
|
def set_style_properties(
|
41
|
-
xf_formats, palette, font_count,
|
41
|
+
xf_formats, palette, font_count, num_formats, border_count,
|
42
42
|
fill_count, custom_colors, dxf_formats, has_comments
|
43
43
|
)
|
44
|
-
@xf_formats
|
45
|
-
@palette
|
46
|
-
@font_count
|
47
|
-
@
|
48
|
-
@border_count
|
49
|
-
@fill_count
|
50
|
-
@custom_colors
|
51
|
-
@dxf_formats
|
52
|
-
@has_comments
|
44
|
+
@xf_formats = xf_formats
|
45
|
+
@palette = palette
|
46
|
+
@font_count = font_count
|
47
|
+
@num_formats = num_formats
|
48
|
+
@border_count = border_count
|
49
|
+
@fill_count = fill_count
|
50
|
+
@custom_colors = custom_colors
|
51
|
+
@dxf_formats = dxf_formats
|
52
|
+
@has_comments = has_comments
|
53
53
|
end
|
54
54
|
|
55
55
|
#
|
@@ -77,7 +77,7 @@ module Writexlsx
|
|
77
77
|
# Write the <numFmts> element.
|
78
78
|
#
|
79
79
|
def write_num_fmts
|
80
|
-
count = @
|
80
|
+
count = @num_formats.size
|
81
81
|
|
82
82
|
return if count == 0
|
83
83
|
|
@@ -85,11 +85,10 @@ module Writexlsx
|
|
85
85
|
|
86
86
|
@writer.tag_elements('numFmts', attributes) do
|
87
87
|
# Write the numFmts elements.
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
write_num_fmt(format.num_format_index, format.num_format)
|
88
|
+
index = 164
|
89
|
+
@num_formats.each do |num_format|
|
90
|
+
write_num_fmt(index, num_format)
|
91
|
+
index += 1
|
93
92
|
end
|
94
93
|
end
|
95
94
|
end
|
@@ -51,6 +51,7 @@ module Writexlsx
|
|
51
51
|
|
52
52
|
add_the_table_columns
|
53
53
|
write_the_cell_data_if_supplied
|
54
|
+
store_filter_cell_positions
|
54
55
|
end
|
55
56
|
|
56
57
|
def set_xml_writer(filename)
|
@@ -155,6 +156,14 @@ module Writexlsx
|
|
155
156
|
end
|
156
157
|
end
|
157
158
|
|
159
|
+
def store_filter_cell_positions
|
160
|
+
if ptrue?(@param[:autofilter])
|
161
|
+
(@col1..@col2).each do |col|
|
162
|
+
@worksheet.filter_cells["#{@row1}:#{col}"] = 1
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
158
167
|
def prepare(id)
|
159
168
|
@id = id
|
160
169
|
@name ||= "Table#{id}"
|
data/lib/write_xlsx/utility.rb
CHANGED
@@ -5,10 +5,28 @@ require 'write_xlsx/col_name'
|
|
5
5
|
|
6
6
|
module Writexlsx
|
7
7
|
module Utility
|
8
|
-
ROW_MAX
|
9
|
-
COL_MAX
|
10
|
-
STR_MAX
|
8
|
+
ROW_MAX = 1048576 # :nodoc:
|
9
|
+
COL_MAX = 16384 # :nodoc:
|
10
|
+
STR_MAX = 32767 # :nodoc:
|
11
11
|
SHEETNAME_MAX = 31 # :nodoc:
|
12
|
+
CHAR_WIDTHS = {
|
13
|
+
' ' => 3, '!' => 5, '"' => 6, '#' => 7, '$' => 7, '%' => 11,
|
14
|
+
'&' => 10, "'" => 3, '(' => 5, ')' => 5, '*' => 7, '+' => 7,
|
15
|
+
',' => 4, '-' => 5, '.' => 4, '/' => 6, '0' => 7, '1' => 7,
|
16
|
+
'2' => 7, '3' => 7, '4' => 7, '5' => 7, '6' => 7, '7' => 7,
|
17
|
+
'8' => 7, '9' => 7, ':' => 4, ';' => 4, '<' => 7, '=' => 7,
|
18
|
+
'>' => 7, '?' => 7, '@' => 13, 'A' => 9, 'B' => 8, 'C' => 8,
|
19
|
+
'D' => 9, 'E' => 7, 'F' => 7, 'G' => 9, 'H' => 9, 'I' => 4,
|
20
|
+
'J' => 5, 'K' => 8, 'L' => 6, 'M' => 12, 'N' => 10, 'O' => 10,
|
21
|
+
'P' => 8, 'Q' => 10, 'R' => 8, 'S' => 7, 'T' => 7, 'U' => 9,
|
22
|
+
'V' => 9, 'W' => 13, 'X' => 8, 'Y' => 7, 'Z' => 7, '[' => 5,
|
23
|
+
'\\' => 6, ']' => 5, '^' => 7, '_' => 7, '`' => 4, 'a' => 7,
|
24
|
+
'b' => 8, 'c' => 6, 'd' => 8, 'e' => 8, 'f' => 5, 'g' => 7,
|
25
|
+
'h' => 8, 'i' => 4, 'j' => 4, 'k' => 7, 'l' => 4, 'm' => 12,
|
26
|
+
'n' => 8, 'o' => 8, 'p' => 8, 'q' => 8, 'r' => 5, 's' => 6,
|
27
|
+
't' => 5, 'u' => 8, 'v' => 7, 'w' => 11, 'x' => 7, 'y' => 7,
|
28
|
+
'z' => 6, '{' => 5, '|' => 7, '}' => 5, '~' => 7
|
29
|
+
}.freeze
|
12
30
|
|
13
31
|
#
|
14
32
|
# xl_rowcol_to_cell($row, col, row_absolute, col_absolute)
|
@@ -84,6 +102,21 @@ module Writexlsx
|
|
84
102
|
"=#{sheetname}!#{range1}:#{range2}"
|
85
103
|
end
|
86
104
|
|
105
|
+
#
|
106
|
+
# xl_string_pixel_width($string)
|
107
|
+
#
|
108
|
+
# Get the pixel width of a string based on individual character widths taken
|
109
|
+
# from Excel. UTF8 characters are given a default width of 8.
|
110
|
+
#
|
111
|
+
# Note, Excel adds an additional 7 pixels padding to a cell.
|
112
|
+
#
|
113
|
+
def xl_string_pixel_width(string)
|
114
|
+
length = 0
|
115
|
+
string.to_s.split(//).each { |char| length += CHAR_WIDTHS[char] || 8 }
|
116
|
+
|
117
|
+
length
|
118
|
+
end
|
119
|
+
|
87
120
|
#
|
88
121
|
# Sheetnames used in references should be quoted if they contain any spaces,
|
89
122
|
# special characters or if the look like something that isn't a sheet name.
|
@@ -258,7 +291,7 @@ module Writexlsx
|
|
258
291
|
|
259
292
|
# Check for a cell reference in A1 notation and substitute row and column
|
260
293
|
def row_col_notation(row_or_a1) # :nodoc:
|
261
|
-
substitute_cellref(row_or_a1) if row_or_a1.to_s =~ /^\D/
|
294
|
+
substitute_cellref(row_or_a1) if row_or_a1.respond_to?(:match) && row_or_a1.to_s =~ /^\D/
|
262
295
|
end
|
263
296
|
|
264
297
|
#
|
data/lib/write_xlsx/version.rb
CHANGED
data/lib/write_xlsx/workbook.rb
CHANGED
@@ -58,7 +58,7 @@ module Writexlsx
|
|
58
58
|
@xf_formats = []
|
59
59
|
@dxf_formats = []
|
60
60
|
@font_count = 0
|
61
|
-
@
|
61
|
+
@num_formats = []
|
62
62
|
@defined_names = []
|
63
63
|
@named_ranges = []
|
64
64
|
@custom_colors = []
|
@@ -560,7 +560,7 @@ module Writexlsx
|
|
560
560
|
@xf_formats,
|
561
561
|
@palette,
|
562
562
|
@font_count,
|
563
|
-
@
|
563
|
+
@num_formats,
|
564
564
|
@border_count,
|
565
565
|
@fill_count,
|
566
566
|
@custom_colors,
|
@@ -869,6 +869,9 @@ module Writexlsx
|
|
869
869
|
@activesheet = @worksheets.visible_first.index if @activesheet == 0
|
870
870
|
@worksheets[@activesheet].activate
|
871
871
|
|
872
|
+
# Convert the SST strings data structure.
|
873
|
+
prepare_sst_string_data
|
874
|
+
|
872
875
|
# Prepare the worksheet VML elements such as comments and buttons.
|
873
876
|
prepare_vml_objects
|
874
877
|
# Set the defined names for the worksheets such as Print Titles.
|
@@ -917,6 +920,11 @@ module Writexlsx
|
|
917
920
|
Dir.glob(File.join(tempdir, "**", "*"), File::FNM_DOTMATCH).select { |f| File.file?(f) }
|
918
921
|
end
|
919
922
|
|
923
|
+
#
|
924
|
+
# prepare_sst_string_data
|
925
|
+
#
|
926
|
+
def prepare_sst_string_data; end
|
927
|
+
|
920
928
|
#
|
921
929
|
# Prepare all of the format properties prior to passing them to Styles.rb.
|
922
930
|
#
|
@@ -977,9 +985,10 @@ module Writexlsx
|
|
977
985
|
# User defined records start from index 0xA4.
|
978
986
|
#
|
979
987
|
def prepare_num_formats # :nodoc:
|
980
|
-
num_formats
|
981
|
-
|
982
|
-
|
988
|
+
num_formats = []
|
989
|
+
unique_num_formats = {}
|
990
|
+
index = 164
|
991
|
+
num_format_count = 0
|
983
992
|
|
984
993
|
(@xf_formats + @dxf_formats).each do |format|
|
985
994
|
num_format = format.num_format
|
@@ -1000,21 +1009,22 @@ module Writexlsx
|
|
1000
1009
|
next
|
1001
1010
|
end
|
1002
1011
|
|
1003
|
-
if
|
1012
|
+
if unique_num_formats[num_format]
|
1004
1013
|
# Number format has already been used.
|
1005
|
-
format.num_format_index =
|
1014
|
+
format.num_format_index = unique_num_formats[num_format]
|
1006
1015
|
else
|
1007
1016
|
# Add a new number format.
|
1008
|
-
|
1017
|
+
unique_num_formats[num_format] = index
|
1009
1018
|
format.num_format_index = index
|
1010
1019
|
index += 1
|
1011
1020
|
|
1012
|
-
# Only increase
|
1013
|
-
|
1021
|
+
# Only store/increase number format count for XF formats
|
1022
|
+
# (not for DXF formats).
|
1023
|
+
num_formats << num_format if ptrue?(format.xf_index)
|
1014
1024
|
end
|
1015
1025
|
end
|
1016
1026
|
|
1017
|
-
@
|
1027
|
+
@num_formats = num_formats
|
1018
1028
|
end
|
1019
1029
|
|
1020
1030
|
#
|
@@ -1,5 +1,6 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
|
2
|
+
|
3
|
+
# frozen__literal: true
|
3
4
|
|
4
5
|
module Writexlsx
|
5
6
|
class Worksheet
|
@@ -24,8 +25,8 @@ module Writexlsx
|
|
24
25
|
elsif worksheet.set_rows[row] && worksheet.set_rows[row][1]
|
25
26
|
row_xf = worksheet.set_rows[row][1]
|
26
27
|
attributes << ['s', row_xf.get_xf_index]
|
27
|
-
elsif worksheet.
|
28
|
-
col_xf = worksheet.
|
28
|
+
elsif worksheet.col_info[col] && worksheet.col_info[col].format
|
29
|
+
col_xf = worksheet.col_info[col].format
|
29
30
|
attributes << ['s', col_xf.get_xf_index]
|
30
31
|
end
|
31
32
|
attributes
|
@@ -56,11 +57,12 @@ module Writexlsx
|
|
56
57
|
end
|
57
58
|
|
58
59
|
class StringCellData < CellData # :nodoc:
|
59
|
-
attr_reader :token
|
60
|
+
attr_reader :token, :raw_string
|
60
61
|
|
61
|
-
def initialize(index, xf)
|
62
|
+
def initialize(index, xf, raw_string)
|
62
63
|
@token = index
|
63
64
|
@xf = xf
|
65
|
+
@raw_string = raw_string
|
64
66
|
end
|
65
67
|
|
66
68
|
def data
|
@@ -81,6 +83,12 @@ module Writexlsx
|
|
81
83
|
end
|
82
84
|
end
|
83
85
|
|
86
|
+
class RichStringCellData < StringCellData # :nodoc:
|
87
|
+
end
|
88
|
+
|
89
|
+
class DateTimeCellData < NumberCellData # :nodoc:
|
90
|
+
end
|
91
|
+
|
84
92
|
class FormulaCellData < CellData # :nodoc:
|
85
93
|
attr_reader :token, :result, :range, :link_type, :url
|
86
94
|
|
data/lib/write_xlsx/worksheet.rb
CHANGED
@@ -31,20 +31,25 @@ module Writexlsx
|
|
31
31
|
attr_reader :vml_data_id # :nodoc:
|
32
32
|
attr_reader :vml_header_id # :nodoc:
|
33
33
|
attr_reader :autofilter_area # :nodoc:
|
34
|
-
attr_reader :writer, :set_rows, :
|
34
|
+
attr_reader :writer, :set_rows, :col_info # :nodoc:
|
35
35
|
attr_reader :vml_shape_id # :nodoc:
|
36
36
|
attr_reader :comments, :comments_author # :nodoc:
|
37
37
|
attr_accessor :data_bars_2010, :dxf_priority # :nodoc:
|
38
38
|
attr_reader :vba_codename # :nodoc:
|
39
|
-
attr_writer :excel_version
|
39
|
+
attr_writer :excel_version # :nodoc:
|
40
|
+
attr_reader :filter_cells # :nodoc:
|
40
41
|
|
41
42
|
def initialize(workbook, index, name) # :nodoc:
|
43
|
+
rowmax = 1_048_576
|
44
|
+
colmax = 16_384
|
45
|
+
strmax = 32_767
|
46
|
+
|
42
47
|
@writer = Package::XMLWriterSimple.new
|
43
48
|
|
44
49
|
@workbook = workbook
|
45
50
|
@index = index
|
46
51
|
@name = name
|
47
|
-
@
|
52
|
+
@col_info = {}
|
48
53
|
@cell_data_table = []
|
49
54
|
@excel_version = 2007
|
50
55
|
@palette = workbook.palette
|
@@ -55,6 +60,10 @@ module Writexlsx
|
|
55
60
|
|
56
61
|
@screen_gridlines = true
|
57
62
|
@show_zeros = true
|
63
|
+
|
64
|
+
@xls_rowmax = rowmax
|
65
|
+
@xls_colmax = colmax
|
66
|
+
@xls_strmax = strmax
|
58
67
|
@dim_rowmin = nil
|
59
68
|
@dim_rowmax = nil
|
60
69
|
@dim_colmin = nil
|
@@ -77,11 +86,10 @@ module Writexlsx
|
|
77
86
|
@filter_on = false
|
78
87
|
@filter_range = []
|
79
88
|
@filter_cols = {}
|
89
|
+
@filter_cells = {}
|
80
90
|
@filter_type = {}
|
81
91
|
|
82
|
-
@col_sizes = {}
|
83
92
|
@row_sizes = {}
|
84
|
-
@col_formats = {}
|
85
93
|
|
86
94
|
@last_shape_id = 1
|
87
95
|
@rel_count = 0
|
@@ -90,8 +98,8 @@ module Writexlsx
|
|
90
98
|
@external_drawing_links = []
|
91
99
|
@external_comment_links = []
|
92
100
|
@external_vml_links = []
|
93
|
-
@external_table_links = []
|
94
101
|
@external_background_links = []
|
102
|
+
@external_table_links = []
|
95
103
|
@drawing_links = []
|
96
104
|
@vml_drawing_links = []
|
97
105
|
@charts = []
|
@@ -121,6 +129,7 @@ module Writexlsx
|
|
121
129
|
@default_col_width = 8.43
|
122
130
|
@default_col_pixels = 64
|
123
131
|
@default_row_rezoed = 0
|
132
|
+
@default_date_pixels = 68
|
124
133
|
|
125
134
|
@merge = []
|
126
135
|
|
@@ -305,7 +314,8 @@ module Writexlsx
|
|
305
314
|
#
|
306
315
|
def set_column(*args)
|
307
316
|
# Check for a cell reference in A1 notation and substitute row and column
|
308
|
-
|
317
|
+
# ruby 3.2 no longer handles =~ for various types
|
318
|
+
if args[0].respond_to?(:=~) && args[0].to_s =~ /^\D/
|
309
319
|
_row1, firstcol, _row2, lastcol, *data = substitute_cellref(*args)
|
310
320
|
else
|
311
321
|
firstcol, lastcol, *data = args
|
@@ -321,6 +331,7 @@ module Writexlsx
|
|
321
331
|
firstcol, lastcol = lastcol, firstcol if firstcol > lastcol
|
322
332
|
|
323
333
|
width, format, hidden, level, collapsed = data
|
334
|
+
autofit = 0
|
324
335
|
|
325
336
|
# Check that cols are valid and store max and min values with default row.
|
326
337
|
# NOTE: The check shouldn't modify the row dimensions and should only modify
|
@@ -338,22 +349,20 @@ module Writexlsx
|
|
338
349
|
level = 0 if level < 0
|
339
350
|
level = 7 if level > 7
|
340
351
|
|
352
|
+
# Excel has a maximum column width of 255 characters.
|
353
|
+
width = 255.0 if width && width > 255.0
|
354
|
+
|
341
355
|
@outline_col_level = level if level > @outline_col_level
|
342
356
|
|
343
357
|
# Store the column data based on the first column. Padded for sorting.
|
344
|
-
|
358
|
+
(firstcol..lastcol).each do |col|
|
359
|
+
@col_info[col] =
|
360
|
+
Struct.new('ColInfo', :width, :format, :hidden, :level, :collapsed, :autofit)
|
361
|
+
.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,113 @@ 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
|
+
Struct.new('ColInfo', :width, :format, :hidden, :level, :collapsed, :autofit)
|
501
|
+
.new(width, nil, 0, 0, 0, 1)
|
502
|
+
end
|
503
|
+
end
|
504
|
+
end
|
505
|
+
|
390
506
|
#
|
391
507
|
# :call-seq:
|
392
508
|
# set_selection(cell_or_cell_range)
|
@@ -936,31 +1052,35 @@ module Writexlsx
|
|
936
1052
|
write_row(_row, _col, _token, _format, _value1, _value2)
|
937
1053
|
elsif _token.respond_to?(:coerce) # Numeric
|
938
1054
|
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
|
-
|
1055
|
+
elsif _token.respond_to?(:=~) # String
|
1056
|
+
# Match integer with leading zero(s)
|
1057
|
+
if @leading_zeros && _token =~ /^0\d*$/
|
1058
|
+
write_string(_row, _col, _token, _format)
|
1059
|
+
elsif _token =~ /\A([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?\Z/
|
1060
|
+
write_number(_row, _col, _token, _format)
|
1061
|
+
# Match formula
|
1062
|
+
elsif _token =~ /^=/
|
1063
|
+
write_formula(_row, _col, _token, _format, _value1)
|
1064
|
+
# Match array formula
|
1065
|
+
elsif _token =~ /^\{=.*\}$/
|
1066
|
+
write_formula(_row, _col, _token, _format, _value1)
|
1067
|
+
# Match blank
|
1068
|
+
elsif _token == ''
|
1069
|
+
# row_col_args.delete_at(2) # remove the empty string from the parameter list
|
1070
|
+
write_blank(_row, _col, _format)
|
1071
|
+
elsif @workbook.strings_to_urls
|
1072
|
+
# Match http, https or ftp URL
|
1073
|
+
if _token =~ %r{\A[fh]tt?ps?://}
|
1074
|
+
write_url(_row, _col, _token, _format, _value1, _value2)
|
1075
|
+
# Match mailto:
|
1076
|
+
elsif _token =~ /\Amailto:/
|
1077
|
+
write_url(_row, _col, _token, _format, _value1, _value2)
|
1078
|
+
# Match internal or external sheet link
|
1079
|
+
elsif _token =~ /\A(?:in|ex)ternal:/
|
1080
|
+
write_url(_row, _col, _token, _format, _value1, _value2)
|
1081
|
+
else
|
1082
|
+
write_string(_row, _col, _token, _format)
|
1083
|
+
end
|
964
1084
|
else
|
965
1085
|
write_string(_row, _col, _token, _format)
|
966
1086
|
end
|
@@ -1114,7 +1234,7 @@ module Writexlsx
|
|
1114
1234
|
|
1115
1235
|
index = shared_string_index(_string.length > STR_MAX ? _string[0, STR_MAX] : _string)
|
1116
1236
|
|
1117
|
-
store_data_to_table(StringCellData.new(index, _format), _row, _col)
|
1237
|
+
store_data_to_table(StringCellData.new(index, _format, _string), _row, _col)
|
1118
1238
|
end
|
1119
1239
|
|
1120
1240
|
#
|
@@ -1143,13 +1263,16 @@ module Writexlsx
|
|
1143
1263
|
check_dimensions(_row, _col)
|
1144
1264
|
store_row_col_max_min_values(_row, _col)
|
1145
1265
|
|
1146
|
-
_fragments,
|
1266
|
+
_fragments, _raw_string = rich_strings_fragments(_rich_strings)
|
1147
1267
|
# can't allow 2 formats in a row
|
1148
1268
|
return -4 unless _fragments
|
1149
1269
|
|
1270
|
+
# Check that the string si < 32767 chars.
|
1271
|
+
return 3 if _raw_string.size > @xls_strmax
|
1272
|
+
|
1150
1273
|
index = shared_string_index(xml_str_of_rich_string(_fragments))
|
1151
1274
|
|
1152
|
-
store_data_to_table(
|
1275
|
+
store_data_to_table(RichStringCellData.new(index, _xf, _raw_string), _row, _col)
|
1153
1276
|
end
|
1154
1277
|
|
1155
1278
|
#
|
@@ -1679,7 +1802,7 @@ module Writexlsx
|
|
1679
1802
|
date_time = convert_date_time(_str)
|
1680
1803
|
|
1681
1804
|
if date_time
|
1682
|
-
store_data_to_table(
|
1805
|
+
store_data_to_table(DateTimeCellData.new(date_time, _format), _row, _col)
|
1683
1806
|
else
|
1684
1807
|
# If the date isn't valid then write it as a string.
|
1685
1808
|
write_string(_row, _col, _str, _format)
|
@@ -2164,6 +2287,11 @@ module Writexlsx
|
|
2164
2287
|
@autofilter_area = convert_name_area(_row1, _col1, _row2, _col2)
|
2165
2288
|
@autofilter_ref = xl_range(_row1, _row2, _col1, _col2)
|
2166
2289
|
@filter_range = [_col1, _col2]
|
2290
|
+
|
2291
|
+
# Store the filter cell positions for use in the autofit calculation.
|
2292
|
+
(_col1.._col2).each do |col|
|
2293
|
+
@filter_cells["#{_row1}:#{col}"] = 1
|
2294
|
+
end
|
2167
2295
|
end
|
2168
2296
|
|
2169
2297
|
#
|
@@ -2506,8 +2634,8 @@ module Writexlsx
|
|
2506
2634
|
@external_hyper_links,
|
2507
2635
|
@external_drawing_links,
|
2508
2636
|
@external_vml_links,
|
2509
|
-
@external_table_links,
|
2510
2637
|
@external_background_links,
|
2638
|
+
@external_table_links,
|
2511
2639
|
@external_comment_links
|
2512
2640
|
].reject { |a| a.empty? }
|
2513
2641
|
end
|
@@ -2634,6 +2762,33 @@ module Writexlsx
|
|
2634
2762
|
|
2635
2763
|
private
|
2636
2764
|
|
2765
|
+
#
|
2766
|
+
# Compare adjacent column information structures.
|
2767
|
+
#
|
2768
|
+
def compare_col_info(col_options, previous_options)
|
2769
|
+
if !col_options.width.nil? != !previous_options.width.nil?
|
2770
|
+
return nil
|
2771
|
+
end
|
2772
|
+
if col_options.width && previous_options.width &&
|
2773
|
+
col_options.width != previous_options.width
|
2774
|
+
return nil
|
2775
|
+
end
|
2776
|
+
|
2777
|
+
if !col_options.format.nil? != !previous_options.format.nil?
|
2778
|
+
return nil
|
2779
|
+
end
|
2780
|
+
if col_options.format && previous_options.format &&
|
2781
|
+
col_options.format != previous_options.format
|
2782
|
+
return nil
|
2783
|
+
end
|
2784
|
+
|
2785
|
+
return nil if col_options.hidden != previous_options.hidden
|
2786
|
+
return nil if col_options.level != previous_options.level
|
2787
|
+
return nil if col_options.collapsed != previous_options.collapsed
|
2788
|
+
|
2789
|
+
true
|
2790
|
+
end
|
2791
|
+
|
2637
2792
|
#
|
2638
2793
|
# Get the index used to address a drawing rel link.
|
2639
2794
|
#
|
@@ -2685,9 +2840,9 @@ module Writexlsx
|
|
2685
2840
|
# Create a temp format with the default font for unformatted fragments.
|
2686
2841
|
default = Format.new(0)
|
2687
2842
|
|
2688
|
-
length = 0 # String length.
|
2689
2843
|
last = 'format'
|
2690
2844
|
pos = 0
|
2845
|
+
raw_string = ''
|
2691
2846
|
|
2692
2847
|
fragments = []
|
2693
2848
|
rich_strings.each do |token|
|
@@ -2708,12 +2863,12 @@ module Writexlsx
|
|
2708
2863
|
fragments << default << token
|
2709
2864
|
end
|
2710
2865
|
|
2711
|
-
|
2866
|
+
raw_string += token # Keep track of actual string length.
|
2712
2867
|
last = 'string'
|
2713
2868
|
end
|
2714
2869
|
pos += 1
|
2715
2870
|
end
|
2716
|
-
[fragments,
|
2871
|
+
[fragments, raw_string]
|
2717
2872
|
end
|
2718
2873
|
|
2719
2874
|
def xml_str_of_rich_string(fragments)
|
@@ -2944,8 +3099,9 @@ module Writexlsx
|
|
2944
3099
|
#
|
2945
3100
|
def size_col(col, anchor = 0) # :nodoc:
|
2946
3101
|
# Look up the cell value to see if it has been changed.
|
2947
|
-
if @
|
2948
|
-
width
|
3102
|
+
if @col_info[col]
|
3103
|
+
width = @col_info[col].width || @default_col_width
|
3104
|
+
hidden = @col_info[col].hidden
|
2949
3105
|
|
2950
3106
|
# Convert to pixels.
|
2951
3107
|
pixels = if hidden == 1 && anchor != 4
|
@@ -3276,28 +3432,22 @@ EOS
|
|
3276
3432
|
end
|
3277
3433
|
|
3278
3434
|
#
|
3279
|
-
# Based on the algorithm
|
3280
|
-
#
|
3435
|
+
# Hash a worksheet password. Based on the algorithm in ECMA-376-4:2016,
|
3436
|
+
# Office Open XML File Foemats -- Transitional Migration Features,
|
3437
|
+
# Additional attributes for workbookProtection element (Part 1, §18.2.29). #
|
3281
3438
|
def encode_password(password) # :nodoc:
|
3282
|
-
|
3283
|
-
chars = password.split(//)
|
3284
|
-
count = chars.size
|
3439
|
+
hash = 0
|
3285
3440
|
|
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
|
3441
|
+
password.reverse.split(//).each do |char|
|
3442
|
+
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff)
|
3443
|
+
hash ^= char.ord
|
3293
3444
|
end
|
3294
3445
|
|
3295
|
-
|
3296
|
-
|
3297
|
-
|
3298
|
-
encoded_password ^= 0xCE4B
|
3446
|
+
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff)
|
3447
|
+
hash ^= password.length
|
3448
|
+
hash ^= 0xCE4B
|
3299
3449
|
|
3300
|
-
sprintf("%X",
|
3450
|
+
sprintf("%X", hash)
|
3301
3451
|
end
|
3302
3452
|
|
3303
3453
|
#
|
@@ -3475,10 +3625,42 @@ EOS
|
|
3475
3625
|
#
|
3476
3626
|
def write_cols # :nodoc:
|
3477
3627
|
# Exit unless some column have been formatted.
|
3478
|
-
return if @
|
3628
|
+
return if @col_info.empty?
|
3479
3629
|
|
3480
3630
|
@writer.tag_elements('cols') do
|
3481
|
-
|
3631
|
+
# Use the first element of the column informatin structure to set
|
3632
|
+
# the initial/previous properties.
|
3633
|
+
first_col = @col_info.keys.min
|
3634
|
+
last_col = first_col
|
3635
|
+
previous_options = @col_info[first_col]
|
3636
|
+
deleted_col = first_col
|
3637
|
+
deleted_col_options = previous_options
|
3638
|
+
|
3639
|
+
@col_info.delete(first_col)
|
3640
|
+
|
3641
|
+
@col_info.keys.sort.each do |col|
|
3642
|
+
col_options = @col_info[col]
|
3643
|
+
|
3644
|
+
# Check if the column number is contiguous with the previous
|
3645
|
+
# column and if the properties are the same.
|
3646
|
+
if (col == last_col + 1) &&
|
3647
|
+
compare_col_info(col_options, previous_options)
|
3648
|
+
last_col = col
|
3649
|
+
else
|
3650
|
+
# If not contiguous/equal then we write out the current range
|
3651
|
+
# of columns and start again.
|
3652
|
+
write_col_info([first_col, last_col, previous_options])
|
3653
|
+
first_col = col
|
3654
|
+
last_col = first_col
|
3655
|
+
previous_options = col_options
|
3656
|
+
end
|
3657
|
+
end
|
3658
|
+
|
3659
|
+
# We will exit the previous loop with one unhandled column range.
|
3660
|
+
write_col_info([first_col, last_col, previous_options])
|
3661
|
+
|
3662
|
+
# Put back the deleted first column information structure:
|
3663
|
+
@col_info[deleted_col] = deleted_col_options
|
3482
3664
|
end
|
3483
3665
|
end
|
3484
3666
|
|
@@ -3490,13 +3672,14 @@ EOS
|
|
3490
3672
|
end
|
3491
3673
|
|
3492
3674
|
def col_info_attributes(args)
|
3493
|
-
min
|
3494
|
-
max
|
3495
|
-
width
|
3496
|
-
format
|
3497
|
-
hidden
|
3498
|
-
level
|
3499
|
-
collapsed = args[
|
3675
|
+
min = args[0] || 0 # First formatted column.
|
3676
|
+
max = args[1] || 0 # Last formatted column.
|
3677
|
+
width = args[2].width # Col width in user units.
|
3678
|
+
format = args[2].format # Format index.
|
3679
|
+
hidden = args[2].hidden || 0 # Hidden flag.
|
3680
|
+
level = args[2].level || 0 # Outline level.
|
3681
|
+
collapsed = args[2].collapsed || 0 # Outline Collapsed
|
3682
|
+
autofit = args[2].autofit || 0 # Best fit for autofit numbers.
|
3500
3683
|
xf_index = format ? format.get_xf_index : 0
|
3501
3684
|
|
3502
3685
|
custom_width = true
|
@@ -3519,10 +3702,11 @@ EOS
|
|
3519
3702
|
['width', width]
|
3520
3703
|
]
|
3521
3704
|
|
3522
|
-
attributes << ['style', xf_index] if xf_index
|
3523
|
-
attributes << ['hidden', 1] if hidden
|
3705
|
+
attributes << ['style', xf_index] if xf_index != 0
|
3706
|
+
attributes << ['hidden', 1] if hidden != 0
|
3707
|
+
attributes << ['bestFit', 1] if autofit != 0
|
3524
3708
|
attributes << ['customWidth', 1] if custom_width
|
3525
|
-
attributes << ['outlineLevel', level] if level
|
3709
|
+
attributes << ['outlineLevel', level] if level != 0
|
3526
3710
|
attributes << ['collapsed', 1] if collapsed != 0
|
3527
3711
|
attributes
|
3528
3712
|
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.0
|
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-05-06 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.
|