write_xlsx 1.10.1 → 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 +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
|
|