write_xlsx 1.10.2 → 1.11.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/.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.
|