write_xlsx 1.10.1 → 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 +15 -0
- data/Changes +21 -0
- data/README.md +1 -1
- 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/conditional_format.rb +15 -4
- 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 +34 -16
- data/lib/write_xlsx/utility.rb +45 -11
- 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/data_validation.rb +13 -1
- data/lib/write_xlsx/worksheet.rb +702 -278
- 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,11 +36,17 @@ 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:
|
39
45
|
- 'lib/write_xlsx/worksheet.rb'
|
40
46
|
|
47
|
+
Lint/UnderscorePrefixedVariableName:
|
48
|
+
Enabled: false
|
49
|
+
|
41
50
|
Lint/UselessSetterCall:
|
42
51
|
Exclude:
|
43
52
|
- 'lib/write_xlsx/worksheet.rb'
|
@@ -57,6 +66,9 @@ Metrics/CyclomaticComplexity:
|
|
57
66
|
Metrics/MethodLength:
|
58
67
|
Max: 400
|
59
68
|
|
69
|
+
Metrics/ModuleLength:
|
70
|
+
Max: 1000
|
71
|
+
|
60
72
|
Metrics/ParameterLists:
|
61
73
|
Max: 12
|
62
74
|
MaxOptionalParameters: 6
|
@@ -93,6 +105,9 @@ Style/HashSyntax:
|
|
93
105
|
EnforceStyle: ruby19_no_mixed_keys
|
94
106
|
EnforcedShorthandSyntax: either
|
95
107
|
|
108
|
+
Style/IfUnlessModifier:
|
109
|
+
Enabled: false
|
110
|
+
|
96
111
|
Style/NumericLiterals:
|
97
112
|
MinDigits: 10
|
98
113
|
|
data/Changes
CHANGED
@@ -1,5 +1,26 @@
|
|
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
|
+
|
18
|
+
2023-02-16 v1.10.2
|
19
|
+
Fixed issue #104. Worksheet#write Ruby 3.2 removed Object#=~
|
20
|
+
making it impossible to write Date objects
|
21
|
+
|
22
|
+
Memory usage optimization.
|
23
|
+
|
3
24
|
2023-01-31 v1.10.1
|
4
25
|
Fixed PR #99. Remove range [1..] style to work on Ruby 2.5.
|
5
26
|
|
data/README.md
CHANGED
@@ -85,7 +85,7 @@ the first worksheet in an Excel XML spreadsheet called ruby.xlsx:
|
|
85
85
|
Original Perl module was written by John McNamara(jmcnamara@cpan.org).
|
86
86
|
|
87
87
|
Converted to ruby by Hideo NAKAMURA(nakamrua.hideo@gmail.com)
|
88
|
-
Copyright (c) 2012-
|
88
|
+
Copyright (c) 2012-2023 Hideo NAKAMURA.
|
89
89
|
|
90
90
|
See LICENSE.txt for further details.
|
91
91
|
|
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)
|
@@ -409,12 +409,23 @@ module Writexlsx
|
|
409
409
|
|
410
410
|
def row_col_param_for_conditional_formatting(*args)
|
411
411
|
# Check for a cell reference in A1 notation and substitute row and column
|
412
|
-
if args[0].to_s =~ (/^\D/) && (args[0] =~ /,/)
|
413
|
-
|
414
|
-
|
412
|
+
user_range = if args[0].to_s =~ (/^\D/) && (args[0] =~ /,/)
|
413
|
+
# Check for a user defined multiple range like B3:K6,B8:K11.
|
414
|
+
args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub(/\$/, '')
|
415
|
+
end
|
416
|
+
|
417
|
+
if (row_col_array = row_col_notation(args.first))
|
418
|
+
if row_col_array.size == 2
|
419
|
+
row1, col1 = row_col_array
|
420
|
+
row2 = args[1]
|
421
|
+
elsif row_col_array.size == 4
|
422
|
+
row1, col1, row2, col2 = row_col_array
|
423
|
+
param = args[1]
|
424
|
+
end
|
425
|
+
else
|
426
|
+
row1, col1, row2, col2, param = args
|
415
427
|
end
|
416
428
|
|
417
|
-
row1, col1, row2, col2, param = row_col_notation(args)
|
418
429
|
if row2.respond_to?(:keys)
|
419
430
|
param = row2
|
420
431
|
row2 = row1
|
@@ -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}"
|
@@ -162,41 +171,50 @@ module Writexlsx
|
|
162
171
|
|
163
172
|
private
|
164
173
|
|
165
|
-
def handle_args(
|
174
|
+
def handle_args(row1, col1 = nil, row2 = nil, col2 = nil, param = nil)
|
166
175
|
# Check for a cell reference in A1 notation and substitute row and column
|
167
|
-
|
176
|
+
if (row_col_array = row_col_notation(row1))
|
177
|
+
_row1, _col1, _row2, _col2 = row_col_array
|
178
|
+
_param = col1
|
179
|
+
else
|
180
|
+
_row1 = row1
|
181
|
+
_col1 = col1
|
182
|
+
_row2 = row2
|
183
|
+
_col2 = col2
|
184
|
+
_param = param
|
185
|
+
end
|
168
186
|
|
169
187
|
# Check for a valid number of args.
|
170
|
-
raise "Not enough parameters to add_table()" if [
|
188
|
+
raise "Not enough parameters to add_table()" if [_row1, _col1, _row2, _col2].include?(nil)
|
171
189
|
|
172
190
|
# Check that row and col are valid without storing the values.
|
173
|
-
check_dimensions_and_update_max_min_values(
|
174
|
-
check_dimensions_and_update_max_min_values(
|
191
|
+
check_dimensions_and_update_max_min_values(_row1, _col1, 1, 1)
|
192
|
+
check_dimensions_and_update_max_min_values(_row2, _col2, 1, 1)
|
175
193
|
|
176
194
|
# Swap last row/col for first row/col as necessary.
|
177
|
-
|
178
|
-
|
195
|
+
_row1, _row2 = _row2, _row1 if _row1 > _row2
|
196
|
+
_col1, _col2 = _col2, _col1 if _col1 > _col2
|
179
197
|
|
180
198
|
# The final hash contains the validation parameters.
|
181
|
-
|
199
|
+
_param ||= {}
|
182
200
|
|
183
201
|
# Turn on Excel's defaults.
|
184
|
-
|
185
|
-
|
186
|
-
|
202
|
+
_param[:banded_rows] ||= 1
|
203
|
+
_param[:header_row] ||= 1
|
204
|
+
_param[:autofilter] ||= 1
|
187
205
|
|
188
206
|
# Check that there are enough rows.
|
189
|
-
num_rows =
|
190
|
-
num_rows -= 1 if ptrue?(
|
207
|
+
num_rows = _row2 - _row1
|
208
|
+
num_rows -= 1 if ptrue?(_param[:header_row])
|
191
209
|
|
192
210
|
raise "Must have at least one data row in in add_table()" if num_rows < 0
|
193
211
|
|
194
212
|
# If the header row if off the default is to turn autofilter off.
|
195
|
-
|
213
|
+
_param[:autofilter] = 0 if _param[:header_row] == 0
|
196
214
|
|
197
|
-
check_parameter(
|
215
|
+
check_parameter(_param, valid_table_parameter, 'add_table')
|
198
216
|
|
199
|
-
[
|
217
|
+
[_row1, _row2, _col1, _col2, _param]
|
200
218
|
end
|
201
219
|
|
202
220
|
# List of valid input parameters.
|
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)
|
@@ -53,7 +71,12 @@ module Writexlsx
|
|
53
71
|
|
54
72
|
def xl_col_to_name(col, col_absolute)
|
55
73
|
col_str = ColName.instance.col_str(col)
|
56
|
-
|
74
|
+
if col_absolute
|
75
|
+
"#{absolute_char(col_absolute)}#{col_str}"
|
76
|
+
else
|
77
|
+
# Do not allocate new string
|
78
|
+
col_str
|
79
|
+
end
|
57
80
|
end
|
58
81
|
|
59
82
|
def xl_range(row_1, row_2, col_1, col_2,
|
@@ -79,6 +102,21 @@ module Writexlsx
|
|
79
102
|
"=#{sheetname}!#{range1}:#{range2}"
|
80
103
|
end
|
81
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
|
+
|
82
120
|
#
|
83
121
|
# Sheetnames used in references should be quoted if they contain any spaces,
|
84
122
|
# special characters or if the look like something that isn't a sheet name.
|
@@ -252,12 +290,8 @@ module Writexlsx
|
|
252
290
|
end
|
253
291
|
|
254
292
|
# Check for a cell reference in A1 notation and substitute row and column
|
255
|
-
def row_col_notation(
|
256
|
-
if
|
257
|
-
substitute_cellref(*args)
|
258
|
-
else
|
259
|
-
args
|
260
|
-
end
|
293
|
+
def row_col_notation(row_or_a1) # :nodoc:
|
294
|
+
substitute_cellref(row_or_a1) if row_or_a1.respond_to?(:match) && row_or_a1.to_s =~ /^\D/
|
261
295
|
end
|
262
296
|
|
263
297
|
#
|
@@ -267,7 +301,7 @@ module Writexlsx
|
|
267
301
|
# Ex: ("A4", "Hello") is converted to (3, 0, "Hello").
|
268
302
|
#
|
269
303
|
def substitute_cellref(cell, *args) # :nodoc:
|
270
|
-
return [*args] if cell.respond_to?(:coerce) # Numeric
|
304
|
+
# return [*args] if cell.respond_to?(:coerce) # Numeric
|
271
305
|
|
272
306
|
normalized_cell = cell.upcase
|
273
307
|
|
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
|
|