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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: cabafeb058f3742956ec06251cab5ecf67d9b76cd5db3ec659e2e4184d2c1483
4
- data.tar.gz: 95a68e0390bff44e03dc8577b31162c1d1c2cb80d77f3943947e1114327afb01
3
+ metadata.gz: 9dae4b31e210af6cea2f7df87d92e29d48e8b36d7408cfc0c542b4aa0fe4ea22
4
+ data.tar.gz: 3c1be9afcd157d1c7a4aabf6f0688b049a80699133e6a3d31d17874bce453b5a
5
5
  SHA512:
6
- metadata.gz: 70a98e3ffc2be69574805f72a63678b2023cc3aef9a1c1a97c5f8a13de80de29c641c573d8c8c9bd7d33da088827a15fb6feb3b4c7591b50ffb26cb321591b49
7
- data.tar.gz: 1d387aa195a7a35f0b664e4ff155ca71de765ad6ae886df66debc9063d1fea8c4c905ab10a7aef735d69813b79faa1d6e7ded96e70ce23a75df56e5f172b1648
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
 
@@ -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(/\t/)
221
+ sheet, name = line.split("\t")
222
222
  if last_sheet != sheet
223
223
  worksheet = workbook.add_worksheet(sheet)
224
224
  row = 2
@@ -123,8 +123,7 @@ module Writexlsx
123
123
  # Write the <c:legend> element.
124
124
  #
125
125
  def write_legend
126
- position = @legend.position
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',
@@ -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
- write_ext_lst(series.inverted_color) if series.inverted_color
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 write_ext_lst(color)
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
- # Write the <c:showLeaderLines> element.
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
- @writer.empty_tag('c:showLeaderLines', [['val', 1]])
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
- [@external_drawing_links]
194
+ [
195
+ @external_drawing_links,
196
+ @external_vml_links
197
+ ]
189
198
  end
190
199
 
191
200
  private
@@ -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] = col_str_build(col) unless @col_str_table[col]
15
- @col_str_table[col]
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
@@ -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
- return 0x00 if color_code =~ /\D/
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 { |s| s.is_chartsheet? }.count
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
- .reject { |sheet| sheet.is_chartsheet? }
61
- .each { |sheet| add_part_name(sheet.name) }
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
- .select { |sheet| sheet.is_chartsheet? }
67
- .each { |sheet| add_part_name(sheet.name) }
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', (value || 10)]
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
- overrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
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 overrite_the_defaults_with_any_use_defined_values(col_id, col_data, col_num)
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, col_num, formula, format)
256
+ def handle_the_column_formula(col_data, _col_num, formula, _format)
238
257
  return unless formula
239
258
 
240
- col_data.formula = formula.sub(/^=/, '').gsub(/@/, '[#This Row],')
259
+ formula = formula.sub(/^=/, '').gsub(/@/, '[#This Row],')
241
260
 
242
- (@first_data_row..@last_data_row).each do |row|
243
- @worksheet.write_formula(row, col_num, col_data.formula, format)
244
- end
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
- function = user_data[:total_function].downcase.gsub(/[_\s]/, '')
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
- function = 'countNums' if function == 'countnums'
251
- function = 'stdDev' if function == 'stddev'
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
- col_data.total_function = function
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
- formula = table_function_to_formula(function, col_data.name)
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
- # Write the calculatedColumnFormula element.
401
- write_calculated_column_formula(col_data.formula)
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
- result = @tag_start_cache[tag]
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
- result = "<#{tag}#{key_vals(attr)}>"
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
- result = @tag_end_cache[tag]
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 empty_tag_encoded(tag, attr = [])
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
- .inject('') { |str, attr| str + key_val(attr.first, escape_attributes(attr.last)) }
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.to_s =~ /["&<>\n]/
127
+ return str unless str.respond_to?(:match) && str =~ /["&<>\n]/
140
128
 
141
129
  str
142
- .gsub(/&/, "&amp;")
143
- .gsub(/"/, "&quot;")
144
- .gsub(/</, "&lt;")
145
- .gsub(/>/, "&gt;")
146
- .gsub(/\n/, "&#xA;")
130
+ .gsub("&", "&amp;")
131
+ .gsub('"', "&quot;")
132
+ .gsub("<", "&lt;")
133
+ .gsub(">", "&gt;")
134
+ .gsub("\n", "&#xA;")
147
135
  end
148
136
 
149
137
  def escape_data(str = '')
150
- if str.to_s =~ /[&<>]/
151
- str.gsub(/&/, '&amp;')
152
- .gsub(/</, '&lt;')
153
- .gsub(/>/, '&gt;')
138
+ if str.respond_to?(:match) && str =~ /[&<>]/
139
+ str.gsub("&", '&amp;')
140
+ .gsub("<", '&lt;')
141
+ .gsub(">", '&gt;')
154
142
  else
155
143
  str
156
144
  end
@@ -252,9 +252,13 @@ module Writexlsx
252
252
  ['sheetId', sheet_id]
253
253
  ]
254
254
 
255
- attributes << %w[state hidden] if sheet.hidden?
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.empty_tag_encoded('sheet', attributes)
261
+ writer.empty_tag('sheet', attributes)
258
262
  end
259
263
  end
260
264
  end
@@ -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]
@@ -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(row, col, row_absolute = false, col_absolute = false)
35
- row += 1 # Change from 0-indexed to 1 indexed.
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)}#{row}"
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(//).each { |char| length += CHAR_WIDTHS[char] || 8 }
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(/T/)
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? ? 4 : 0
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(/%/, "%25")
253
+ url = url.gsub("%", "%25")
252
254
 
253
255
  # Escape whitespae in URL.
254
256
  url = url.gsub(/[\s\x00]/, '%20')
@@ -1,3 +1,3 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- WriteXLSX_VERSION = "1.11.1"
3
+ WriteXLSX_VERSION = "1.11.2"
@@ -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(row, col)]
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(/#/, 2)
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(/#/, 2)
109
+ url, url_str = url.split("#", 2)
110
110
 
111
111
  # Escape URL unless it looks already escaped.
112
112
  url = escape_url(url)
@@ -228,15 +228,26 @@ module Writexlsx
228
228
  #
229
229
  # Hide this worksheet.
230
230
  #
231
- def hide
232
- @hidden = true
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 = true)
616
- @page_view = !!flag
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(/&\[Picture\]/, '&G')
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(/&G/).count
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(/&\[Picture\]/, '&G')
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(/&G/).count
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, 'LET\(')
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, 'XMATCH\(')
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
- return formula unless @use_future_functions
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(/#/, '%23')
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(//).each do |char|
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
- # TODO. Add pageBreakPreview mode when requested.
3563
- attributes << %w[view pageLayout] if page_view?
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] unless page_view?
3571
- attributes << ['zoomScaleNormal', @zoom] if zoom_scale_normal?
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.1
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-08-08 00:00:00.000000000 Z
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.4.10
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.