write_xlsx 1.11.0 → 1.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (39) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -1
  3. data/Changes +12 -0
  4. data/examples/shape_all.rb +1 -1
  5. data/lib/write_xlsx/chart/area.rb +1 -0
  6. data/lib/write_xlsx/chart/axis.rb +1 -0
  7. data/lib/write_xlsx/chart/bar.rb +1 -0
  8. data/lib/write_xlsx/chart/caption.rb +1 -0
  9. data/lib/write_xlsx/chart/column.rb +1 -0
  10. data/lib/write_xlsx/chart/doughnut.rb +1 -0
  11. data/lib/write_xlsx/chart/legend.rb +1 -0
  12. data/lib/write_xlsx/chart/line.rb +1 -0
  13. data/lib/write_xlsx/chart/pie.rb +15 -2
  14. data/lib/write_xlsx/chart/radar.rb +1 -0
  15. data/lib/write_xlsx/chart/scatter.rb +1 -0
  16. data/lib/write_xlsx/chart/series.rb +56 -4
  17. data/lib/write_xlsx/chart/stock.rb +1 -0
  18. data/lib/write_xlsx/chart.rb +107 -23
  19. data/lib/write_xlsx/chartsheet.rb +10 -1
  20. data/lib/write_xlsx/col_name.rb +7 -3
  21. data/lib/write_xlsx/colors.rb +20 -19
  22. data/lib/write_xlsx/format.rb +10 -8
  23. data/lib/write_xlsx/package/app.rb +9 -5
  24. data/lib/write_xlsx/package/comments.rb +2 -1
  25. data/lib/write_xlsx/package/conditional_format.rb +6 -6
  26. data/lib/write_xlsx/package/packager.rb +2 -3
  27. data/lib/write_xlsx/package/styles.rb +11 -13
  28. data/lib/write_xlsx/package/table.rb +74 -20
  29. data/lib/write_xlsx/package/xml_writer_simple.rb +32 -44
  30. data/lib/write_xlsx/sheets.rb +6 -2
  31. data/lib/write_xlsx/sparkline.rb +2 -2
  32. data/lib/write_xlsx/utility.rb +14 -12
  33. data/lib/write_xlsx/version.rb +1 -1
  34. data/lib/write_xlsx/workbook.rb +2 -3
  35. data/lib/write_xlsx/worksheet/cell_data.rb +17 -18
  36. data/lib/write_xlsx/worksheet/hyperlink.rb +2 -2
  37. data/lib/write_xlsx/worksheet.rb +90 -39
  38. data/write_xlsx.gemspec +2 -0
  39. metadata +31 -3
@@ -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)
@@ -23,6 +23,7 @@ module Writexlsx
23
23
 
24
24
  MAX_DIGIT_WIDTH = 7 # For Calabri 11. # :nodoc:
25
25
  PADDING = 5 # :nodoc:
26
+ COLINFO = Struct.new('ColInfo', :width, :format, :hidden, :level, :collapsed, :autofit)
26
27
 
27
28
  attr_reader :index # :nodoc:
28
29
  attr_reader :charts, :images, :tables, :shapes, :drawings # :nodoc:
@@ -227,15 +228,26 @@ module Writexlsx
227
228
  #
228
229
  # Hide this worksheet.
229
230
  #
230
- def hide
231
- @hidden = true
231
+ def hide(hidden = :hidden)
232
+ @hidden = hidden
232
233
  @selected = false
233
234
  @workbook.activesheet = 0 if @workbook.activesheet == @index
234
235
  @workbook.firstsheet = 0 if @workbook.firstsheet == @index
235
236
  end
236
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
+
237
245
  def hidden? # :nodoc:
238
- @hidden
246
+ @hidden == :hidden
247
+ end
248
+
249
+ def very_hidden? # :nodoc:
250
+ @hidden == :very_hidden
239
251
  end
240
252
 
241
253
  #
@@ -270,7 +282,7 @@ module Writexlsx
270
282
  if range.nil?
271
283
  raise "The range must be defined in unprotect_range())\n"
272
284
  else
273
- range = range.gsub(/\$/, "")
285
+ range = range.gsub("$", "")
274
286
  range = range.sub(/^=/, "")
275
287
  @num_protected_ranges += 1
276
288
  end
@@ -357,8 +369,7 @@ module Writexlsx
357
369
  # Store the column data based on the first column. Padded for sorting.
358
370
  (firstcol..lastcol).each do |col|
359
371
  @col_info[col] =
360
- Struct.new('ColInfo', :width, :format, :hidden, :level, :collapsed, :autofit)
361
- .new(width, format, hidden, level, collapsed, autofit)
372
+ COLINFO.new(width, format, hidden, level, collapsed, autofit)
362
373
  end
363
374
 
364
375
  # Store the column change to allow optimisations.
@@ -497,8 +508,7 @@ module Writexlsx
497
508
  @col_info[col_num].autofit = 1
498
509
  else
499
510
  @col_info[col_num] =
500
- Struct.new('ColInfo', :width, :format, :hidden, :level, :collapsed, :autofit)
501
- .new(width, nil, 0, 0, 0, 1)
511
+ COLINFO.new(width, nil, 0, 0, 0, 1)
502
512
  end
503
513
  end
504
514
  end
@@ -613,8 +623,17 @@ module Writexlsx
613
623
  #
614
624
  # This method is used to display the worksheet in "Page View/Layout" mode.
615
625
  #
616
- def set_page_view(flag = true)
617
- @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
618
637
  end
619
638
 
620
639
  #
@@ -649,7 +668,7 @@ module Writexlsx
649
668
  raise 'Header string must be less than 255 characters' if string.length > 255
650
669
 
651
670
  # Replace the Excel placeholder &[Picture] with the internal &G.
652
- @page_setup.header = string.gsub(/&\[Picture\]/, '&G')
671
+ @page_setup.header = string.gsub("&[Picture]", '&G')
653
672
 
654
673
  @page_setup.header_footer_aligns = options[:align_with_margins] if options[:align_with_margins]
655
674
 
@@ -665,7 +684,7 @@ module Writexlsx
665
684
  end
666
685
 
667
686
  # placeholeder /&G/ の数
668
- placeholder_count = @page_setup.header.scan(/&G/).count
687
+ placeholder_count = @page_setup.header.scan("&G").count
669
688
 
670
689
  image_count = @header_images.count
671
690
 
@@ -686,7 +705,7 @@ module Writexlsx
686
705
  @page_setup.footer = string.dup
687
706
 
688
707
  # Replace the Excel placeholder &[Picture] with the internal &G.
689
- @page_setup.footer = string.gsub(/&\[Picture\]/, '&G')
708
+ @page_setup.footer = string.gsub("&[Picture]", '&G')
690
709
 
691
710
  @page_setup.header_footer_aligns = options[:align_with_margins] if options[:align_with_margins]
692
711
 
@@ -702,7 +721,7 @@ module Writexlsx
702
721
  end
703
722
 
704
723
  # placeholeder /&G/ の数
705
- placeholder_count = @page_setup.footer.scan(/&G/).count
724
+ placeholder_count = @page_setup.footer.scan("&G").count
706
725
 
707
726
  image_count = @footer_images.count
708
727
 
@@ -1321,7 +1340,7 @@ module Writexlsx
1321
1340
  # Utility method to strip equal sign and array braces from a formula
1322
1341
  # and also expand out future and dynamic array formulas.
1323
1342
  #
1324
- def prepare_formula(given_formula)
1343
+ def prepare_formula(given_formula, expand_future_functions = nil)
1325
1344
  # Ignore empty/null formulas.
1326
1345
  return given_formula unless ptrue?(given_formula)
1327
1346
 
@@ -1332,26 +1351,46 @@ module Writexlsx
1332
1351
  return formula if formula =~ /_xlfn\./
1333
1352
 
1334
1353
  # Expand dynamic array formulas.
1335
- 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\(')
1336
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\(')
1337
1370
  formula = expand_formula(formula, 'SINGLE\(')
1371
+ formula = expand_formula(formula, 'SORT\(', '._xlws')
1338
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\(')
1339
1378
  formula = expand_formula(formula, 'UNIQUE\(')
1340
- formula = expand_formula(formula, 'XMATCH\(')
1379
+ formula = expand_formula(formula, 'VSTACK\(')
1380
+ formula = expand_formula(formula, 'WRAPCOLS\(')
1381
+ formula = expand_formula(formula, 'WRAPROWS\(')
1341
1382
  formula = expand_formula(formula, 'XLOOKUP\(')
1342
- formula = expand_formula(formula, 'SEQUENCE\(')
1343
- formula = expand_formula(formula, 'RANDARRAY\(')
1344
- formula = expand_formula(formula, 'SORT\(', '._xlws')
1345
- formula = expand_formula(formula, 'ANCHORARRAY\(')
1346
- formula = expand_formula(formula, 'FILTER\(', '._xlws')
1347
1383
 
1348
- return formula unless @use_future_functions
1384
+ if !@use_future_functions && !ptrue?(expand_future_functions)
1385
+ return formula
1386
+ end
1349
1387
 
1350
1388
  # Future functions.
1351
1389
  formula = expand_formula(formula, 'ACOTH\(')
1352
1390
  formula = expand_formula(formula, 'ACOT\(')
1353
1391
  formula = expand_formula(formula, 'AGGREGATE\(')
1354
1392
  formula = expand_formula(formula, 'ARABIC\(')
1393
+ formula = expand_formula(formula, 'ARRAYTOTEXT\(')
1355
1394
  formula = expand_formula(formula, 'BASE\(')
1356
1395
  formula = expand_formula(formula, 'BETA.DIST\(')
1357
1396
  formula = expand_formula(formula, 'BETA.INV\(')
@@ -1416,7 +1455,9 @@ module Writexlsx
1416
1455
  formula = expand_formula(formula, 'IMSINH\(')
1417
1456
  formula = expand_formula(formula, 'IMTAN\(')
1418
1457
  formula = expand_formula(formula, 'ISFORMULA\(')
1458
+ formula = expand_formula(formula, 'ISOMITTED\(')
1419
1459
  formula = expand_formula(formula, 'ISOWEEKNUM\(')
1460
+ formula = expand_formula(formula, 'LET\(')
1420
1461
  formula = expand_formula(formula, 'LOGNORM.DIST\(')
1421
1462
  formula = expand_formula(formula, 'LOGNORM.INV\(')
1422
1463
  formula = expand_formula(formula, 'MAXIFS\(')
@@ -1451,24 +1492,26 @@ module Writexlsx
1451
1492
  formula = expand_formula(formula, 'SKEW.P\(')
1452
1493
  formula = expand_formula(formula, 'STDEV.P\(')
1453
1494
  formula = expand_formula(formula, 'STDEV.S\(')
1454
- formula = expand_formula(formula, 'SWITCH\(')
1455
1495
  formula = expand_formula(formula, 'T.DIST.2T\(')
1456
1496
  formula = expand_formula(formula, 'T.DIST.RT\(')
1457
1497
  formula = expand_formula(formula, 'T.DIST\(')
1458
1498
  formula = expand_formula(formula, 'T.INV.2T\(')
1459
1499
  formula = expand_formula(formula, 'T.INV\(')
1460
1500
  formula = expand_formula(formula, 'T.TEST\(')
1501
+ formula = expand_formula(formula, 'TEXTAFTER\(')
1502
+ formula = expand_formula(formula, 'TEXTBEFORE\(')
1461
1503
  formula = expand_formula(formula, 'TEXTJOIN\(')
1462
1504
  formula = expand_formula(formula, 'UNICHAR\(')
1463
1505
  formula = expand_formula(formula, 'UNICODE\(')
1506
+ formula = expand_formula(formula, 'VALUETOTEXT\(')
1464
1507
  formula = expand_formula(formula, 'VAR.P\(')
1465
1508
  formula = expand_formula(formula, 'VAR.S\(')
1466
1509
  formula = expand_formula(formula, 'WEBSERVICE\(')
1467
1510
  formula = expand_formula(formula, 'WEIBULL.DIST\(')
1511
+ formula = expand_formula(formula, 'XMATCH\(')
1468
1512
  formula = expand_formula(formula, 'XOR\(')
1469
1513
  expand_formula(formula, 'Z.TEST\(')
1470
1514
  end
1471
- private :prepare_formula
1472
1515
 
1473
1516
  #
1474
1517
  # :call-seq:
@@ -1552,7 +1595,7 @@ module Writexlsx
1552
1595
  end
1553
1596
 
1554
1597
  # Modify the formula string, as needed.
1555
- formula = prepare_formula(formula)
1598
+ formula = prepare_formula(formula, 1)
1556
1599
 
1557
1600
  store_data_to_table(
1558
1601
  if type == 'a'
@@ -2927,7 +2970,7 @@ module Writexlsx
2927
2970
  tokens.map! do |token|
2928
2971
  token.sub!(/^"/, '')
2929
2972
  token.sub!(/"$/, '')
2930
- token.gsub!(/""/, '"')
2973
+ token.gsub!('""', '"')
2931
2974
 
2932
2975
  # if token is number, convert to numeric.
2933
2976
  if token =~ /^([+-]?)(?=\d|\.\d)\d*(\.\d*)?([Ee]([+-]?\d+))?$/
@@ -3209,13 +3252,13 @@ module Writexlsx
3209
3252
  target = escape_url(url.sub(/^external:/, ''))
3210
3253
 
3211
3254
  # Additional escape not required in worksheet hyperlinks
3212
- target = target.gsub(/#/, '%23')
3255
+ target = target.gsub("#", '%23')
3213
3256
 
3214
3257
  # Prefix absolute paths (not relative) with file:///
3215
3258
  target = if target =~ /^\w:/ || target =~ /^\\\\/
3216
3259
  "file:///#{target}"
3217
3260
  else
3218
- target.gsub(/\\/, '/')
3261
+ target.gsub("\\", '/')
3219
3262
  end
3220
3263
  end
3221
3264
 
@@ -3438,7 +3481,7 @@ EOS
3438
3481
  def encode_password(password) # :nodoc:
3439
3482
  hash = 0
3440
3483
 
3441
- password.reverse.split(//).each do |char|
3484
+ password.reverse.split("").each do |char|
3442
3485
  hash = ((hash >> 14) & 0x01) | ((hash << 1) & 0x7fff)
3443
3486
  hash ^= char.ord
3444
3487
  end
@@ -3560,16 +3603,27 @@ EOS
3560
3603
  attributes << ["showOutlineSymbols", 0] if @outline_on
3561
3604
 
3562
3605
  # Set the page view/layout mode if required.
3563
- # TODO. Add pageBreakPreview mode when requested.
3564
- 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
3565
3612
 
3566
3613
  # Set the first visible cell.
3567
3614
  attributes << ['topLeftCell', @top_left_cell] if ptrue?(@top_left_cell)
3568
3615
 
3569
3616
  # Set the zoom level.
3570
3617
  if @zoom != 100
3571
- attributes << ['zoomScale', @zoom] unless page_view?
3572
- 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
3573
3627
  end
3574
3628
 
3575
3629
  attributes << ['workbookViewId', 0]
@@ -3755,9 +3809,10 @@ EOS
3755
3809
 
3756
3810
  def write_cell_column_dimension(row_num) # :nodoc:
3757
3811
  row = @cell_data_table[row_num]
3812
+ row_name = (row_num + 1).to_s
3758
3813
  (@dim_colmin..@dim_colmax).each do |col_num|
3759
3814
  if (cell = row[col_num])
3760
- cell.write_cell(self, row_num, col_num)
3815
+ cell.write_cell(self, row_num, row_name, col_num)
3761
3816
  end
3762
3817
  end
3763
3818
  end
@@ -4756,10 +4811,6 @@ EOS
4756
4811
  ptrue?(@zoom_scale_normal)
4757
4812
  end
4758
4813
 
4759
- def page_view? # :nodoc:
4760
- !!@page_view
4761
- end
4762
-
4763
4814
  def right_to_left? # :nodoc:
4764
4815
  !!@right_to_left
4765
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.0
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-05-06 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.