write_xlsx 1.11.1 → 1.11.2
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Changes +9 -0
- data/examples/shape_all.rb +1 -1
- data/lib/write_xlsx/chart/pie.rb +14 -2
- data/lib/write_xlsx/chart/series.rb +48 -0
- data/lib/write_xlsx/chart.rb +65 -12
- data/lib/write_xlsx/chartsheet.rb +10 -1
- data/lib/write_xlsx/col_name.rb +7 -3
- data/lib/write_xlsx/format.rb +1 -1
- data/lib/write_xlsx/package/app.rb +9 -5
- data/lib/write_xlsx/package/conditional_format.rb +2 -2
- data/lib/write_xlsx/package/packager.rb +2 -3
- data/lib/write_xlsx/package/table.rb +74 -20
- data/lib/write_xlsx/package/xml_writer_simple.rb +32 -44
- data/lib/write_xlsx/sheets.rb +6 -2
- data/lib/write_xlsx/sparkline.rb +2 -2
- data/lib/write_xlsx/utility.rb +11 -9
- data/lib/write_xlsx/version.rb +1 -1
- data/lib/write_xlsx/workbook.rb +2 -2
- data/lib/write_xlsx/worksheet/cell_data.rb +16 -16
- data/lib/write_xlsx/worksheet/hyperlink.rb +2 -2
- data/lib/write_xlsx/worksheet.rb +87 -35
- data/write_xlsx.gemspec +2 -0
- metadata +31 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9dae4b31e210af6cea2f7df87d92e29d48e8b36d7408cfc0c542b4aa0fe4ea22
|
4
|
+
data.tar.gz: 3c1be9afcd157d1c7a4aabf6f0688b049a80699133e6a3d31d17874bce453b5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7975e43767efe81a4d32819a62ce805d88c51c879e7456f9ea653be43521501bf79612d61ea95ab065efcf5bf7c43fa7f4c2e657a0ab09e211310200237faceb
|
7
|
+
data.tar.gz: 03f711b7f01ba88e9e84676ce442737bf8c7cd14db67cd04bdd50aa30eddaad850133d476e11b7a0c0ed25f485740810d6724e0449f7343cc10345bc67ba9c5c
|
data/Changes
CHANGED
@@ -1,5 +1,14 @@
|
|
1
1
|
Change history of write_xlsx rubygem.
|
2
2
|
|
3
|
+
2023-12-26 v1.11.2
|
4
|
+
Fix issue where header images in chartsheets weren't displayed.
|
5
|
+
Add support for custom table total functions.
|
6
|
+
Add chart option to display N/A as empty cells.
|
7
|
+
Add support for leader lines to all chart types.
|
8
|
+
Fix issue where column formulas were overwritten by table data
|
9
|
+
add Worksheet#very_hidden method.
|
10
|
+
Add add trendline equation formatting for chart.
|
11
|
+
|
3
12
|
2023-08-09 v1.11.1
|
4
13
|
Fixed issue #110. Redefining costant Struct::ColInfo
|
5
14
|
|
data/examples/shape_all.rb
CHANGED
@@ -218,7 +218,7 @@ shapes_list.each_line do |line|
|
|
218
218
|
line = line.chomp
|
219
219
|
next unless line =~ /^\w/ # Skip blank lines and comments.
|
220
220
|
|
221
|
-
sheet, name = line.split(
|
221
|
+
sheet, name = line.split("\t")
|
222
222
|
if last_sheet != sheet
|
223
223
|
worksheet = workbook.add_worksheet(sheet)
|
224
224
|
row = 2
|
data/lib/write_xlsx/chart/pie.rb
CHANGED
@@ -123,8 +123,7 @@ module Writexlsx
|
|
123
123
|
# Write the <c:legend> element.
|
124
124
|
#
|
125
125
|
def write_legend
|
126
|
-
|
127
|
-
allowed = %w[right left top bottom]
|
126
|
+
allowed = %w[right left top bottom]
|
128
127
|
delete_series = @legend.delete_series || []
|
129
128
|
|
130
129
|
if @legend.position =~ /^overlay_/
|
@@ -207,6 +206,19 @@ module Writexlsx
|
|
207
206
|
def write_first_slice_ang
|
208
207
|
@writer.empty_tag('c:firstSliceAng', [['val', @rotation]])
|
209
208
|
end
|
209
|
+
|
210
|
+
#
|
211
|
+
# Write the <c:showLeaderLines> element. This is for Pie/Doughnut charts.
|
212
|
+
# Other chart types only supported leader lines after Excel 2015 via an
|
213
|
+
# extension element.
|
214
|
+
#
|
215
|
+
def write_show_leader_lines
|
216
|
+
val = 1
|
217
|
+
|
218
|
+
attributes = [['val', val]]
|
219
|
+
|
220
|
+
@writer.empty_tag('c:showLeaderLines', attributes)
|
221
|
+
end
|
210
222
|
end
|
211
223
|
end
|
212
224
|
end
|
@@ -59,10 +59,13 @@ module Writexlsx
|
|
59
59
|
class Trendline < Chartline
|
60
60
|
attr_reader :name, :forward, :backward, :order, :period
|
61
61
|
attr_reader :intercept, :display_equation, :display_r_squared
|
62
|
+
attr_reader :label
|
62
63
|
|
63
64
|
def initialize(params)
|
64
65
|
super(params)
|
65
66
|
|
67
|
+
@label = trendline_label_properties(params[:label])
|
68
|
+
|
66
69
|
@name = params[:name]
|
67
70
|
@forward = params[:forward]
|
68
71
|
@backward = params[:backward]
|
@@ -76,6 +79,51 @@ module Writexlsx
|
|
76
79
|
|
77
80
|
private
|
78
81
|
|
82
|
+
#
|
83
|
+
# Convert user defined trendline label properties to the structure required
|
84
|
+
# internally.
|
85
|
+
#
|
86
|
+
def trendline_label_properties(_label)
|
87
|
+
return unless _label || _label.is_a?(Hash)
|
88
|
+
|
89
|
+
# Copy the user supplied properties.
|
90
|
+
label = {}
|
91
|
+
|
92
|
+
# Set the font properties for the label.
|
93
|
+
label[:font] = convert_font_args(_label[:font]) if ptrue?(_label[:font])
|
94
|
+
|
95
|
+
# Set the line properties for the label.
|
96
|
+
line = line_properties(_label[:line])
|
97
|
+
|
98
|
+
# Allow 'border' as a synonym for 'line'.
|
99
|
+
line = line_properties(_label[:border]) if ptrue?(_label[:border])
|
100
|
+
|
101
|
+
# Set the fill properties for the label.
|
102
|
+
fill = fill_properties(_label[:fill])
|
103
|
+
|
104
|
+
# Set the pattern properties for the label.
|
105
|
+
pattern = pattern_properties(_label[:pattern])
|
106
|
+
|
107
|
+
# Set the gradient fill properties for the label.
|
108
|
+
gradient = gradient_properties(_label[:gradient])
|
109
|
+
|
110
|
+
# Pattern fill overrides solid fill.
|
111
|
+
fill = nil if ptrue?(pattern)
|
112
|
+
|
113
|
+
# Gradient fill overrides solid and pattern fills.
|
114
|
+
if ptrue?(gradient)
|
115
|
+
pattern = nil
|
116
|
+
fill = nil
|
117
|
+
end
|
118
|
+
|
119
|
+
label[:line] = line
|
120
|
+
label[:fill] = fill
|
121
|
+
label[:pattern] = pattern
|
122
|
+
label[:gradient] = gradient
|
123
|
+
|
124
|
+
label
|
125
|
+
end
|
126
|
+
|
79
127
|
def types
|
80
128
|
{
|
81
129
|
exponential: 'exp',
|
data/lib/write_xlsx/chart.rb
CHANGED
@@ -568,6 +568,13 @@ module Writexlsx
|
|
568
568
|
@is_secondary
|
569
569
|
end
|
570
570
|
|
571
|
+
#
|
572
|
+
# Set the option for displaying #N/A as an empty cell in a chart.
|
573
|
+
#
|
574
|
+
def show_na_as_empty_cell
|
575
|
+
@show_na_as_empty = true
|
576
|
+
end
|
577
|
+
|
571
578
|
private
|
572
579
|
|
573
580
|
def axis_setup
|
@@ -598,6 +605,7 @@ module Writexlsx
|
|
598
605
|
@cross_between = 'between'
|
599
606
|
@date_category = false
|
600
607
|
@show_blanks = 'gap'
|
608
|
+
@show_na_as_empty = false
|
601
609
|
@show_hidden_data = false
|
602
610
|
@show_crosses = true
|
603
611
|
end
|
@@ -782,6 +790,9 @@ module Writexlsx
|
|
782
790
|
|
783
791
|
# Write the c:dispBlanksAs element.
|
784
792
|
write_disp_blanks_as
|
793
|
+
|
794
|
+
# Write the c:extLst element.
|
795
|
+
write_ext_lst_display_na if @show_na_as_empty
|
785
796
|
end
|
786
797
|
end
|
787
798
|
|
@@ -950,12 +961,13 @@ module Writexlsx
|
|
950
961
|
write_val(series)
|
951
962
|
# Write the c:smooth element.
|
952
963
|
write_c_smooth(series.smooth) if ptrue?(@smooth_allowed)
|
953
|
-
|
964
|
+
# Write the c:extLst element.
|
965
|
+
write_ext_lst_inverted_fill(series.inverted_color) if series.inverted_color
|
954
966
|
end
|
955
967
|
@series_index += 1
|
956
968
|
end
|
957
969
|
|
958
|
-
def
|
970
|
+
def write_ext_lst_inverted_fill(color)
|
959
971
|
uri = '{6F2FDCE9-48DA-4B69-8628-5D25D57E5C99}'
|
960
972
|
xmlns_c_14 =
|
961
973
|
'http://schemas.microsoft.com/office/drawing/2007/8/2/chart'
|
@@ -980,6 +992,31 @@ module Writexlsx
|
|
980
992
|
end
|
981
993
|
end
|
982
994
|
|
995
|
+
#
|
996
|
+
# Write the <c:extLst> element for the display N/A as empty cell option.
|
997
|
+
#
|
998
|
+
def write_ext_lst_display_na
|
999
|
+
uri = '{56B9EC1D-385E-4148-901F-78D8002777C0}'
|
1000
|
+
xmlns_c_16 = 'http://schemas.microsoft.com/office/drawing/2017/03/chart'
|
1001
|
+
|
1002
|
+
attributes1 = [
|
1003
|
+
['uri', uri],
|
1004
|
+
['xmlns:c16r3', xmlns_c_16]
|
1005
|
+
]
|
1006
|
+
|
1007
|
+
attributes2 = [
|
1008
|
+
['val', 1]
|
1009
|
+
]
|
1010
|
+
|
1011
|
+
@writer.tag_elements('c:extLst') do
|
1012
|
+
@writer.tag_elements('c:ext', attributes1) do
|
1013
|
+
@writer.tag_elements('c16r3:dataDisplayOptions16') do
|
1014
|
+
@writer.empty_tag('c16r3:dispNaAsBlank', attributes2)
|
1015
|
+
end
|
1016
|
+
end
|
1017
|
+
end
|
1018
|
+
end
|
1019
|
+
|
983
1020
|
def write_ser_base(series)
|
984
1021
|
# Write the c:idx element.
|
985
1022
|
write_idx(@series_index)
|
@@ -2122,7 +2159,7 @@ module Writexlsx
|
|
2122
2159
|
# Write the c:dispEq element.
|
2123
2160
|
write_disp_eq
|
2124
2161
|
# Write the c:trendlineLbl element.
|
2125
|
-
write_trendline_lbl
|
2162
|
+
write_trendline_lbl(trendline)
|
2126
2163
|
end
|
2127
2164
|
end
|
2128
2165
|
end
|
@@ -2199,12 +2236,18 @@ module Writexlsx
|
|
2199
2236
|
#
|
2200
2237
|
# Write the <c:trendlineLbl> element.
|
2201
2238
|
#
|
2202
|
-
def write_trendline_lbl
|
2239
|
+
def write_trendline_lbl(trendline)
|
2203
2240
|
@writer.tag_elements('c:trendlineLbl') do
|
2204
2241
|
# Write the c:layout element.
|
2205
2242
|
write_layout
|
2206
2243
|
# Write the c:numFmt element.
|
2207
2244
|
write_trendline_num_fmt
|
2245
|
+
# Write the c:spPr element for the label formatting.
|
2246
|
+
write_sp_pr(trendline.label)
|
2247
|
+
# Write the data label font elements.
|
2248
|
+
if trendline.label && ptrue?(trendline.label[:font])
|
2249
|
+
write_axis_font(trendline.label[:font])
|
2250
|
+
end
|
2208
2251
|
end
|
2209
2252
|
end
|
2210
2253
|
|
@@ -2544,11 +2587,25 @@ module Writexlsx
|
|
2544
2587
|
@writer.data_element('c:separator', data)
|
2545
2588
|
end
|
2546
2589
|
|
2547
|
-
#
|
2548
|
-
#
|
2549
|
-
#
|
2590
|
+
# Write the <c:showLeaderLines> element. This is different for Pie/Doughnut
|
2591
|
+
# charts. Other chart types only supported leader lines after Excel 2015 via
|
2592
|
+
# an extension element.
|
2550
2593
|
def write_show_leader_lines
|
2551
|
-
|
2594
|
+
uri = '{CE6537A1-D6FC-4f65-9D91-7224C49458BB}'
|
2595
|
+
xmlns_c_15 = 'http://schemas.microsoft.com/office/drawing/2012/chart'
|
2596
|
+
|
2597
|
+
attributes1 = [
|
2598
|
+
['uri', uri],
|
2599
|
+
['xmlns:c15', xmlns_c_15]
|
2600
|
+
]
|
2601
|
+
|
2602
|
+
attributes2 = [['val', 1]]
|
2603
|
+
|
2604
|
+
@writer.tag_elements('c:extLst') do
|
2605
|
+
@writer.tag_elements('c:ext', attributes1) do
|
2606
|
+
@writer.empty_tag('c15:showLeaderLines', attributes2)
|
2607
|
+
end
|
2608
|
+
end
|
2552
2609
|
end
|
2553
2610
|
|
2554
2611
|
#
|
@@ -2862,8 +2919,6 @@ module Writexlsx
|
|
2862
2919
|
# Write the <a:fillToRect> element.
|
2863
2920
|
#
|
2864
2921
|
def write_a_fill_to_rect(type)
|
2865
|
-
attributes = []
|
2866
|
-
|
2867
2922
|
attributes = if type == 'shape'
|
2868
2923
|
[
|
2869
2924
|
['l', 50000],
|
@@ -2885,8 +2940,6 @@ module Writexlsx
|
|
2885
2940
|
# Write the <a:tileRect> element.
|
2886
2941
|
#
|
2887
2942
|
def write_a_tile_rect(type)
|
2888
|
-
attributes = []
|
2889
|
-
|
2890
2943
|
attributes = if type == 'shape'
|
2891
2944
|
[]
|
2892
2945
|
else
|
@@ -54,6 +54,8 @@ module Writexlsx
|
|
54
54
|
write_header_footer
|
55
55
|
# Write the drawing element.
|
56
56
|
write_drawings
|
57
|
+
# Write the legaacyDrawingHF element.
|
58
|
+
write_legacy_drawing_hf
|
57
59
|
# Close the worksheet tag.
|
58
60
|
end
|
59
61
|
end
|
@@ -145,6 +147,10 @@ module Writexlsx
|
|
145
147
|
@chart.show_blanks_as(*args)
|
146
148
|
end
|
147
149
|
|
150
|
+
def show_na_as_empty_cell
|
151
|
+
@chart.show_na_as_empty_cell(*args)
|
152
|
+
end
|
153
|
+
|
148
154
|
def show_hidden_data(*args)
|
149
155
|
@chart.show_hidden_data(*args)
|
150
156
|
end
|
@@ -185,7 +191,10 @@ module Writexlsx
|
|
185
191
|
end
|
186
192
|
|
187
193
|
def external_links
|
188
|
-
[
|
194
|
+
[
|
195
|
+
@external_drawing_links,
|
196
|
+
@external_vml_links
|
197
|
+
]
|
189
198
|
end
|
190
199
|
|
191
200
|
private
|
data/lib/write_xlsx/col_name.rb
CHANGED
@@ -7,12 +7,16 @@ class ColName
|
|
7
7
|
include Singleton
|
8
8
|
|
9
9
|
def initialize
|
10
|
-
@col_str_table =
|
10
|
+
@col_str_table = []
|
11
|
+
@row_str_table = []
|
11
12
|
end
|
12
13
|
|
13
14
|
def col_str(col)
|
14
|
-
@col_str_table[col]
|
15
|
-
|
15
|
+
@col_str_table[col] ||= col_str_build(col)
|
16
|
+
end
|
17
|
+
|
18
|
+
def row_str(row)
|
19
|
+
@row_str_table[row] ||= row.to_s
|
16
20
|
end
|
17
21
|
|
18
22
|
private
|
data/lib/write_xlsx/format.rb
CHANGED
@@ -324,7 +324,7 @@ module Writexlsx
|
|
324
324
|
return colors[color_code.downcase.to_sym] if colors[color_code.downcase.to_sym]
|
325
325
|
|
326
326
|
# or the default color if string is unrecognised,
|
327
|
-
|
327
|
+
0x00 if color_code =~ /\D/
|
328
328
|
else
|
329
329
|
# or an index < 8 mapped into the correct range,
|
330
330
|
return color_code + 8 if color_code < 8
|
@@ -46,7 +46,9 @@ module Writexlsx
|
|
46
46
|
add_heading_pair(
|
47
47
|
[
|
48
48
|
'Worksheets',
|
49
|
-
@workbook.worksheets.reject
|
49
|
+
@workbook.worksheets.reject do |s|
|
50
|
+
s.is_chartsheet? || s.very_hidden?
|
51
|
+
end.count
|
50
52
|
]
|
51
53
|
)
|
52
54
|
end
|
@@ -57,14 +59,16 @@ module Writexlsx
|
|
57
59
|
|
58
60
|
def add_worksheet_part_names
|
59
61
|
@workbook.worksheets
|
60
|
-
|
61
|
-
|
62
|
+
.reject { |sheet| sheet.is_chartsheet? || sheet.very_hidden? }
|
63
|
+
.each do |sheet|
|
64
|
+
add_part_name(sheet.name)
|
65
|
+
end
|
62
66
|
end
|
63
67
|
|
64
68
|
def add_chartsheet_part_names
|
65
69
|
@workbook.worksheets
|
66
|
-
|
67
|
-
|
70
|
+
.select { |sheet| sheet.is_chartsheet? }
|
71
|
+
.each { |sheet| add_part_name(sheet.name) }
|
68
72
|
end
|
69
73
|
|
70
74
|
def add_part_name(part_name)
|
@@ -411,7 +411,7 @@ module Writexlsx
|
|
411
411
|
# Check for a cell reference in A1 notation and substitute row and column
|
412
412
|
user_range = if args[0].to_s =~ (/^\D/) && (args[0] =~ /,/)
|
413
413
|
# Check for a user defined multiple range like B3:K6,B8:K11.
|
414
|
-
args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub(
|
414
|
+
args[0].sub(/^=/, '').gsub(/\s*,\s*/, ' ').gsub("$", '')
|
415
415
|
end
|
416
416
|
|
417
417
|
if (row_col_array = row_col_notation(args.first))
|
@@ -769,7 +769,7 @@ module Writexlsx
|
|
769
769
|
attr = super
|
770
770
|
attr << ['percent', 1] if criteria == '%'
|
771
771
|
attr << ['bottom', 1] if direction
|
772
|
-
attr << ['rank',
|
772
|
+
attr << ['rank', value || 10]
|
773
773
|
attr
|
774
774
|
end
|
775
775
|
end
|
@@ -142,13 +142,12 @@ module Writexlsx
|
|
142
142
|
def write_app_file
|
143
143
|
app = Package::App.new(@workbook)
|
144
144
|
|
145
|
+
# Add the Worksheet parts.
|
146
|
+
app.add_worksheet_part_names
|
145
147
|
# Add the Worksheet heading pairs.
|
146
148
|
app.add_worksheet_heading_pairs
|
147
149
|
# Add the Chartsheet heading pairs.
|
148
150
|
app.add_chartsheet_heading_pairs
|
149
|
-
|
150
|
-
# Add the Worksheet parts.
|
151
|
-
app.add_worksheet_part_names
|
152
151
|
# Add the Chartsheet parts.
|
153
152
|
app.add_chartsheet_part_names
|
154
153
|
# Add the Named Range heading pairs.
|
@@ -12,13 +12,14 @@ module Writexlsx
|
|
12
12
|
class ColumnData
|
13
13
|
attr_reader :id
|
14
14
|
attr_accessor :name, :format, :formula, :name_format
|
15
|
-
attr_accessor :total_string, :total_function
|
15
|
+
attr_accessor :total_string, :total_function, :custom_total
|
16
16
|
|
17
17
|
def initialize(id, param = {})
|
18
18
|
@id = id
|
19
19
|
@name = "Column#{id}"
|
20
20
|
@total_string = ''
|
21
21
|
@total_function = ''
|
22
|
+
@custom_total = ''
|
22
23
|
@formula = ''
|
23
24
|
@format = nil
|
24
25
|
@name_format = nil
|
@@ -51,6 +52,7 @@ module Writexlsx
|
|
51
52
|
|
52
53
|
add_the_table_columns
|
53
54
|
write_the_cell_data_if_supplied
|
55
|
+
write_any_columns_formulas_after_the_user_supplied_table_data
|
54
56
|
store_filter_cell_positions
|
55
57
|
end
|
56
58
|
|
@@ -78,7 +80,7 @@ module Writexlsx
|
|
78
80
|
# Set up the default column data.
|
79
81
|
col_data = Package::Table::ColumnData.new(col_id + 1, @param[:columns])
|
80
82
|
|
81
|
-
|
83
|
+
overwrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
|
82
84
|
|
83
85
|
# Store the column data.
|
84
86
|
@columns << col_data
|
@@ -89,7 +91,7 @@ module Writexlsx
|
|
89
91
|
end # Table columns.
|
90
92
|
end
|
91
93
|
|
92
|
-
def
|
94
|
+
def overwrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
|
93
95
|
# Check if there are user defined values for this column.
|
94
96
|
if @param[:columns] && (user_data = @param[:columns][col_id])
|
95
97
|
# Map user defined values to internal values.
|
@@ -156,6 +158,23 @@ module Writexlsx
|
|
156
158
|
end
|
157
159
|
end
|
158
160
|
|
161
|
+
def write_any_columns_formulas_after_the_user_supplied_table_data
|
162
|
+
col_id = 0
|
163
|
+
|
164
|
+
(@col1..@col2).each do |col|
|
165
|
+
column_data = @columns[col_id]
|
166
|
+
if ptrue?(column_data) && ptrue?(column_data.formula)
|
167
|
+
formula_format = @col_formats[col_id]
|
168
|
+
formula = column_data.formula
|
169
|
+
|
170
|
+
(@first_data_row..@last_data_row).each do |row|
|
171
|
+
@worksheet.write_formula(row, col, formula, formula_format)
|
172
|
+
end
|
173
|
+
end
|
174
|
+
col_id += 1
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
159
178
|
def store_filter_cell_positions
|
160
179
|
if ptrue?(@param[:autofilter])
|
161
180
|
(@col1..@col2).each do |col|
|
@@ -234,25 +253,45 @@ module Writexlsx
|
|
234
253
|
]
|
235
254
|
end
|
236
255
|
|
237
|
-
def handle_the_column_formula(col_data,
|
256
|
+
def handle_the_column_formula(col_data, _col_num, formula, _format)
|
238
257
|
return unless formula
|
239
258
|
|
240
|
-
|
259
|
+
formula = formula.sub(/^=/, '').gsub(/@/, '[#This Row],')
|
241
260
|
|
242
|
-
|
243
|
-
|
244
|
-
|
261
|
+
# Escape any future functions.
|
262
|
+
col_data.formula = @worksheet.prepare_formula(formula, 1)
|
263
|
+
|
264
|
+
# (@first_data_row..@last_data_row).each do |row|
|
265
|
+
# @worksheet.write_formula(row, col_num, col_data.formula, format)
|
266
|
+
# end
|
245
267
|
end
|
246
268
|
|
247
269
|
def handle_the_function_for_the_table_row(row2, col_data, col_num, user_data)
|
248
|
-
|
270
|
+
formula = ''
|
271
|
+
function = user_data[:total_function]
|
272
|
+
function = 'countNums' if function == 'count_nums'
|
273
|
+
function = 'stdDev' if function == 'std_dev'
|
249
274
|
|
250
|
-
|
251
|
-
|
275
|
+
subtotals = {
|
276
|
+
average: 101,
|
277
|
+
countNums: 102,
|
278
|
+
count: 103,
|
279
|
+
max: 104,
|
280
|
+
min: 105,
|
281
|
+
stdDev: 106,
|
282
|
+
sum: 109,
|
283
|
+
var: 110
|
284
|
+
}
|
252
285
|
|
253
|
-
|
286
|
+
if subtotals[function.to_sym]
|
287
|
+
formula = table_function_to_formula(function, col_data.name)
|
288
|
+
else
|
289
|
+
formula = @worksheet.prepare_formula(function, 1)
|
290
|
+
col_data.custom_total = formula
|
291
|
+
function = 'custom'
|
292
|
+
end
|
254
293
|
|
255
|
-
|
294
|
+
col_data.total_function = function
|
256
295
|
@worksheet.write_formula(row2, col_num, formula, user_data[:format], user_data[:total_value])
|
257
296
|
end
|
258
297
|
|
@@ -260,10 +299,10 @@ module Writexlsx
|
|
260
299
|
# Convert a table total function to a worksheet formula.
|
261
300
|
#
|
262
301
|
def table_function_to_formula(function, col_name)
|
263
|
-
col_name = col_name.gsub(
|
264
|
-
.gsub(
|
265
|
-
.gsub(
|
266
|
-
.gsub(
|
302
|
+
col_name = col_name.gsub("'", "''")
|
303
|
+
.gsub("#", "'#")
|
304
|
+
.gsub("[", "'[")
|
305
|
+
.gsub("]", "']")
|
267
306
|
|
268
307
|
subtotals = {
|
269
308
|
average: 101,
|
@@ -395,10 +434,16 @@ module Writexlsx
|
|
395
434
|
|
396
435
|
attributes << [:dataDxfId, col_data.format] if col_data.format
|
397
436
|
|
398
|
-
if ptrue?(col_data.formula)
|
437
|
+
if ptrue?(col_data.formula) || ptrue?(col_data.custom_total)
|
399
438
|
@writer.tag_elements('tableColumn', attributes) do
|
400
|
-
|
401
|
-
|
439
|
+
if ptrue?(col_data.formula)
|
440
|
+
# Write the calculatedColumnFormula element.
|
441
|
+
write_calculated_column_formula(col_data.formula)
|
442
|
+
end
|
443
|
+
if ptrue?(col_data.custom_total)
|
444
|
+
# Write the totalsRowFormula element.
|
445
|
+
write_totals_row_formula(col_data.custom_total)
|
446
|
+
end
|
402
447
|
end
|
403
448
|
else
|
404
449
|
@writer.empty_tag('tableColumn', attributes)
|
@@ -425,6 +470,15 @@ module Writexlsx
|
|
425
470
|
def write_calculated_column_formula(formula)
|
426
471
|
@writer.data_element('calculatedColumnFormula', formula)
|
427
472
|
end
|
473
|
+
|
474
|
+
#
|
475
|
+
# _write_totals_row_formula()
|
476
|
+
#
|
477
|
+
# Write the <totalsRowFormula> element.
|
478
|
+
#
|
479
|
+
def write_totals_row_formula(formula)
|
480
|
+
@writer.data_element('totalsRowFormula', formula)
|
481
|
+
end
|
428
482
|
end
|
429
483
|
end
|
430
484
|
end
|
@@ -29,33 +29,28 @@ module Writexlsx
|
|
29
29
|
io_write(str)
|
30
30
|
end
|
31
31
|
|
32
|
-
def tag_elements(tag, attributes =
|
32
|
+
def tag_elements(tag, attributes = nil)
|
33
33
|
start_tag(tag, attributes)
|
34
34
|
yield
|
35
35
|
end_tag(tag)
|
36
36
|
end
|
37
37
|
|
38
|
-
def tag_elements_str(tag, attributes =
|
38
|
+
def tag_elements_str(tag, attributes = nil)
|
39
39
|
start_tag_str(tag, attributes) +
|
40
40
|
yield +
|
41
41
|
end_tag_str(tag)
|
42
42
|
end
|
43
43
|
|
44
|
-
def start_tag(tag, attr =
|
44
|
+
def start_tag(tag, attr = nil)
|
45
45
|
io_write(start_tag_str(tag, attr))
|
46
46
|
end
|
47
47
|
|
48
|
-
def start_tag_str(tag, attr =
|
49
|
-
if attr.empty?
|
50
|
-
|
51
|
-
unless result
|
52
|
-
result = "<#{tag}>"
|
53
|
-
@tag_start_cache[tag] = result
|
54
|
-
end
|
48
|
+
def start_tag_str(tag, attr = nil)
|
49
|
+
if attr.nil? || attr.empty?
|
50
|
+
@tag_start_cache[tag] ||= "<#{tag}>"
|
55
51
|
else
|
56
|
-
|
52
|
+
"<#{tag}#{key_vals(attr)}>"
|
57
53
|
end
|
58
|
-
result
|
59
54
|
end
|
60
55
|
|
61
56
|
def end_tag(tag)
|
@@ -63,28 +58,15 @@ module Writexlsx
|
|
63
58
|
end
|
64
59
|
|
65
60
|
def end_tag_str(tag)
|
66
|
-
|
67
|
-
unless result
|
68
|
-
result = "</#{tag}>"
|
69
|
-
@tag_end_cache[tag] = result
|
70
|
-
end
|
71
|
-
result
|
61
|
+
@tag_end_cache[tag] ||= "</#{tag}>"
|
72
62
|
end
|
73
63
|
|
74
|
-
def empty_tag(tag, attr =
|
64
|
+
def empty_tag(tag, attr = nil)
|
75
65
|
str = "<#{tag}#{key_vals(attr)}/>"
|
76
66
|
io_write(str)
|
77
67
|
end
|
78
68
|
|
79
|
-
def
|
80
|
-
io_write(empty_tag_encoded_str(tag, attr))
|
81
|
-
end
|
82
|
-
|
83
|
-
def empty_tag_encoded_str(tag, attr = [])
|
84
|
-
"<#{tag}#{key_vals(attr)}/>"
|
85
|
-
end
|
86
|
-
|
87
|
-
def data_element(tag, data, attr = [])
|
69
|
+
def data_element(tag, data, attr = nil)
|
88
70
|
tag_elements(tag, attr) { io_write(escape_data(data)) }
|
89
71
|
end
|
90
72
|
|
@@ -126,31 +108,37 @@ module Writexlsx
|
|
126
108
|
|
127
109
|
private
|
128
110
|
|
129
|
-
def key_val(key, val)
|
130
|
-
%( #{key}="#{val}")
|
131
|
-
end
|
132
|
-
|
133
111
|
def key_vals(attribute)
|
134
|
-
attribute
|
135
|
-
|
112
|
+
if attribute
|
113
|
+
result = "".dup
|
114
|
+
attribute.each do |attr|
|
115
|
+
# Generate and concat %( #{key}="#{val}") values for attribute pair
|
116
|
+
result << " "
|
117
|
+
result << attr.first.to_s
|
118
|
+
result << '="'
|
119
|
+
result << escape_attributes(attr.last).to_s
|
120
|
+
result << '"'
|
121
|
+
end
|
122
|
+
result
|
123
|
+
end
|
136
124
|
end
|
137
125
|
|
138
126
|
def escape_attributes(str = '')
|
139
|
-
return str unless str.
|
127
|
+
return str unless str.respond_to?(:match) && str =~ /["&<>\n]/
|
140
128
|
|
141
129
|
str
|
142
|
-
.gsub(
|
143
|
-
.gsub(
|
144
|
-
.gsub(
|
145
|
-
.gsub(
|
146
|
-
.gsub(
|
130
|
+
.gsub("&", "&")
|
131
|
+
.gsub('"', """)
|
132
|
+
.gsub("<", "<")
|
133
|
+
.gsub(">", ">")
|
134
|
+
.gsub("\n", "
")
|
147
135
|
end
|
148
136
|
|
149
137
|
def escape_data(str = '')
|
150
|
-
if str.
|
151
|
-
str.gsub(
|
152
|
-
.gsub(
|
153
|
-
.gsub(
|
138
|
+
if str.respond_to?(:match) && str =~ /[&<>]/
|
139
|
+
str.gsub("&", '&')
|
140
|
+
.gsub("<", '<')
|
141
|
+
.gsub(">", '>')
|
154
142
|
else
|
155
143
|
str
|
156
144
|
end
|
data/lib/write_xlsx/sheets.rb
CHANGED
@@ -252,9 +252,13 @@ module Writexlsx
|
|
252
252
|
['sheetId', sheet_id]
|
253
253
|
]
|
254
254
|
|
255
|
-
|
255
|
+
if sheet.hidden?
|
256
|
+
attributes << %w[state hidden]
|
257
|
+
elsif sheet.very_hidden?
|
258
|
+
attributes << %w[state veryHidden]
|
259
|
+
end
|
256
260
|
attributes << r_id_attributes(sheet_id)
|
257
|
-
writer.
|
261
|
+
writer.empty_tag('sheet', attributes)
|
258
262
|
end
|
259
263
|
end
|
260
264
|
end
|
data/lib/write_xlsx/sparkline.rb
CHANGED
@@ -43,13 +43,13 @@ module Writexlsx
|
|
43
43
|
# Cleanup the input ranges.
|
44
44
|
@ranges.collect! do |range|
|
45
45
|
# Remove the absolute reference $ symbols.
|
46
|
-
range = range.gsub(
|
46
|
+
range = range.gsub("$", '')
|
47
47
|
# Convert a simple range into a full Sheet1!A1:D1 range.
|
48
48
|
range = "#{sheetname}!#{range}" unless range =~ /!/
|
49
49
|
range
|
50
50
|
end
|
51
51
|
# Cleanup the input locations.
|
52
|
-
@locations.collect! { |location| location.gsub(
|
52
|
+
@locations.collect! { |location| location.gsub("$", '') }
|
53
53
|
|
54
54
|
# Map options.
|
55
55
|
@high = param[:high_point]
|
data/lib/write_xlsx/utility.rb
CHANGED
@@ -31,10 +31,12 @@ module Writexlsx
|
|
31
31
|
#
|
32
32
|
# xl_rowcol_to_cell($row, col, row_absolute, col_absolute)
|
33
33
|
#
|
34
|
-
def xl_rowcol_to_cell(
|
35
|
-
|
34
|
+
def xl_rowcol_to_cell(row_or_name, col, row_absolute = false, col_absolute = false)
|
35
|
+
if row_or_name.is_a?(Integer)
|
36
|
+
row_or_name += 1 # Change from 0-indexed to 1 indexed.
|
37
|
+
end
|
36
38
|
col_str = xl_col_to_name(col, col_absolute)
|
37
|
-
"#{col_str}#{absolute_char(row_absolute)}#{
|
39
|
+
"#{col_str}#{absolute_char(row_absolute)}#{row_or_name}"
|
38
40
|
end
|
39
41
|
|
40
42
|
#
|
@@ -53,7 +55,7 @@ module Writexlsx
|
|
53
55
|
|
54
56
|
# Convert base26 column string to number
|
55
57
|
# All your Base are belong to us.
|
56
|
-
chars = col.split(
|
58
|
+
chars = col.split("")
|
57
59
|
expn = 0
|
58
60
|
col = 0
|
59
61
|
|
@@ -112,7 +114,7 @@ module Writexlsx
|
|
112
114
|
#
|
113
115
|
def xl_string_pixel_width(string)
|
114
116
|
length = 0
|
115
|
-
string.to_s.split(
|
117
|
+
string.to_s.split("").each { |char| length += CHAR_WIDTHS[char] || 8 }
|
116
118
|
|
117
119
|
length
|
118
120
|
end
|
@@ -128,7 +130,7 @@ module Writexlsx
|
|
128
130
|
name = sheetname.dup
|
129
131
|
if name =~ /\W/ && !(name =~ /^'/)
|
130
132
|
# Double quote and single quoted strings.
|
131
|
-
name = name.gsub(
|
133
|
+
name = name.gsub("'", "''")
|
132
134
|
name = "'#{name}'"
|
133
135
|
end
|
134
136
|
name
|
@@ -159,7 +161,7 @@ module Writexlsx
|
|
159
161
|
seconds = 0 # Time expressed as fraction of 24h hours in seconds
|
160
162
|
|
161
163
|
# Split into date and time.
|
162
|
-
date, time = date_time.split(
|
164
|
+
date, time = date_time.split("T")
|
163
165
|
|
164
166
|
# We allow the time portion of the input DateTime to be optional.
|
165
167
|
if time
|
@@ -207,7 +209,7 @@ module Writexlsx
|
|
207
209
|
# becomes 100 for 4 and 100 year leapdays and 400 for 400 year leapdays.
|
208
210
|
#
|
209
211
|
epoch = date_1904? ? 1904 : 1900
|
210
|
-
offset = date_1904? ?
|
212
|
+
offset = date_1904? ? 4 : 0
|
211
213
|
norm = 300
|
212
214
|
range = year - epoch
|
213
215
|
|
@@ -248,7 +250,7 @@ module Writexlsx
|
|
248
250
|
def escape_url(url)
|
249
251
|
unless url =~ /%[0-9a-fA-F]{2}/
|
250
252
|
# Escape the URL escape symbol.
|
251
|
-
url = url.gsub(
|
253
|
+
url = url.gsub("%", "%25")
|
252
254
|
|
253
255
|
# Escape whitespae in URL.
|
254
256
|
url = url.gsub(/[\s\x00]/, '%20')
|
data/lib/write_xlsx/version.rb
CHANGED
data/lib/write_xlsx/workbook.rb
CHANGED
@@ -715,7 +715,7 @@ module Writexlsx
|
|
715
715
|
|
716
716
|
# Split the cell range into 2 cells or else use single cell for both.
|
717
717
|
if cells =~ /:/
|
718
|
-
cell_1, cell_2 = cells.split(
|
718
|
+
cell_1, cell_2 = cells.split(":")
|
719
719
|
else
|
720
720
|
cell_1 = cells
|
721
721
|
cell_2 = cells
|
@@ -724,7 +724,7 @@ module Writexlsx
|
|
724
724
|
# Remove leading/trailing apostrophes and convert escaped quotes to single.
|
725
725
|
sheetname.sub!(/^'/, '')
|
726
726
|
sheetname.sub!(/'$/, '')
|
727
|
-
sheetname.gsub!(
|
727
|
+
sheetname.gsub!("''", "'")
|
728
728
|
|
729
729
|
row_start, col_start = xl_cell_to_rowcol(cell_1)
|
730
730
|
row_end, col_end = xl_cell_to_rowcol(cell_2)
|
@@ -12,10 +12,10 @@ module Writexlsx
|
|
12
12
|
# attributes for the <cell> element. This is the innermost loop so efficiency is
|
13
13
|
# important where possible.
|
14
14
|
#
|
15
|
-
def cell_attributes(worksheet, row, col) # :nodoc:
|
15
|
+
def cell_attributes(worksheet, row, row_name, col) # :nodoc:
|
16
16
|
xf_index = xf ? xf.get_xf_index : 0
|
17
17
|
attributes = [
|
18
|
-
['r', xl_rowcol_to_cell(
|
18
|
+
['r', xl_rowcol_to_cell(row_name, col)]
|
19
19
|
]
|
20
20
|
|
21
21
|
# Add the cell format index.
|
@@ -48,8 +48,8 @@ module Writexlsx
|
|
48
48
|
@token
|
49
49
|
end
|
50
50
|
|
51
|
-
def write_cell(worksheet, row, col)
|
52
|
-
worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, col)) do
|
51
|
+
def write_cell(worksheet, row, row_name, col)
|
52
|
+
worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, row_name, col)) do
|
53
53
|
worksheet.write_cell_value(token)
|
54
54
|
end
|
55
55
|
end
|
@@ -69,8 +69,8 @@ module Writexlsx
|
|
69
69
|
end
|
70
70
|
|
71
71
|
TYPE_STR_ATTRS = %w[t s].freeze
|
72
|
-
def write_cell(worksheet, row, col)
|
73
|
-
attributes = cell_attributes(worksheet, row, col)
|
72
|
+
def write_cell(worksheet, row, row_name, col)
|
73
|
+
attributes = cell_attributes(worksheet, row, row_name, col)
|
74
74
|
attributes << TYPE_STR_ATTRS
|
75
75
|
worksheet.writer.tag_elements('c', attributes) do
|
76
76
|
worksheet.write_cell_value(token)
|
@@ -101,11 +101,11 @@ module Writexlsx
|
|
101
101
|
@result || 0
|
102
102
|
end
|
103
103
|
|
104
|
-
def write_cell(worksheet, row, col)
|
104
|
+
def write_cell(worksheet, row, row_name, col)
|
105
105
|
truefalse = { 'TRUE' => 1, 'FALSE' => 0 }
|
106
106
|
error_code = ['#DIV/0!', '#N/A', '#NAME?', '#NULL!', '#NUM!', '#REF!', '#VALUE!']
|
107
107
|
|
108
|
-
attributes = cell_attributes(worksheet, row, col)
|
108
|
+
attributes = cell_attributes(worksheet, row, row_name, col)
|
109
109
|
if @result && !(@result.to_s =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/)
|
110
110
|
if truefalse[@result]
|
111
111
|
attributes << %w[t b]
|
@@ -137,8 +137,8 @@ module Writexlsx
|
|
137
137
|
@result || 0
|
138
138
|
end
|
139
139
|
|
140
|
-
def write_cell(worksheet, row, col)
|
141
|
-
worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, col)) do
|
140
|
+
def write_cell(worksheet, row, row_name, col)
|
141
|
+
worksheet.writer.tag_elements('c', cell_attributes(worksheet, row, row_name, col)) do
|
142
142
|
worksheet.write_cell_array_formula(token, range)
|
143
143
|
worksheet.write_cell_value(result)
|
144
144
|
end
|
@@ -159,9 +159,9 @@ module Writexlsx
|
|
159
159
|
@result || 0
|
160
160
|
end
|
161
161
|
|
162
|
-
def write_cell(worksheet, row, col)
|
162
|
+
def write_cell(worksheet, row, row_name, col)
|
163
163
|
# Add metadata linkage for dynamic array formulas.
|
164
|
-
attributes = cell_attributes(worksheet, row, col)
|
164
|
+
attributes = cell_attributes(worksheet, row, row_name, col)
|
165
165
|
attributes << %w[cm 1]
|
166
166
|
|
167
167
|
worksheet.writer.tag_elements('c', attributes) do
|
@@ -183,8 +183,8 @@ module Writexlsx
|
|
183
183
|
@token
|
184
184
|
end
|
185
185
|
|
186
|
-
def write_cell(worksheet, row, col)
|
187
|
-
attributes = cell_attributes(worksheet, row, col)
|
186
|
+
def write_cell(worksheet, row, row_name, col)
|
187
|
+
attributes = cell_attributes(worksheet, row, row_name, col)
|
188
188
|
|
189
189
|
attributes << %w[t b]
|
190
190
|
worksheet.writer.tag_elements('c', attributes) do
|
@@ -202,8 +202,8 @@ module Writexlsx
|
|
202
202
|
''
|
203
203
|
end
|
204
204
|
|
205
|
-
def write_cell(worksheet, row, col)
|
206
|
-
worksheet.writer.empty_tag('c', cell_attributes(worksheet, row, col))
|
205
|
+
def write_cell(worksheet, row, row_name, col)
|
206
|
+
worksheet.writer.empty_tag('c', cell_attributes(worksheet, row, row_name, col))
|
207
207
|
end
|
208
208
|
end
|
209
209
|
end
|
@@ -28,7 +28,7 @@ module Writexlsx
|
|
28
28
|
normalized_str = str.sub(/^mailto:/, '')
|
29
29
|
|
30
30
|
# Split url into the link and optional anchor/location.
|
31
|
-
url, @url_str = url.split(
|
31
|
+
url, @url_str = url.split("#", 2)
|
32
32
|
|
33
33
|
# Escape URL unless it looks already escaped.
|
34
34
|
url = escape_url(url)
|
@@ -106,7 +106,7 @@ module Writexlsx
|
|
106
106
|
str = str.sub(/^mailto:/, '')
|
107
107
|
|
108
108
|
# Split url into the link and optional anchor/location.
|
109
|
-
url, url_str = url.split(
|
109
|
+
url, url_str = url.split("#", 2)
|
110
110
|
|
111
111
|
# Escape URL unless it looks already escaped.
|
112
112
|
url = escape_url(url)
|
data/lib/write_xlsx/worksheet.rb
CHANGED
@@ -228,15 +228,26 @@ module Writexlsx
|
|
228
228
|
#
|
229
229
|
# Hide this worksheet.
|
230
230
|
#
|
231
|
-
def hide
|
232
|
-
@hidden =
|
231
|
+
def hide(hidden = :hidden)
|
232
|
+
@hidden = hidden
|
233
233
|
@selected = false
|
234
234
|
@workbook.activesheet = 0 if @workbook.activesheet == @index
|
235
235
|
@workbook.firstsheet = 0 if @workbook.firstsheet == @index
|
236
236
|
end
|
237
237
|
|
238
|
+
#
|
239
|
+
# Hide this worksheet. This can only be unhidden from VBA.
|
240
|
+
#
|
241
|
+
def very_hidden
|
242
|
+
hide(:very_hidden)
|
243
|
+
end
|
244
|
+
|
238
245
|
def hidden? # :nodoc:
|
239
|
-
@hidden
|
246
|
+
@hidden == :hidden
|
247
|
+
end
|
248
|
+
|
249
|
+
def very_hidden? # :nodoc:
|
250
|
+
@hidden == :very_hidden
|
240
251
|
end
|
241
252
|
|
242
253
|
#
|
@@ -271,7 +282,7 @@ module Writexlsx
|
|
271
282
|
if range.nil?
|
272
283
|
raise "The range must be defined in unprotect_range())\n"
|
273
284
|
else
|
274
|
-
range = range.gsub(
|
285
|
+
range = range.gsub("$", "")
|
275
286
|
range = range.sub(/^=/, "")
|
276
287
|
@num_protected_ranges += 1
|
277
288
|
end
|
@@ -612,8 +623,17 @@ module Writexlsx
|
|
612
623
|
#
|
613
624
|
# This method is used to display the worksheet in "Page View/Layout" mode.
|
614
625
|
#
|
615
|
-
def set_page_view(flag =
|
616
|
-
@page_view =
|
626
|
+
def set_page_view(flag = 1)
|
627
|
+
@page_view = flag
|
628
|
+
end
|
629
|
+
|
630
|
+
#
|
631
|
+
# set_pagebreak_view
|
632
|
+
#
|
633
|
+
# Set the page view mode.
|
634
|
+
#
|
635
|
+
def set_pagebreak_view
|
636
|
+
@page_view = 2
|
617
637
|
end
|
618
638
|
|
619
639
|
#
|
@@ -648,7 +668,7 @@ module Writexlsx
|
|
648
668
|
raise 'Header string must be less than 255 characters' if string.length > 255
|
649
669
|
|
650
670
|
# Replace the Excel placeholder &[Picture] with the internal &G.
|
651
|
-
@page_setup.header = string.gsub(
|
671
|
+
@page_setup.header = string.gsub("&[Picture]", '&G')
|
652
672
|
|
653
673
|
@page_setup.header_footer_aligns = options[:align_with_margins] if options[:align_with_margins]
|
654
674
|
|
@@ -664,7 +684,7 @@ module Writexlsx
|
|
664
684
|
end
|
665
685
|
|
666
686
|
# placeholeder /&G/ の数
|
667
|
-
placeholder_count = @page_setup.header.scan(
|
687
|
+
placeholder_count = @page_setup.header.scan("&G").count
|
668
688
|
|
669
689
|
image_count = @header_images.count
|
670
690
|
|
@@ -685,7 +705,7 @@ module Writexlsx
|
|
685
705
|
@page_setup.footer = string.dup
|
686
706
|
|
687
707
|
# Replace the Excel placeholder &[Picture] with the internal &G.
|
688
|
-
@page_setup.footer = string.gsub(
|
708
|
+
@page_setup.footer = string.gsub("&[Picture]", '&G')
|
689
709
|
|
690
710
|
@page_setup.header_footer_aligns = options[:align_with_margins] if options[:align_with_margins]
|
691
711
|
|
@@ -701,7 +721,7 @@ module Writexlsx
|
|
701
721
|
end
|
702
722
|
|
703
723
|
# placeholeder /&G/ の数
|
704
|
-
placeholder_count = @page_setup.footer.scan(
|
724
|
+
placeholder_count = @page_setup.footer.scan("&G").count
|
705
725
|
|
706
726
|
image_count = @footer_images.count
|
707
727
|
|
@@ -1320,7 +1340,7 @@ module Writexlsx
|
|
1320
1340
|
# Utility method to strip equal sign and array braces from a formula
|
1321
1341
|
# and also expand out future and dynamic array formulas.
|
1322
1342
|
#
|
1323
|
-
def prepare_formula(given_formula)
|
1343
|
+
def prepare_formula(given_formula, expand_future_functions = nil)
|
1324
1344
|
# Ignore empty/null formulas.
|
1325
1345
|
return given_formula unless ptrue?(given_formula)
|
1326
1346
|
|
@@ -1331,26 +1351,46 @@ module Writexlsx
|
|
1331
1351
|
return formula if formula =~ /_xlfn\./
|
1332
1352
|
|
1333
1353
|
# Expand dynamic array formulas.
|
1334
|
-
formula = expand_formula(formula, '
|
1354
|
+
formula = expand_formula(formula, 'ANCHORARRAY\(')
|
1355
|
+
formula = expand_formula(formula, 'BYCOL\(')
|
1356
|
+
formula = expand_formula(formula, 'BYROW\(')
|
1357
|
+
formula = expand_formula(formula, 'CHOOSECOLS\(')
|
1358
|
+
formula = expand_formula(formula, 'CHOOSEROWS\(')
|
1359
|
+
formula = expand_formula(formula, 'DROP\(')
|
1360
|
+
formula = expand_formula(formula, 'EXPAND\(')
|
1361
|
+
formula = expand_formula(formula, 'FILTER\(', '._xlws')
|
1362
|
+
formula = expand_formula(formula, 'HSTACK\(')
|
1335
1363
|
formula = expand_formula(formula, 'LAMBDA\(')
|
1364
|
+
formula = expand_formula(formula, 'MAKEARRAY\(')
|
1365
|
+
formula = expand_formula(formula, 'MAP\(')
|
1366
|
+
formula = expand_formula(formula, 'RANDARRAY\(')
|
1367
|
+
formula = expand_formula(formula, 'REDUCE\(')
|
1368
|
+
formula = expand_formula(formula, 'SCAN\(')
|
1369
|
+
formula = expand_formula(formula, 'SEQUENCE\(')
|
1336
1370
|
formula = expand_formula(formula, 'SINGLE\(')
|
1371
|
+
formula = expand_formula(formula, 'SORT\(', '._xlws')
|
1337
1372
|
formula = expand_formula(formula, 'SORTBY\(')
|
1373
|
+
formula = expand_formula(formula, 'SWITCH\(')
|
1374
|
+
formula = expand_formula(formula, 'TAKE\(')
|
1375
|
+
formula = expand_formula(formula, 'TEXTSPLIT\(')
|
1376
|
+
formula = expand_formula(formula, 'TOCOL\(')
|
1377
|
+
formula = expand_formula(formula, 'TOROW\(')
|
1338
1378
|
formula = expand_formula(formula, 'UNIQUE\(')
|
1339
|
-
formula = expand_formula(formula, '
|
1379
|
+
formula = expand_formula(formula, 'VSTACK\(')
|
1380
|
+
formula = expand_formula(formula, 'WRAPCOLS\(')
|
1381
|
+
formula = expand_formula(formula, 'WRAPROWS\(')
|
1340
1382
|
formula = expand_formula(formula, 'XLOOKUP\(')
|
1341
|
-
formula = expand_formula(formula, 'SEQUENCE\(')
|
1342
|
-
formula = expand_formula(formula, 'RANDARRAY\(')
|
1343
|
-
formula = expand_formula(formula, 'SORT\(', '._xlws')
|
1344
|
-
formula = expand_formula(formula, 'ANCHORARRAY\(')
|
1345
|
-
formula = expand_formula(formula, 'FILTER\(', '._xlws')
|
1346
1383
|
|
1347
|
-
|
1384
|
+
if !@use_future_functions && !ptrue?(expand_future_functions)
|
1385
|
+
return formula
|
1386
|
+
end
|
1348
1387
|
|
1349
1388
|
# Future functions.
|
1350
1389
|
formula = expand_formula(formula, 'ACOTH\(')
|
1351
1390
|
formula = expand_formula(formula, 'ACOT\(')
|
1352
1391
|
formula = expand_formula(formula, 'AGGREGATE\(')
|
1353
1392
|
formula = expand_formula(formula, 'ARABIC\(')
|
1393
|
+
formula = expand_formula(formula, 'ARRAYTOTEXT\(')
|
1354
1394
|
formula = expand_formula(formula, 'BASE\(')
|
1355
1395
|
formula = expand_formula(formula, 'BETA.DIST\(')
|
1356
1396
|
formula = expand_formula(formula, 'BETA.INV\(')
|
@@ -1415,7 +1455,9 @@ module Writexlsx
|
|
1415
1455
|
formula = expand_formula(formula, 'IMSINH\(')
|
1416
1456
|
formula = expand_formula(formula, 'IMTAN\(')
|
1417
1457
|
formula = expand_formula(formula, 'ISFORMULA\(')
|
1458
|
+
formula = expand_formula(formula, 'ISOMITTED\(')
|
1418
1459
|
formula = expand_formula(formula, 'ISOWEEKNUM\(')
|
1460
|
+
formula = expand_formula(formula, 'LET\(')
|
1419
1461
|
formula = expand_formula(formula, 'LOGNORM.DIST\(')
|
1420
1462
|
formula = expand_formula(formula, 'LOGNORM.INV\(')
|
1421
1463
|
formula = expand_formula(formula, 'MAXIFS\(')
|
@@ -1450,24 +1492,26 @@ module Writexlsx
|
|
1450
1492
|
formula = expand_formula(formula, 'SKEW.P\(')
|
1451
1493
|
formula = expand_formula(formula, 'STDEV.P\(')
|
1452
1494
|
formula = expand_formula(formula, 'STDEV.S\(')
|
1453
|
-
formula = expand_formula(formula, 'SWITCH\(')
|
1454
1495
|
formula = expand_formula(formula, 'T.DIST.2T\(')
|
1455
1496
|
formula = expand_formula(formula, 'T.DIST.RT\(')
|
1456
1497
|
formula = expand_formula(formula, 'T.DIST\(')
|
1457
1498
|
formula = expand_formula(formula, 'T.INV.2T\(')
|
1458
1499
|
formula = expand_formula(formula, 'T.INV\(')
|
1459
1500
|
formula = expand_formula(formula, 'T.TEST\(')
|
1501
|
+
formula = expand_formula(formula, 'TEXTAFTER\(')
|
1502
|
+
formula = expand_formula(formula, 'TEXTBEFORE\(')
|
1460
1503
|
formula = expand_formula(formula, 'TEXTJOIN\(')
|
1461
1504
|
formula = expand_formula(formula, 'UNICHAR\(')
|
1462
1505
|
formula = expand_formula(formula, 'UNICODE\(')
|
1506
|
+
formula = expand_formula(formula, 'VALUETOTEXT\(')
|
1463
1507
|
formula = expand_formula(formula, 'VAR.P\(')
|
1464
1508
|
formula = expand_formula(formula, 'VAR.S\(')
|
1465
1509
|
formula = expand_formula(formula, 'WEBSERVICE\(')
|
1466
1510
|
formula = expand_formula(formula, 'WEIBULL.DIST\(')
|
1511
|
+
formula = expand_formula(formula, 'XMATCH\(')
|
1467
1512
|
formula = expand_formula(formula, 'XOR\(')
|
1468
1513
|
expand_formula(formula, 'Z.TEST\(')
|
1469
1514
|
end
|
1470
|
-
private :prepare_formula
|
1471
1515
|
|
1472
1516
|
#
|
1473
1517
|
# :call-seq:
|
@@ -1551,7 +1595,7 @@ module Writexlsx
|
|
1551
1595
|
end
|
1552
1596
|
|
1553
1597
|
# Modify the formula string, as needed.
|
1554
|
-
formula = prepare_formula(formula)
|
1598
|
+
formula = prepare_formula(formula, 1)
|
1555
1599
|
|
1556
1600
|
store_data_to_table(
|
1557
1601
|
if type == 'a'
|
@@ -2926,7 +2970,7 @@ module Writexlsx
|
|
2926
2970
|
tokens.map! do |token|
|
2927
2971
|
token.sub!(/^"/, '')
|
2928
2972
|
token.sub!(/"$/, '')
|
2929
|
-
token.gsub!(
|
2973
|
+
token.gsub!('""', '"')
|
2930
2974
|
|
2931
2975
|
# if token is number, convert to numeric.
|
2932
2976
|
if token =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
|
@@ -3208,13 +3252,13 @@ module Writexlsx
|
|
3208
3252
|
target = escape_url(url.sub(/^external:/, ''))
|
3209
3253
|
|
3210
3254
|
# Additional escape not required in worksheet hyperlinks
|
3211
|
-
target = target.gsub(
|
3255
|
+
target = target.gsub("#", '%23')
|
3212
3256
|
|
3213
3257
|
# Prefix absolute paths (not relative) with file:///
|
3214
3258
|
target = if target =~ /^\w:/ || target =~ /^\\\\/
|
3215
3259
|
"file:///#{target}"
|
3216
3260
|
else
|
3217
|
-
target.gsub(
|
3261
|
+
target.gsub("\\", '/')
|
3218
3262
|
end
|
3219
3263
|
end
|
3220
3264
|
|
@@ -3437,7 +3481,7 @@ EOS
|
|
3437
3481
|
def encode_password(password) # :nodoc:
|
3438
3482
|
hash = 0
|
3439
3483
|
|
3440
|
-
password.reverse.split(
|
3484
|
+
password.reverse.split("").each do |char|
|
3441
3485
|
hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff)
|
3442
3486
|
hash ^= char.ord
|
3443
3487
|
end
|
@@ -3559,16 +3603,27 @@ EOS
|
|
3559
3603
|
attributes << ["showOutlineSymbols", 0] if @outline_on
|
3560
3604
|
|
3561
3605
|
# Set the page view/layout mode if required.
|
3562
|
-
|
3563
|
-
|
3606
|
+
case @page_view
|
3607
|
+
when 1
|
3608
|
+
attributes << %w[view pageLayout]
|
3609
|
+
when 2
|
3610
|
+
attributes << %w[view pageBreakPreview]
|
3611
|
+
end
|
3564
3612
|
|
3565
3613
|
# Set the first visible cell.
|
3566
3614
|
attributes << ['topLeftCell', @top_left_cell] if ptrue?(@top_left_cell)
|
3567
3615
|
|
3568
3616
|
# Set the zoom level.
|
3569
3617
|
if @zoom != 100
|
3570
|
-
attributes << ['zoomScale', @zoom]
|
3571
|
-
|
3618
|
+
attributes << ['zoomScale', @zoom]
|
3619
|
+
|
3620
|
+
if @page_view == 1
|
3621
|
+
attributes << ['zoomScalePageLayoutView', @zoom]
|
3622
|
+
elsif @page_view == 2
|
3623
|
+
attributes << ['zoomScaleSheetLayoutView', @zoom]
|
3624
|
+
elsif ptrue?(@zoom_scale_normal)
|
3625
|
+
attributes << ['zoomScaleNormal', @zoom]
|
3626
|
+
end
|
3572
3627
|
end
|
3573
3628
|
|
3574
3629
|
attributes << ['workbookViewId', 0]
|
@@ -3754,9 +3809,10 @@ EOS
|
|
3754
3809
|
|
3755
3810
|
def write_cell_column_dimension(row_num) # :nodoc:
|
3756
3811
|
row = @cell_data_table[row_num]
|
3812
|
+
row_name = (row_num + 1).to_s
|
3757
3813
|
(@dim_colmin..@dim_colmax).each do |col_num|
|
3758
3814
|
if (cell = row[col_num])
|
3759
|
-
cell.write_cell(self, row_num, col_num)
|
3815
|
+
cell.write_cell(self, row_num, row_name, col_num)
|
3760
3816
|
end
|
3761
3817
|
end
|
3762
3818
|
end
|
@@ -4755,10 +4811,6 @@ EOS
|
|
4755
4811
|
ptrue?(@zoom_scale_normal)
|
4756
4812
|
end
|
4757
4813
|
|
4758
|
-
def page_view? # :nodoc:
|
4759
|
-
!!@page_view
|
4760
|
-
end
|
4761
|
-
|
4762
4814
|
def right_to_left? # :nodoc:
|
4763
4815
|
!!@right_to_left
|
4764
4816
|
end
|
data/write_xlsx.gemspec
CHANGED
@@ -20,9 +20,11 @@ Gem::Specification.new do |gem|
|
|
20
20
|
end
|
21
21
|
gem.executables = gem.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
22
22
|
gem.require_paths = ['lib']
|
23
|
+
gem.add_runtime_dependency 'nkf'
|
23
24
|
gem.add_runtime_dependency 'rubyzip', '>= 1.0.0'
|
24
25
|
gem.add_development_dependency 'byebug'
|
25
26
|
gem.add_development_dependency 'minitest'
|
27
|
+
gem.add_development_dependency 'mutex_m'
|
26
28
|
gem.add_development_dependency 'rake'
|
27
29
|
gem.add_development_dependency 'rubocop'
|
28
30
|
gem.add_development_dependency 'rubocop-minitest'
|
metadata
CHANGED
@@ -1,15 +1,29 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: write_xlsx
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.11.
|
4
|
+
version: 1.11.2
|
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-12-26 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: nkf
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
13
27
|
- !ruby/object:Gem::Dependency
|
14
28
|
name: rubyzip
|
15
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -52,6 +66,20 @@ dependencies:
|
|
52
66
|
- - ">="
|
53
67
|
- !ruby/object:Gem::Version
|
54
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: mutex_m
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
55
83
|
- !ruby/object:Gem::Dependency
|
56
84
|
name: rake
|
57
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -276,7 +304,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
276
304
|
- !ruby/object:Gem::Version
|
277
305
|
version: '0'
|
278
306
|
requirements: []
|
279
|
-
rubygems_version: 3.
|
307
|
+
rubygems_version: 3.5.3
|
280
308
|
signing_key:
|
281
309
|
specification_version: 4
|
282
310
|
summary: write_xlsx is a gem to create a new file in the Excel 2007+ XLSX format.
|