write_xlsx 1.12.1 → 1.12.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +12 -0
  3. data/Changes +3 -0
  4. data/LICENSE.txt +1 -1
  5. data/examples/autofilter.rb +1 -2
  6. data/examples/colors.rb +4 -4
  7. data/examples/formats.rb +14 -14
  8. data/lib/write_xlsx/chart/area.rb +1 -1
  9. data/lib/write_xlsx/chart/axis.rb +4 -4
  10. data/lib/write_xlsx/chart/bar.rb +1 -1
  11. data/lib/write_xlsx/chart/caption.rb +8 -4
  12. data/lib/write_xlsx/chart/column.rb +1 -1
  13. data/lib/write_xlsx/chart/doughnut.rb +2 -2
  14. data/lib/write_xlsx/chart/line.rb +1 -1
  15. data/lib/write_xlsx/chart/pie.rb +2 -2
  16. data/lib/write_xlsx/chart/radar.rb +1 -1
  17. data/lib/write_xlsx/chart/scatter.rb +1 -1
  18. data/lib/write_xlsx/chart/series.rb +10 -20
  19. data/lib/write_xlsx/chart/stock.rb +1 -1
  20. data/lib/write_xlsx/chart.rb +14 -21
  21. data/lib/write_xlsx/chartsheet.rb +3 -3
  22. data/lib/write_xlsx/drawing.rb +108 -114
  23. data/lib/write_xlsx/format.rb +20 -24
  24. data/lib/write_xlsx/image.rb +89 -0
  25. data/lib/write_xlsx/image_property.rb +163 -0
  26. data/lib/write_xlsx/inserted_chart.rb +42 -0
  27. data/lib/write_xlsx/package/button.rb +58 -5
  28. data/lib/write_xlsx/package/conditional_format.rb +4 -4
  29. data/lib/write_xlsx/package/packager.rb +22 -27
  30. data/lib/write_xlsx/package/rich_value.rb +1 -1
  31. data/lib/write_xlsx/package/styles.rb +1 -1
  32. data/lib/write_xlsx/package/vml.rb +10 -19
  33. data/lib/write_xlsx/shape.rb +3 -2
  34. data/lib/write_xlsx/sparkline.rb +1 -1
  35. data/lib/write_xlsx/utility.rb +8 -203
  36. data/lib/write_xlsx/version.rb +1 -1
  37. data/lib/write_xlsx/workbook.rb +87 -175
  38. data/lib/write_xlsx/worksheet/data_validation.rb +1 -1
  39. data/lib/write_xlsx/worksheet/hyperlink.rb +2 -2
  40. data/lib/write_xlsx/worksheet.rb +478 -484
  41. data/lib/write_xlsx/zip_file_utils.rb +1 -1
  42. data/write_xlsx.gemspec +3 -3
  43. metadata +11 -11
@@ -1,30 +1,33 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # frozen_string_literal: true
3
3
 
4
- require 'write_xlsx/package/xml_writer_simple'
5
- require 'write_xlsx/package/packager'
6
- require 'write_xlsx/sheets'
7
- require 'write_xlsx/worksheet'
4
+ require 'write_xlsx/chart'
8
5
  require 'write_xlsx/chartsheet'
9
- require 'write_xlsx/formats'
10
6
  require 'write_xlsx/format'
7
+ require 'write_xlsx/formats'
8
+ require 'write_xlsx/image_property'
11
9
  require 'write_xlsx/shape'
10
+ require 'write_xlsx/sheets'
12
11
  require 'write_xlsx/utility'
13
- require 'write_xlsx/chart'
12
+ require 'write_xlsx/worksheet'
14
13
  require 'write_xlsx/zip_file_utils'
14
+ require 'write_xlsx/package/xml_writer_simple'
15
+ require 'write_xlsx/package/packager'
15
16
  require 'tmpdir'
16
17
  require 'tempfile'
17
18
  require 'digest/md5'
18
19
 
19
20
  module Writexlsx
20
- OFFICE_URL = 'http://schemas.microsoft.com/office/' # :nodoc:
21
+ OFFICE_URL = 'http://schemas.microsoft.com/office/' # :nodoc:
22
+ MAX_URL_LENGTH = 2_079
21
23
 
22
24
  class Workbook
23
25
  include Writexlsx::Utility
24
26
 
25
27
  attr_writer :firstsheet # :nodoc:
26
28
  attr_reader :palette # :nodoc:
27
- attr_reader :worksheets, :charts, :drawings # :nodoc:
29
+ attr_reader :worksheets # :nodoc:
30
+ attr_accessor :drawings # :nodoc:
28
31
  attr_reader :named_ranges # :nodoc:
29
32
  attr_reader :doc_properties # :nodoc:
30
33
  attr_reader :custom_properties # :nodoc:
@@ -38,9 +41,13 @@ module Writexlsx
38
41
  attr_reader :embedded_image_indexes # :nodec:
39
42
  attr_reader :embedded_images # :nodoc:
40
43
  attr_reader :embedded_descriptions # :nodoc:
44
+ attr_writer :has_embedded_descriptions # :nodoc:
45
+ attr_accessor :charts # :nodoc:
41
46
 
42
47
  def initialize(file, *option_params)
43
48
  options, default_formats = process_workbook_options(*option_params)
49
+ @options = options.dup # for test
50
+ @default_formats = default_formats.dup # for test
44
51
  @writer = Package::XMLWriterSimple.new
45
52
 
46
53
  @file = file
@@ -60,7 +67,6 @@ module Writexlsx
60
67
  @formats = Formats.new
61
68
  @xf_formats = []
62
69
  @dxf_formats = []
63
- @font_count = 0
64
70
  @num_formats = []
65
71
  @defined_names = []
66
72
  @named_ranges = []
@@ -70,16 +76,15 @@ module Writexlsx
70
76
  @optimization = options[:optimization] || 0
71
77
  @x_window = 240
72
78
  @y_window = 15
73
- @window_width = 16095
74
- @window_height = 9660
79
+ @window_width = 16_095
80
+ @window_height = 9_660
75
81
  @tab_ratio = 600
76
82
  @excel2003_style = options[:excel2003_style] || false
77
- @table_count = 0
78
83
  @image_types = {}
79
84
  @images = []
80
85
  @strings_to_urls = options[:strings_to_urls].nil? || options[:strings_to_urls] ? true : false
81
86
 
82
- @max_url_length = 2079
87
+ @max_url_length = MAX_URL_LENGTH
83
88
  @has_comments = false
84
89
  @read_only = 0
85
90
  @has_metadata = false
@@ -87,10 +92,11 @@ module Writexlsx
87
92
  @has_embedded_descriptions = false
88
93
 
89
94
  if options[:max_url_length]
90
- @max_url_length = options[:max_url_length]
95
+ @max_url_length = options[:max_url_length].to_i
91
96
 
92
- @max_url_length = 2079 if @max_url_length < 250
97
+ @max_url_length = MAX_URL_LENGTH if @max_url_length < 255
93
98
  end
99
+
94
100
  # Structures for the shared strings data.
95
101
  @shared_strings = Package::SharedStrings.new
96
102
 
@@ -619,8 +625,51 @@ module Writexlsx
619
625
  @has_embedded_descriptions
620
626
  end
621
627
 
628
+ #
629
+ # Store the image types (PNG/JPEG/etc) used in the workbook to use in these
630
+ # Content_Types file.
631
+ #
632
+ def store_image_types(type)
633
+ case type
634
+ when 'png'
635
+ @image_types[:png] = 1
636
+ when 'jpeg'
637
+ @image_types[:jpeg] = 1
638
+ when 'gif'
639
+ @image_types[:gif] = 1
640
+ when 'bmp'
641
+ @image_types[:bmp] = 1
642
+ end
643
+ end
644
+
622
645
  private
623
646
 
647
+ #
648
+ # Workbook の生成時のオプションハッシュを解析する
649
+ #
650
+ def process_workbook_options(*params)
651
+ case params.size
652
+ when 0
653
+ [{}, {}]
654
+ when 1 # one hash
655
+ options_keys = %i[tempdir date_1904 optimization excel2003_style strings_to_urls max_url_length]
656
+
657
+ hash = params.first
658
+ options = hash.reject { |k, _v| !options_keys.include?(k) }
659
+
660
+ default_format_properties =
661
+ hash[:default_format_properties] ||
662
+ hash.reject { |k, _v| options_keys.include?(k) }
663
+
664
+ [options, default_format_properties.dup]
665
+ when 2 # array which includes options and default_format_properties
666
+ options, default_format_properties = params
667
+ default_format_properties ||= {}
668
+
669
+ [options.dup, default_format_properties.dup]
670
+ end
671
+ end
672
+
624
673
  def filename
625
674
  setup_filename unless @filename
626
675
  @filename
@@ -732,7 +781,7 @@ module Writexlsx
732
781
 
733
782
  if pos > 0
734
783
  sheetname = range[0, pos]
735
- cells = range[pos + 1..-1]
784
+ cells = range[(pos + 1)..-1]
736
785
  end
737
786
 
738
787
  # Split the cell range into 2 cells or else use single cell for both.
@@ -924,24 +973,10 @@ module Writexlsx
924
973
  Writexlsx::Utility.delete_files(tempdir)
925
974
  end
926
975
 
927
- def write_parts(zip)
928
- parts.each do |part|
929
- zip.put_next_entry(zip_entry_for_part(part.sub(Regexp.new("#{tempdir}/?"), '')))
930
- zip.puts(File.read(part))
931
- end
932
- end
933
-
934
976
  def zip_entry_for_part(part)
935
977
  Zip::Entry.new("", part)
936
978
  end
937
979
 
938
- #
939
- # files
940
- #
941
- def parts
942
- Dir.glob(File.join(tempdir, "**", "*"), File::FNM_DOTMATCH).select { |f| File.file?(f) }
943
- end
944
-
945
980
  #
946
981
  # prepare_sst_string_data
947
982
  #
@@ -1188,7 +1223,6 @@ module Writexlsx
1188
1223
  vml_data_id = 1
1189
1224
  vml_header_id = 0
1190
1225
  vml_shape_id = 1024
1191
- comment_files = 0
1192
1226
  has_button = false
1193
1227
 
1194
1228
  @worksheets.each do |sheet|
@@ -1196,8 +1230,7 @@ module Writexlsx
1196
1230
 
1197
1231
  if sheet.has_vml?
1198
1232
  if sheet.has_comments?
1199
- comment_files += 1
1200
- comment_id += 1
1233
+ comment_id += 1
1201
1234
  @has_comments = true
1202
1235
  end
1203
1236
  vml_drawing_id += 1
@@ -1402,158 +1435,37 @@ module Writexlsx
1402
1435
  # Iterate through the worksheets and set up any chart or image drawings.
1403
1436
  #
1404
1437
  def prepare_drawings # :nodoc:
1405
- chart_ref_id = 0
1406
- drawing_id = 0
1407
- ref_id = 0
1408
- image_ids = {}
1409
- header_image_ids = {}
1410
- background_ids = {}
1411
-
1412
1438
  # Store the image types for any embedded images.
1413
- @embedded_images.each do |image_data|
1414
- store_image_types(image_data[1])
1439
+ @embedded_images.each do |image|
1440
+ store_image_types(image.type)
1415
1441
 
1416
- @has_embedded_descriptions = true if ptrue?(image_data[2])
1442
+ @has_embedded_descriptions = true if ptrue?(image.description)
1417
1443
  end
1418
1444
 
1419
- # The image IDs start from after the embedded images.
1420
- image_ref_id = @embedded_images.size
1421
-
1422
- @worksheets.each do |sheet|
1423
- chart_count = sheet.charts.size
1424
- image_count = sheet.images.size
1425
- shape_count = sheet.shapes.size
1426
- header_image_count = sheet.header_images.size
1427
- footer_image_count = sheet.footer_images.size
1428
- has_background = sheet.background_image.size
1429
- has_drawings = false
1430
-
1431
- # Check that some image or drawing needs to be processed.
1432
- next if chart_count + image_count + shape_count + header_image_count + footer_image_count + has_background == 0
1433
-
1434
- # Don't increase the drawing_id header/footer images.
1435
- if chart_count + image_count + shape_count > 0
1436
- drawing_id += 1
1437
- has_drawings = true
1438
- end
1439
-
1440
- # Prepare the background images.
1441
- if ptrue?(has_background)
1442
- filename = sheet.background_image
1443
- type, width, height, name, x_dpi, y_dpi, md5 = get_image_properties(filename)
1444
-
1445
- if background_ids[md5]
1446
- ref_id = background_ids[md5]
1447
- else
1448
- image_ref_id += 1
1449
- ref_id = image_ref_id
1450
- background_ids[md5] = ref_id
1451
- @images << [filename, type]
1452
- end
1453
-
1454
- sheet.prepare_background(ref_id, type)
1455
- end
1456
-
1457
- # Prepare the worksheet images.
1458
- sheet.images.each_with_index do |image, index|
1459
- filename = image[2]
1460
- type, width, height, name, x_dpi, y_dpi, md5 = get_image_properties(image[2])
1461
- if image_ids[md5]
1462
- ref_id = image_ids[md5]
1463
- else
1464
- image_ref_id += 1
1465
- image_ids[md5] = ref_id = image_ref_id
1466
- @images << [filename, type]
1467
- end
1468
- sheet.prepare_image(
1469
- index, ref_id, drawing_id, width, height,
1470
- name, type, x_dpi, y_dpi, md5
1471
- )
1472
- end
1473
-
1474
- # Prepare the worksheet charts.
1475
- sheet.charts.each_with_index do |_chart, index|
1476
- chart_ref_id += 1
1477
- sheet.prepare_chart(index, chart_ref_id, drawing_id)
1478
- end
1479
-
1480
- # Prepare the worksheet shapes.
1481
- sheet.shapes.each_with_index do |_shape, index|
1482
- sheet.prepare_shape(index, drawing_id)
1483
- end
1484
-
1485
- # Prepare the header images.
1486
- header_image_count.times do |index|
1487
- filename = sheet.header_images[index][0]
1488
- position = sheet.header_images[index][1]
1489
-
1490
- type, width, height, name, x_dpi, y_dpi, md5 =
1491
- get_image_properties(filename)
1492
-
1493
- if header_image_ids[md5]
1494
- ref_id = header_image_ids[md5]
1495
- else
1496
- image_ref_id += 1
1497
- header_image_ids[md5] = ref_id = image_ref_id
1498
- @images << [filename, type]
1499
- end
1500
-
1501
- sheet.prepare_header_image(
1502
- ref_id, width, height, name, type,
1503
- position, x_dpi, y_dpi, md5
1504
- )
1505
- end
1506
-
1507
- # Prepare the footer images.
1508
- footer_image_count.times do |index|
1509
- filename = sheet.footer_images[index][0]
1510
- position = sheet.footer_images[index][1]
1511
-
1512
- type, width, height, name, x_dpi, y_dpi, md5 =
1513
- get_image_properties(filename)
1514
-
1515
- if header_image_ids[md5]
1516
- ref_id = header_image_ids[md5]
1517
- else
1518
- image_ref_id += 1
1519
- header_image_ids[md5] = ref_id = image_ref_id
1520
- @images << [filename, type]
1521
- end
1522
-
1523
- sheet.prepare_header_image(
1524
- ref_id, width, height, name, type,
1525
- position, x_dpi, y_dpi, md5
1526
- )
1527
- end
1528
-
1529
- if has_drawings
1530
- drawings = sheet.drawings
1531
- @drawings << drawings
1532
- end
1533
- end
1445
+ prepare_drawings_of_all_sheets
1534
1446
 
1535
1447
  # Sort the workbook charts references into the order that the were
1536
1448
  # written from the worksheets above.
1537
1449
  @charts = @charts.select { |chart| chart.id != -1 }
1538
- .sort_by { |chart| chart.id }
1539
-
1540
- @drawing_count = drawing_id
1450
+ .sort_by { |chart| chart.id }
1541
1451
  end
1542
1452
 
1543
- #
1544
- # Store the image types (PNG/JPEG/etc) used in the workbook to use in these
1545
- # Content_Types file.
1546
- #
1547
- def store_image_types(type)
1548
- case type
1549
- when 'png'
1550
- @image_types[:png] = 1
1551
- when 'jpeg'
1552
- @image_types[:jpeg] = 1
1553
- when 'gif'
1554
- @image_types[:gif] = 1
1555
- when 'bmp'
1556
- @image_types[:bmp] = 1
1453
+ def prepare_drawings_of_all_sheets
1454
+ drawing_id = 0
1455
+ chart_ref_id = 0
1456
+ image_ids = {}
1457
+ header_image_ids = {}
1458
+ background_ids = {}
1459
+
1460
+ # The image IDs start from after the embedded images.
1461
+ image_ref_id = @embedded_images.size
1462
+
1463
+ @worksheets.each do |sheet|
1464
+ drawing_id, chart_ref_id, image_ref_id =
1465
+ sheet.prepare_drawings(
1466
+ drawing_id, chart_ref_id, image_ref_id, image_ids,
1467
+ header_image_ids, background_ids
1468
+ )
1557
1469
  end
1558
1470
  end
1559
1471
  end
@@ -163,7 +163,7 @@ module Writexlsx
163
163
  attributes << %w[errorStyle information] if @error_type == 2
164
164
  end
165
165
  attributes << ['allowBlank', 1] if @ignore_blank != 0
166
- attributes << ['showDropDown', 1] if @dropdown == 0
166
+ attributes << ['showDropDown', 1] if @dropdown == 0
167
167
  attributes << ['showInputMessage', 1] if @show_input != 0
168
168
  attributes << ['showErrorMessage', 1] if @show_error != 0
169
169
 
@@ -34,7 +34,7 @@ module Writexlsx
34
34
  url = escape_url(url)
35
35
 
36
36
  # Excel limits the escaped URL and location/anchor to 255 characters.
37
- raise "Ignoring URL '#{url}' where link or anchor > #{max_url_length} characters since it exceeds Excel's limit for URLS. See LIMITATIONS section of the Excel::Writer::XLSX documentation." if url.bytesize > max_url_length || (!@url_str.nil? && @url_str.bytesize > max_url_length)
37
+ raise "Ignoring URL '#{url}' where link or anchor > #{max_url_length} characters since it exceeds Excel's limit for URLS. See LIMITATIONS section of the WriteXLSX documentation." if url.bytesize > max_url_length || (!@url_str.nil? && @url_str.bytesize > max_url_length)
38
38
 
39
39
  @url = url
40
40
  @str = normalized_str
@@ -123,7 +123,7 @@ module Writexlsx
123
123
  @url_str = url_str
124
124
 
125
125
  # Excel limits the escaped URL and location/anchor to max_url_length characters.
126
- raise "Ignoring URL '#{url}' where link or anchor > #{max_url_length} characters since it exceeds Excel's limit for URLS. See LIMITATIONS section of the Excel::Writer::XLSX documentation." if url.bytesize > max_url_length || (!@url_str.nil? && @url_str.bytesize > max_url_length)
126
+ raise "Ignoring URL '#{url}' where link or anchor > #{max_url_length} characters since it exceeds Excel's limit for URLS. See LIMITATIONS section of the WriteXLSX documentation." if url.bytesize > max_url_length || (!@url_str.nil? && @url_str.bytesize > max_url_length)
127
127
 
128
128
  @url = url
129
129
  @str = str