write_xlsx 1.04.0 → 1.08.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (123) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +0 -1
  3. data/Changes +50 -0
  4. data/README.md +1 -1
  5. data/examples/chart_data_labels.rb +320 -0
  6. data/examples/ignore_errors.rb +39 -0
  7. data/ignore_errors.xlsx +0 -0
  8. data/lib/write_xlsx/chart/series.rb +100 -0
  9. data/lib/write_xlsx/chart.rb +155 -33
  10. data/lib/write_xlsx/drawing.rb +80 -17
  11. data/lib/write_xlsx/package/app.rb +3 -3
  12. data/lib/write_xlsx/package/conditional_format.rb +2 -8
  13. data/lib/write_xlsx/package/packager.rb +1 -0
  14. data/lib/write_xlsx/package/styles.rb +16 -3
  15. data/lib/write_xlsx/package/table.rb +8 -0
  16. data/lib/write_xlsx/utility.rb +9 -3
  17. data/lib/write_xlsx/version.rb +1 -1
  18. data/lib/write_xlsx/workbook.rb +23 -0
  19. data/lib/write_xlsx/worksheet/data_validation.rb +1 -6
  20. data/lib/write_xlsx/worksheet.rb +160 -37
  21. data/test/drawing/{test_write_ext.rb → test_write_xdr_ext.rb} +2 -2
  22. data/test/perl_output/chart_data_labels.xlsx +0 -0
  23. data/test/perl_output/ignore_errors.xlsx +0 -0
  24. data/test/regression/test_array_formula04.rb +31 -0
  25. data/test/regression/test_chart_crossing01.rb +1 -1
  26. data/test/regression/test_chart_crossing05.rb +46 -0
  27. data/test/regression/test_chart_crossing06.rb +46 -0
  28. data/test/regression/test_chart_data_labels26.rb +44 -0
  29. data/test/regression/test_chart_data_labels27.rb +44 -0
  30. data/test/regression/test_chart_data_labels28.rb +52 -0
  31. data/test/regression/test_chart_data_labels29.rb +43 -0
  32. data/test/regression/test_chart_data_labels30.rb +46 -0
  33. data/test/regression/test_chart_data_labels31.rb +49 -0
  34. data/test/regression/test_chart_data_labels32.rb +54 -0
  35. data/test/regression/test_chart_data_labels33.rb +52 -0
  36. data/test/regression/test_chart_data_labels34.rb +54 -0
  37. data/test/regression/test_chart_data_labels35.rb +46 -0
  38. data/test/regression/test_chart_data_labels36.rb +54 -0
  39. data/test/regression/test_chart_data_labels37.rb +51 -0
  40. data/test/regression/test_chart_data_labels38.rb +54 -0
  41. data/test/regression/test_chart_data_labels39.rb +53 -0
  42. data/test/regression/test_chart_data_labels40.rb +53 -0
  43. data/test/regression/test_chart_data_labels41.rb +54 -0
  44. data/test/regression/test_chart_data_labels42.rb +58 -0
  45. data/test/regression/test_chart_data_labels43.rb +58 -0
  46. data/test/regression/test_chart_data_labels44.rb +56 -0
  47. data/test/regression/test_chart_data_labels45.rb +57 -0
  48. data/test/regression/test_chart_data_labels46.rb +61 -0
  49. data/test/regression/test_chart_data_labels47.rb +61 -0
  50. data/test/regression/test_chart_data_labels48.rb +55 -0
  51. data/test/regression/test_chart_data_labels49.rb +55 -0
  52. data/test/regression/test_chart_data_labels50.rb +57 -0
  53. data/test/regression/test_format16.rb +24 -0
  54. data/test/regression/test_format17.rb +24 -0
  55. data/test/regression/test_header04.rb +30 -0
  56. data/test/regression/test_hyperlink50.rb +27 -0
  57. data/test/regression/test_hyperlink51.rb +27 -0
  58. data/test/regression/test_ignore_error01.rb +23 -0
  59. data/test/regression/test_ignore_error02.rb +24 -0
  60. data/test/regression/test_ignore_error03.rb +26 -0
  61. data/test/regression/test_ignore_error04.rb +26 -0
  62. data/test/regression/test_ignore_error05.rb +32 -0
  63. data/test/regression/test_ignore_error06.rb +32 -0
  64. data/test/regression/test_image52.rb +26 -0
  65. data/test/regression/test_image53.rb +26 -0
  66. data/test/regression/test_image54.rb +26 -0
  67. data/test/regression/test_image55.rb +27 -0
  68. data/test/regression/test_protect04.rb +32 -0
  69. data/test/regression/test_protect05.rb +35 -0
  70. data/test/regression/test_protect06.rb +35 -0
  71. data/test/regression/test_protect07.rb +23 -0
  72. data/test/regression/test_table26.rb +38 -0
  73. data/test/regression/xlsx_files/array_formula04.xlsx +0 -0
  74. data/test/regression/xlsx_files/chart_crossing05.xlsx +0 -0
  75. data/test/regression/xlsx_files/chart_crossing06.xlsx +0 -0
  76. data/test/regression/xlsx_files/chart_data_labels26.xlsx +0 -0
  77. data/test/regression/xlsx_files/chart_data_labels27.xlsx +0 -0
  78. data/test/regression/xlsx_files/chart_data_labels28.xlsx +0 -0
  79. data/test/regression/xlsx_files/chart_data_labels29.xlsx +0 -0
  80. data/test/regression/xlsx_files/chart_data_labels30.xlsx +0 -0
  81. data/test/regression/xlsx_files/chart_data_labels31.xlsx +0 -0
  82. data/test/regression/xlsx_files/chart_data_labels32.xlsx +0 -0
  83. data/test/regression/xlsx_files/chart_data_labels33.xlsx +0 -0
  84. data/test/regression/xlsx_files/chart_data_labels34.xlsx +0 -0
  85. data/test/regression/xlsx_files/chart_data_labels35.xlsx +0 -0
  86. data/test/regression/xlsx_files/chart_data_labels36.xlsx +0 -0
  87. data/test/regression/xlsx_files/chart_data_labels37.xlsx +0 -0
  88. data/test/regression/xlsx_files/chart_data_labels38.xlsx +0 -0
  89. data/test/regression/xlsx_files/chart_data_labels39.xlsx +0 -0
  90. data/test/regression/xlsx_files/chart_data_labels40.xlsx +0 -0
  91. data/test/regression/xlsx_files/chart_data_labels41.xlsx +0 -0
  92. data/test/regression/xlsx_files/chart_data_labels42.xlsx +0 -0
  93. data/test/regression/xlsx_files/chart_data_labels43.xlsx +0 -0
  94. data/test/regression/xlsx_files/chart_data_labels44.xlsx +0 -0
  95. data/test/regression/xlsx_files/chart_data_labels45.xlsx +0 -0
  96. data/test/regression/xlsx_files/chart_data_labels46.xlsx +0 -0
  97. data/test/regression/xlsx_files/chart_data_labels47.xlsx +0 -0
  98. data/test/regression/xlsx_files/chart_data_labels48.xlsx +0 -0
  99. data/test/regression/xlsx_files/chart_data_labels49.xlsx +0 -0
  100. data/test/regression/xlsx_files/chart_data_labels50.xlsx +0 -0
  101. data/test/regression/xlsx_files/format16.xlsx +0 -0
  102. data/test/regression/xlsx_files/format17.xlsx +0 -0
  103. data/test/regression/xlsx_files/header04.xlsx +0 -0
  104. data/test/regression/xlsx_files/hyperlink50.xlsx +0 -0
  105. data/test/regression/xlsx_files/hyperlink51.xlsx +0 -0
  106. data/test/regression/xlsx_files/ignore_error01.xlsx +0 -0
  107. data/test/regression/xlsx_files/ignore_error02.xlsx +0 -0
  108. data/test/regression/xlsx_files/ignore_error03.xlsx +0 -0
  109. data/test/regression/xlsx_files/ignore_error04.xlsx +0 -0
  110. data/test/regression/xlsx_files/ignore_error05.xlsx +0 -0
  111. data/test/regression/xlsx_files/ignore_error06.xlsx +0 -0
  112. data/test/regression/xlsx_files/image52.xlsx +0 -0
  113. data/test/regression/xlsx_files/image53.xlsx +0 -0
  114. data/test/regression/xlsx_files/image54.xlsx +0 -0
  115. data/test/regression/xlsx_files/image55.xlsx +0 -0
  116. data/test/regression/xlsx_files/protect04.xlsx +0 -0
  117. data/test/regression/xlsx_files/protect05.xlsx +0 -0
  118. data/test/regression/xlsx_files/protect06.xlsx +0 -0
  119. data/test/regression/xlsx_files/protect07.xlsx +0 -0
  120. data/test/regression/xlsx_files/table26.xlsx +0 -0
  121. data/test/test_example_match.rb +345 -1
  122. data/test/utility/test_range.rb +20 -0
  123. metadata +209 -8
@@ -52,6 +52,7 @@ module Writexlsx
52
52
  attr_reader :max_url_length # :nodoc:
53
53
  attr_reader :strings_to_urls # :nodoc:
54
54
  attr_reader :default_url_format # :nodoc:
55
+ attr_reader :read_only # :nodoc:
55
56
 
56
57
  #
57
58
  # A new Excel workbook is created using the +new+ constructor
@@ -133,6 +134,7 @@ module Writexlsx
133
134
 
134
135
  @max_url_length = 2079
135
136
  @has_comments = false
137
+ @read_only = 0
136
138
  if options[:max_url_length]
137
139
  @max_url_length = options[:max_url_length]
138
140
 
@@ -292,6 +294,9 @@ module Writexlsx
292
294
  # Write the XLSX file version.
293
295
  write_file_version
294
296
 
297
+ # Write the fileSharing element.
298
+ write_file_sharing
299
+
295
300
  # Write the workbook properties.
296
301
  write_workbook_pr
297
302
 
@@ -954,6 +959,13 @@ module Writexlsx
954
959
  end
955
960
  end
956
961
 
962
+ #
963
+ # Set the Excel "Read-only recommended" save option.
964
+ #
965
+ def read_only_recommended
966
+ @read_only = 2
967
+ end
968
+
957
969
  #
958
970
  # set_calc_mode()
959
971
  #
@@ -1311,6 +1323,17 @@ module Writexlsx
1311
1323
  @writer.empty_tag('fileVersion', attributes)
1312
1324
  end
1313
1325
 
1326
+ #
1327
+ # Write the <fileSharing> element.
1328
+ #
1329
+ def write_file_sharing
1330
+ return if !ptrue?(@read_only)
1331
+
1332
+ attributes = []
1333
+ attributes << ['readOnlyRecommended', 1]
1334
+ @writer.empty_tag('fileSharing', attributes)
1335
+ end
1336
+
1314
1337
  def write_workbook_pr #:nodoc:
1315
1338
  attributes = []
1316
1339
  attributes << ['codeName', @vba_codename] if ptrue?(@vba_codename)
@@ -138,12 +138,7 @@ module Writexlsx
138
138
  row_first, row_last = row_last, row_first if row_first > row_last
139
139
  col_first, col_last = col_last, col_first if col_first > col_last
140
140
 
141
- # If the first and last cell are the same write a single cell.
142
- if row_first == row_last && col_first == col_last
143
- sqref += xl_rowcol_to_cell(row_first, col_first)
144
- else
145
- sqref += xl_range(row_first, row_last, col_first, col_last)
146
- end
141
+ sqref += xl_range(row_first, row_last, col_first, col_last)
147
142
  end
148
143
 
149
144
  if @validate != 'none'
@@ -381,6 +381,7 @@ module Writexlsx
381
381
  @comments = Package::Comments.new(self)
382
382
  @buttons_array = []
383
383
  @header_images_array = []
384
+ @ignore_errors = nil
384
385
 
385
386
  @validations = []
386
387
 
@@ -388,6 +389,9 @@ module Writexlsx
388
389
  @data_bars_2010 = []
389
390
  @dxf_priority = 1
390
391
 
392
+ @protected_ranges = []
393
+ @num_protected_ranges = 0
394
+
391
395
  if excel2003_style?
392
396
  @original_row_height = 12.75
393
397
  @default_row_height = 12.75
@@ -414,6 +418,7 @@ module Writexlsx
414
418
  write_cols
415
419
  write_sheet_data
416
420
  write_sheet_protection
421
+ write_protected_ranges
417
422
  # write_sheet_calc_pr
418
423
  write_phonetic_pr if excel2003_style?
419
424
  write_auto_filter
@@ -427,6 +432,7 @@ module Writexlsx
427
432
  write_header_footer
428
433
  write_row_breaks
429
434
  write_col_breaks
435
+ write_ignored_errors
430
436
  write_drawings
431
437
  write_legacy_drawing
432
438
  write_legacy_drawing_hf
@@ -616,7 +622,25 @@ module Writexlsx
616
622
 
617
623
  # Set the password after the user defined values.
618
624
  @protect[:password] =
619
- sprintf("%X", encode_password(password)) if password && password != ''
625
+ encode_password(password) if password && password != ''
626
+ end
627
+
628
+ #
629
+ # Unprotect ranges within a protected worksheet.
630
+ #
631
+ def unprotect_range(range, range_name = nil, password = nil)
632
+ if range.nil?
633
+ raise "The range must be defined in unprotect_range())\n"
634
+ else
635
+ range.gsub!(/\$/, "")
636
+ range.sub!(/^=/, "")
637
+ @num_protected_ranges += 1
638
+ end
639
+
640
+ range_name ||= "Range#{@num_protected_ranges}"
641
+ password &&= encode_password(password)
642
+
643
+ @protected_ranges << [range, range_name, password]
620
644
  end
621
645
 
622
646
  def protect_default_settings # :nodoc:
@@ -818,12 +842,7 @@ module Writexlsx
818
842
  row_first, row_last = row_last, row_first if row_first > row_last
819
843
  col_first, col_last = col_last, col_first if col_first > col_last
820
844
 
821
- # If the first and last cell are the same write a single cell.
822
- if row_first == row_last && col_first == col_last
823
- sqref = active_cell
824
- else
825
- sqref = xl_range(row_first, row_last, col_first, col_last)
826
- end
845
+ sqref = xl_range(row_first, row_last, col_first, col_last)
827
846
  else # Single cell selection.
828
847
  sqref = active_cell
829
848
  end
@@ -1207,14 +1226,10 @@ module Writexlsx
1207
1226
  # distribution.
1208
1227
  #
1209
1228
  def set_header(string = '', margin = 0.3, options = {})
1210
- raise 'Header string must be less than 255 characters' if string.length >= 255
1229
+ raise 'Header string must be less than 255 characters' if string.length > 255
1211
1230
  # Replace the Excel placeholder &[Picture] with the internal &G.
1212
1231
  @page_setup.header = string.gsub(/&\[Picture\]/, '&G')
1213
1232
 
1214
- if string.size >= 255
1215
- raise 'Header string must be less than 255 characters'
1216
- end
1217
-
1218
1233
  if options[:align_with_margins]
1219
1234
  @page_setup.header_footer_aligns = options[:align_with_margins]
1220
1235
  end
@@ -1255,17 +1270,13 @@ module Writexlsx
1255
1270
  # The syntax of the set_footer() method is the same as set_header()
1256
1271
  #
1257
1272
  def set_footer(string = '', margin = 0.3, options = {})
1258
- raise 'Footer string must be less than 255 characters' if string.length >= 255
1273
+ raise 'Footer string must be less than 255 characters' if string.length > 255
1259
1274
 
1260
1275
  @page_setup.footer = string.dup
1261
1276
 
1262
1277
  # Replace the Excel placeholder &[Picture] with the internal &G.
1263
1278
  @page_setup.footer = string.gsub(/&\[Picture\]/, '&G')
1264
1279
 
1265
- if string.size >= 255
1266
- raise 'Header string must be less than 255 characters'
1267
- end
1268
-
1269
1280
  if options[:align_with_margins]
1270
1281
  @page_setup.header_footer_aligns = options[:align_with_margins]
1271
1282
  end
@@ -2514,7 +2525,9 @@ module Writexlsx
2514
2525
  col1, col2 = col2, col1 if col1 > col2
2515
2526
 
2516
2527
  # Check that row and col are valid and store max and min values
2528
+ check_dimensions(row1, col1)
2517
2529
  check_dimensions(row2, col2)
2530
+ store_row_col_max_min_values(row1, col1)
2518
2531
  store_row_col_max_min_values(row2, col2)
2519
2532
 
2520
2533
  # Define array range
@@ -3046,14 +3059,16 @@ module Writexlsx
3046
3059
 
3047
3060
  if options.first.class == Hash
3048
3061
  # Newer hash bashed options
3049
- params = options.first
3050
- x_offset = params[:x_offset]
3051
- y_offset = params[:y_offset]
3052
- x_scale = params[:x_scale]
3053
- y_scale = params[:y_scale]
3054
- anchor = params[:object_position]
3055
- url = params[:url]
3056
- tip = params[:tip]
3062
+ params = options.first
3063
+ x_offset = params[:x_offset]
3064
+ y_offset = params[:y_offset]
3065
+ x_scale = params[:x_scale]
3066
+ y_scale = params[:y_scale]
3067
+ anchor = params[:object_position]
3068
+ url = params[:url]
3069
+ tip = params[:tip]
3070
+ description = params[:description]
3071
+ decorative = params[:decorative]
3057
3072
  else
3058
3073
  x_offset, y_offset, x_scale, y_scale, anchor = options
3059
3074
  end
@@ -3065,7 +3080,7 @@ module Writexlsx
3065
3080
 
3066
3081
  @images << [
3067
3082
  row, col, image, x_offset, y_offset,
3068
- x_scale, y_scale, url, tip, anchor
3083
+ x_scale, y_scale, url, tip, anchor, description, decorative
3069
3084
  ]
3070
3085
  end
3071
3086
 
@@ -3363,9 +3378,11 @@ module Writexlsx
3363
3378
  row_first, row_last = row_last, row_first if row_first > row_last
3364
3379
  col_first, col_last = col_last, col_first if col_first > col_last
3365
3380
 
3366
- # Check that column number is valid and store the max value
3367
- check_dimensions(row_last, col_last)
3368
- store_row_col_max_min_values(row_last, col_last)
3381
+ # Check that the data range is valid and store the max and min values.
3382
+ check_dimensions(row_first, col_first)
3383
+ check_dimensions(row_last, col_last)
3384
+ store_row_col_max_min_values(row_first, col_first)
3385
+ store_row_col_max_min_values(row_last, col_last)
3369
3386
 
3370
3387
  # Store the merge range.
3371
3388
  @merge << [row_first, col_first, row_last, col_last]
@@ -3428,9 +3445,11 @@ module Writexlsx
3428
3445
  row_first, row_last = row_last, row_first if row_first > row_last
3429
3446
  col_first, col_last = col_last, col_first if col_first > col_last
3430
3447
 
3431
- # Check that column number is valid and store the max value
3432
- check_dimensions(row_last, col_last)
3433
- store_row_col_max_min_values(row_last, col_last)
3448
+ # Check that the data range is valid and store the max and min values.
3449
+ check_dimensions(row_first, col_first)
3450
+ check_dimensions(row_last, col_last)
3451
+ store_row_col_max_min_values(row_first, col_first)
3452
+ store_row_col_max_min_values(row_last, col_last)
3434
3453
 
3435
3454
  # Store the merge range.
3436
3455
  @merge << [row_first, col_first, row_last, col_last]
@@ -5738,7 +5757,7 @@ module Writexlsx
5738
5757
  name = chart.name
5739
5758
 
5740
5759
  # Create a Drawing object to use with worksheet unless one already exists.
5741
- drawing = Drawing.new(drawing_type, dimensions, 0, 0, name, nil, anchor, drawing_rel_index, 0, nil)
5760
+ drawing = Drawing.new(drawing_type, dimensions, 0, 0, name, nil, anchor, drawing_rel_index, 0, nil, 0)
5742
5761
  if !drawings?
5743
5762
  @drawings = Drawings.new
5744
5763
  @drawings.add_drawing_object(drawing)
@@ -6062,6 +6081,30 @@ module Writexlsx
6062
6081
  end
6063
6082
  end
6064
6083
 
6084
+ #
6085
+ # Ignore worksheet errors/warnings in user defined ranges.
6086
+ #
6087
+ def ignore_errors(ignores)
6088
+ # List of valid input parameters.
6089
+ valid_parameter_keys = [
6090
+ :number_stored_as_text,
6091
+ :eval_error,
6092
+ :formula_differs,
6093
+ :formula_range,
6094
+ :formula_unlocked,
6095
+ :empty_cell_reference,
6096
+ :list_data_validation,
6097
+ :calculated_column,
6098
+ :two_digit_text_year
6099
+ ]
6100
+
6101
+ unless (ignores.keys - valid_parameter_keys).empty?
6102
+ raise "Unknown parameter '#{ignores.key - valid_parameter_keys}' in ignore_errors()."
6103
+ end
6104
+
6105
+ @ignore_errors = ignores
6106
+ end
6107
+
6065
6108
  def write_ext(url)
6066
6109
  attributes = [
6067
6110
  ['xmlns:x14', "#{OFFICE_URL}spreadsheetml/2009/9/main"],
@@ -6464,7 +6507,7 @@ module Writexlsx
6464
6507
  drawing_type = 2
6465
6508
 
6466
6509
  row, col, image, x_offset, y_offset,
6467
- x_scale, y_scale, url, tip, anchor = @images[index]
6510
+ x_scale, y_scale, url, tip, anchor, description, decorative = @images[index]
6468
6511
 
6469
6512
  width *= x_scale
6470
6513
  height *= y_scale
@@ -6479,7 +6522,7 @@ module Writexlsx
6479
6522
  height = (0.5 + (height * 9_525)).to_i
6480
6523
 
6481
6524
  # Create a Drawing object to use with worksheet unless one already exists.
6482
- drawing = Drawing.new(drawing_type, dimensions, width, height, name, nil, anchor, 0, 0, tip)
6525
+ drawing = Drawing.new(drawing_type, dimensions, width, height, name, nil, anchor, 0, 0, tip, decorative)
6483
6526
  if !drawings?
6484
6527
  drawings = Drawings.new
6485
6528
  drawings.embedded = 1
@@ -6492,6 +6535,10 @@ module Writexlsx
6492
6535
  end
6493
6536
  drawings.add_drawing_object(drawing)
6494
6537
 
6538
+ if description
6539
+ drawing.description = description
6540
+ end
6541
+
6495
6542
  if url
6496
6543
  rel_type = '/hyperlink'
6497
6544
  target_mode = 'External'
@@ -6499,10 +6546,19 @@ module Writexlsx
6499
6546
  target = escape_url(url)
6500
6547
  end
6501
6548
  if url =~ /^external:/
6502
- target = escape_url(url.sub(/^external:/, 'file:///'))
6549
+ target = escape_url(url.sub(/^external:/, ''))
6550
+
6503
6551
  # Additional escape not required in worksheet hyperlinks
6504
6552
  target = target.gsub(/#/, '%23')
6553
+
6554
+ # Prefix absolute paths (not relative) with file:///
6555
+ if target =~ /^\w:/ || target =~ /^\\\\/
6556
+ target = "file:///#{target}"
6557
+ else
6558
+ target = target.gsub(/\\/, '/')
6559
+ end
6505
6560
  end
6561
+
6506
6562
  if url =~ /^internal:/
6507
6563
  target = url.sub(/^internal:/, '#')
6508
6564
  target_mode = nil
@@ -6645,7 +6701,7 @@ EOS
6645
6701
  shape.calc_position_emus(self)
6646
6702
 
6647
6703
  drawing_type = 3
6648
- drawing = Drawing.new(drawing_type, shape.dimensions, shape.width_emu, shape.height_emu, shape.name, shape, shape.anchor, drawing_rel_index, 0, nil)
6704
+ drawing = Drawing.new(drawing_type, shape.dimensions, shape.width_emu, shape.height_emu, shape.name, shape, shape.anchor, drawing_rel_index, 0, nil, 0)
6649
6705
  drawings.add_drawing_object(drawing)
6650
6706
  end
6651
6707
  public :prepare_shape
@@ -6735,6 +6791,8 @@ EOS
6735
6791
  chars.each { |c| encoded_password ^= c }
6736
6792
  encoded_password ^= count
6737
6793
  encoded_password ^= 0xCE4B
6794
+
6795
+ sprintf("%X", encoded_password)
6738
6796
  end
6739
6797
 
6740
6798
  #
@@ -7550,6 +7608,32 @@ EOS
7550
7608
  @writer.empty_tag('sheetProtection', attributes)
7551
7609
  end
7552
7610
 
7611
+ #
7612
+ # Write the <protectedRanges> element.
7613
+ #
7614
+ def write_protected_ranges
7615
+ return if @num_protected_ranges == 0
7616
+
7617
+ @writer.tag_elements('protectedRanges') do
7618
+ @protected_ranges.each do |protected_range|
7619
+ write_protected_range(*protected_range)
7620
+ end
7621
+ end
7622
+ end
7623
+
7624
+ #
7625
+ # Write the <protectedRange> element.
7626
+ #
7627
+ def write_protected_range(sqref, name, password)
7628
+ attributes = []
7629
+
7630
+ attributes << ['password', password] if password
7631
+ attributes << ['sqref', sqref]
7632
+ attributes << ['name', name]
7633
+
7634
+ @writer.empty_tag('protectedRange', attributes)
7635
+ end
7636
+
7553
7637
  #
7554
7638
  # Write the <drawing> elements.
7555
7639
  #
@@ -8082,5 +8166,44 @@ EOS
8082
8166
  end
8083
8167
  col
8084
8168
  end
8169
+
8170
+ #
8171
+ # Write the <ignoredErrors> element.
8172
+ #
8173
+ def write_ignored_errors
8174
+ return unless @ignore_errors
8175
+
8176
+ ignore = @ignore_errors
8177
+
8178
+ @writer.tag_elements('ignoredErrors' ) do
8179
+ {
8180
+ :number_stored_as_text => 'numberStoredAsText',
8181
+ :eval_error => 'evalError',
8182
+ :formula_differs => 'formula',
8183
+ :formula_range => 'formulaRange',
8184
+ :formula_unlocked => 'unlockedFormula',
8185
+ :empty_cell_reference => 'emptyCellReference',
8186
+ :list_data_validation => 'listDataValidation',
8187
+ :calculated_column => 'calculatedColumn',
8188
+ :two_digit_text_year => 'twoDigitTextYear'
8189
+ }.each do |key, value|
8190
+ if ignore[key]
8191
+ write_ignored_error(value, ignore[key])
8192
+ end
8193
+ end
8194
+ end
8195
+ end
8196
+
8197
+ #
8198
+ # Write the <ignoredError> element.
8199
+ #
8200
+ def write_ignored_error(type, sqref)
8201
+ attributes = {
8202
+ 'sqref' => sqref,
8203
+ type => 1
8204
+ }
8205
+
8206
+ @writer.empty_tag('ignoredError', attributes)
8207
+ end
8085
8208
  end
8086
8209
  end
@@ -2,7 +2,7 @@
2
2
  require 'helper'
3
3
  require 'write_xlsx/drawing'
4
4
 
5
- class TestWriteExt < Minitest::Test
5
+ class TestWriteXdrExt < Minitest::Test
6
6
  def setup
7
7
  @drawing = Writexlsx::Drawings.new
8
8
  end
@@ -10,7 +10,7 @@ class TestWriteExt < Minitest::Test
10
10
  def test_write_ext
11
11
  expected = '<xdr:ext cx="9308969" cy="6078325"/>'
12
12
 
13
- @drawing.__send__(:write_ext, 9308969, 6078325)
13
+ @drawing.__send__(:write_xdr_ext, 9308969, 6078325)
14
14
  result = @drawing.instance_variable_get(:@writer).string
15
15
 
16
16
  assert_equal(expected, result)
Binary file
@@ -0,0 +1,31 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class TestRegressionArrayFormula04 < Minitest::Test
5
+ def setup
6
+ setup_dir_var
7
+ end
8
+
9
+ def teardown
10
+ @tempfile.close(true)
11
+ end
12
+
13
+ def test_array_formula04
14
+ @xlsx = 'array_formula04.xlsx'
15
+ workbook = WriteXLSX.new(@io)
16
+ worksheet = workbook.add_worksheet
17
+
18
+ worksheet.write_array_formula(
19
+ 'A1:A3',
20
+ '{=SUM(B1:C1*B2:C2)}',
21
+ nil,
22
+ 0
23
+ )
24
+
25
+ workbook.close
26
+ compare_for_regression(
27
+ [ 'xl/calcChain.xml', '[Content_Types].xml', 'xl/_rels/workbook.xml.rels' ],
28
+ {'xl/workbook.xml' => ['<workbookView']}
29
+ )
30
+ end
31
+ end
@@ -33,7 +33,7 @@ class TestRegressionChartCrossing01 < Minitest::Test
33
33
 
34
34
  chart.set_y_axis(:crossing => 'max')
35
35
 
36
- # Not stictly required. Just to match reference file.
36
+ # Not strictly required. Just to match reference file.
37
37
  chart.set_x_axis(:position => 't')
38
38
 
39
39
  worksheet.insert_chart('E9', chart)
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class TestRegressionChartCrossing05 < Minitest::Test
5
+ def setup
6
+ setup_dir_var
7
+ end
8
+
9
+ def teardown
10
+ @tempfile.close(true)
11
+ end
12
+
13
+ def test_chart_crossing05
14
+ @xlsx = 'chart_crossing05.xlsx'
15
+ workbook = WriteXLSX.new(@io)
16
+ worksheet = workbook.add_worksheet
17
+ chart = workbook.add_chart(:type => 'column', :embedded => 1)
18
+
19
+ # For testing, copy the randomly generated axis ids in the target xlsx file.
20
+ chart.instance_variable_set(:@axis_ids, [55948032, 55950336])
21
+
22
+ data = [
23
+ [1, 2, 3, 4, 5],
24
+ [2, 4, 6, 8, 10],
25
+ [3, 6, 9, 12, 15]
26
+ ]
27
+
28
+ worksheet.write('A1', data)
29
+
30
+ chart.add_series(:values => '=Sheet1!$A$1:$A$5')
31
+ chart.add_series(:values => '=Sheet1!$B$1:$B$5')
32
+ chart.add_series(:values => '=Sheet1!$C$1:$C$5')
33
+
34
+ chart.set_x_axis(:crossing => 'min')
35
+
36
+ worksheet.insert_chart('E9', chart)
37
+
38
+ workbook.close
39
+ compare_for_regression(
40
+ nil,
41
+ {
42
+ 'xl/charts/chart1.xml' => [ '<c:pageMargins' ]
43
+ }
44
+ )
45
+ end
46
+ end
@@ -0,0 +1,46 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class TestRegressionChartCrossing06 < Minitest::Test
5
+ def setup
6
+ setup_dir_var
7
+ end
8
+
9
+ def teardown
10
+ @tempfile.close(true)
11
+ end
12
+
13
+ def test_chart_crossing06
14
+ @xlsx = 'chart_crossing06.xlsx'
15
+ workbook = WriteXLSX.new(@io)
16
+ worksheet = workbook.add_worksheet
17
+ chart = workbook.add_chart(:type => 'column', :embedded => 1)
18
+
19
+ # For testing, copy the randomly generated axis ids in the target xlsx file.
20
+ chart.instance_variable_set(:@axis_ids, [72794880, 72796416])
21
+
22
+ data = [
23
+ [1, 2, 3, 4, 5],
24
+ [2, 4, 6, 8, 10],
25
+ [3, 6, 9, 12, 15]
26
+ ]
27
+
28
+ worksheet.write('A1', data)
29
+
30
+ chart.add_series(:values => '=Sheet1!$A$1:$A$5')
31
+ chart.add_series(:values => '=Sheet1!$B$1:$B$5')
32
+ chart.add_series(:values => '=Sheet1!$C$1:$C$5')
33
+
34
+ chart.set_y_axis(:crossing => 'min')
35
+
36
+ worksheet.insert_chart('E9', chart)
37
+
38
+ workbook.close
39
+ compare_for_regression(
40
+ nil,
41
+ {
42
+ 'xl/charts/chart1.xml' => [ '<c:pageMargins' ]
43
+ }
44
+ )
45
+ end
46
+ end
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class TestRegressionChartDataLabels26 < Minitest::Test
5
+ def setup
6
+ setup_dir_var
7
+ end
8
+
9
+ def teardown
10
+ @tempfile.close(true)
11
+ end
12
+
13
+ def test_chart_data_labels26
14
+ @xlsx = 'chart_data_labels26.xlsx'
15
+ workbook = WriteXLSX.new(@io)
16
+ worksheet = workbook.add_worksheet
17
+ chart = workbook.add_chart(:type => 'column', :embedded => 1)
18
+
19
+ # For testing, copy the randomly generated axis ids in the target xlsx file.
20
+ chart.instance_variable_set(:@axis_ids, [48514944, 48516480])
21
+
22
+ data = [
23
+ [ 1, 2, 3, 4, 5],
24
+ [ 2, 4, 6, 8, 10],
25
+ [ 3, 6, 9, 12, 15],
26
+ [10, 20, 30, 40, 50]
27
+ ]
28
+
29
+ worksheet.write('A1', data)
30
+
31
+ chart.add_series(
32
+ :values => '=Sheet1!$A$1:$A$5',
33
+ :data_labels => {:value => 1, :custom => [{:value => 33}]}
34
+ )
35
+
36
+ chart.add_series(:values => '=Sheet1!$B$1:$B$5')
37
+ chart.add_series(:values => '=Sheet1!$C$1:$C$5')
38
+
39
+ worksheet.insert_chart('E9', chart)
40
+
41
+ workbook.close
42
+ compare_for_regression
43
+ end
44
+ end
@@ -0,0 +1,44 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'helper'
3
+
4
+ class TestRegressionChartDataLabels27 < Minitest::Test
5
+ def setup
6
+ setup_dir_var
7
+ end
8
+
9
+ def teardown
10
+ @tempfile.close(true)
11
+ end
12
+
13
+ def test_chart_data_labels27
14
+ @xlsx = 'chart_data_labels27.xlsx'
15
+ workbook = WriteXLSX.new(@io)
16
+ worksheet = workbook.add_worksheet
17
+ chart = workbook.add_chart(:type => 'column', :embedded => 1)
18
+
19
+ # For testing, copy the randomly generated axis ids in the target xlsx file.
20
+ chart.instance_variable_set(:@axis_ids, [48514944, 48516480])
21
+
22
+ data = [
23
+ [ 1, 2, 3, 4, 5],
24
+ [ 2, 4, 6, 8, 10],
25
+ [ 3, 6, 9, 12, 15],
26
+ [10, 20, 30, 40, 50]
27
+ ]
28
+
29
+ worksheet.write('A1', data)
30
+
31
+ chart.add_series(
32
+ :values => '=Sheet1!$A$1:$A$5',
33
+ :data_labels => {:value => 1, :custom => [{:value => '=Sheet1!$D$1'}]}
34
+ )
35
+
36
+ chart.add_series(:values => '=Sheet1!$B$1:$B$5')
37
+ chart.add_series(:values => '=Sheet1!$C$1:$C$5')
38
+
39
+ worksheet.insert_chart('E9', chart)
40
+
41
+ workbook.close
42
+ compare_for_regression
43
+ end
44
+ end