write_xlsx 1.13.0 → 1.15.1

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 (101) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +25 -4
  3. data/Changes +23 -0
  4. data/lib/write_xlsx/chart/area.rb +2 -2
  5. data/lib/write_xlsx/chart/axis.rb +55 -32
  6. data/lib/write_xlsx/chart/axis_writer.rb +528 -0
  7. data/lib/write_xlsx/chart/bar.rb +2 -2
  8. data/lib/write_xlsx/chart/caption.rb +16 -9
  9. data/lib/write_xlsx/chart/chart_area.rb +121 -0
  10. data/lib/write_xlsx/chart/column.rb +2 -2
  11. data/lib/write_xlsx/chart/d_pt_point_writer.rb +14 -0
  12. data/lib/write_xlsx/chart/doughnut.rb +0 -3
  13. data/lib/write_xlsx/chart/formatting_writer.rb +652 -0
  14. data/lib/write_xlsx/chart/initialization.rb +100 -0
  15. data/lib/write_xlsx/chart/line.rb +4 -3
  16. data/lib/write_xlsx/chart/pie.rb +6 -2
  17. data/lib/write_xlsx/chart/radar.rb +2 -2
  18. data/lib/write_xlsx/chart/scatter.rb +4 -3
  19. data/lib/write_xlsx/chart/series.rb +35 -15
  20. data/lib/write_xlsx/chart/series_data.rb +132 -0
  21. data/lib/write_xlsx/chart/series_writer.rb +318 -0
  22. data/lib/write_xlsx/chart/settings.rb +226 -0
  23. data/lib/write_xlsx/chart/stock.rb +2 -2
  24. data/lib/write_xlsx/chart/table.rb +50 -0
  25. data/lib/write_xlsx/chart/xml_writer.rb +305 -0
  26. data/lib/write_xlsx/chart.rb +286 -2477
  27. data/lib/write_xlsx/chartsheet.rb +31 -82
  28. data/lib/write_xlsx/constants.rb +11 -0
  29. data/lib/write_xlsx/drawing.rb +5 -3
  30. data/lib/write_xlsx/format/alignment_state.rb +39 -0
  31. data/lib/write_xlsx/format/alignment_style.rb +92 -0
  32. data/lib/write_xlsx/format/border_state.rb +47 -0
  33. data/lib/write_xlsx/format/border_style.rb +116 -0
  34. data/lib/write_xlsx/format/fill_state.rb +26 -0
  35. data/lib/write_xlsx/format/fill_style.rb +52 -0
  36. data/lib/write_xlsx/format/font_state.rb +74 -0
  37. data/lib/write_xlsx/format/font_style.rb +172 -0
  38. data/lib/write_xlsx/format/format_state.rb +65 -0
  39. data/lib/write_xlsx/format/number_format_state.rb +20 -0
  40. data/lib/write_xlsx/format/number_format_style.rb +28 -0
  41. data/lib/write_xlsx/format/protection_state.rb +20 -0
  42. data/lib/write_xlsx/format/protection_style.rb +28 -0
  43. data/lib/write_xlsx/format.rb +1093 -426
  44. data/lib/write_xlsx/formats.rb +0 -2
  45. data/lib/write_xlsx/image_property.rb +4 -1
  46. data/lib/write_xlsx/inserted_chart.rb +1 -1
  47. data/lib/write_xlsx/object_positioning.rb +15 -1
  48. data/lib/write_xlsx/package/app.rb +2 -2
  49. data/lib/write_xlsx/package/button.rb +6 -2
  50. data/lib/write_xlsx/package/comments.rb +11 -3
  51. data/lib/write_xlsx/package/conditional_format.rb +7 -3
  52. data/lib/write_xlsx/package/content_types.rb +2 -2
  53. data/lib/write_xlsx/package/core.rb +2 -2
  54. data/lib/write_xlsx/package/custom.rb +3 -2
  55. data/lib/write_xlsx/package/metadata.rb +2 -2
  56. data/lib/write_xlsx/package/packager.rb +0 -3
  57. data/lib/write_xlsx/package/relationships.rb +2 -2
  58. data/lib/write_xlsx/package/rich_value.rb +4 -2
  59. data/lib/write_xlsx/package/rich_value_rel.rb +2 -2
  60. data/lib/write_xlsx/package/rich_value_structure.rb +2 -2
  61. data/lib/write_xlsx/package/rich_value_types.rb +3 -3
  62. data/lib/write_xlsx/package/shared_strings.rb +2 -2
  63. data/lib/write_xlsx/package/styles.rb +13 -9
  64. data/lib/write_xlsx/package/table.rb +8 -2
  65. data/lib/write_xlsx/package/theme.rb +0 -3
  66. data/lib/write_xlsx/package/vml.rb +2 -2
  67. data/lib/write_xlsx/page_setup.rb +3 -1
  68. data/lib/write_xlsx/shape.rb +97 -100
  69. data/lib/write_xlsx/sheets.rb +6 -1
  70. data/lib/write_xlsx/sparkline.rb +2 -2
  71. data/lib/write_xlsx/utility/cell_reference.rb +124 -0
  72. data/lib/write_xlsx/utility/chart_formatting.rb +262 -0
  73. data/lib/write_xlsx/utility/common.rb +44 -0
  74. data/lib/write_xlsx/utility/date_time.rb +113 -0
  75. data/lib/write_xlsx/utility/dimensions.rb +40 -0
  76. data/lib/write_xlsx/utility/drawing.rb +136 -0
  77. data/lib/write_xlsx/utility/rich_text.rb +184 -0
  78. data/lib/write_xlsx/utility/sheetname_quoting.rb +73 -0
  79. data/lib/write_xlsx/utility/string_width.rb +45 -0
  80. data/lib/write_xlsx/utility/url.rb +27 -0
  81. data/lib/write_xlsx/utility/xml_primitives.rb +32 -0
  82. data/lib/write_xlsx/version.rb +1 -1
  83. data/lib/write_xlsx/workbook/chart_data.rb +188 -0
  84. data/lib/write_xlsx/workbook/format_preparation.rb +199 -0
  85. data/lib/write_xlsx/workbook/initialization.rb +223 -0
  86. data/lib/write_xlsx/workbook/package_preparation.rb +231 -0
  87. data/lib/write_xlsx/workbook/workbook_writer.rb +164 -0
  88. data/lib/write_xlsx/workbook.rb +143 -981
  89. data/lib/write_xlsx/worksheet/autofilter.rb +3 -1
  90. data/lib/write_xlsx/worksheet/cell_data.rb +5 -1
  91. data/lib/write_xlsx/worksheet/columns.rb +8 -3
  92. data/lib/write_xlsx/worksheet/data_validation.rb +9 -1
  93. data/lib/write_xlsx/worksheet/data_writing.rb +42 -15
  94. data/lib/write_xlsx/worksheet/drawing_preparation.rb +1 -1
  95. data/lib/write_xlsx/worksheet/formatting.rb +3 -1
  96. data/lib/write_xlsx/worksheet/hyperlink.rb +9 -1
  97. data/lib/write_xlsx/worksheet/row_col_sizing.rb +3 -1
  98. data/lib/write_xlsx/worksheet/xml_writer.rb +9 -4
  99. data/lib/write_xlsx/worksheet.rb +19 -2
  100. metadata +42 -3
  101. data/lib/write_xlsx/utility.rb +0 -1034
@@ -0,0 +1,231 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ module Writexlsx
5
+ class Workbook
6
+ module PackagePreparation
7
+ private
8
+
9
+ #
10
+ # Assemble worksheets into a workbook.
11
+ #
12
+ def store_workbook # :nodoc:
13
+ # Add a default worksheet if non have been added.
14
+ add_worksheet if @worksheets.empty?
15
+
16
+ # Ensure that at least one worksheet has been selected.
17
+ @worksheets.visible_first.select if @activesheet == 0
18
+
19
+ # Set the active sheet.
20
+ @activesheet = @worksheets.visible_first.index if @activesheet == 0
21
+ @worksheets[@activesheet].activate
22
+
23
+ # Convert the SST strings data structure.
24
+ prepare_sst_string_data
25
+
26
+ # Prepare the worksheet VML elements such as comments and buttons.
27
+ prepare_vml_objects
28
+ # Set the defined names for the worksheets such as Print Titles.
29
+ prepare_defined_names
30
+ # Prepare the drawings, charts and images.
31
+ prepare_drawings
32
+ # Add cached data to charts.
33
+ add_chart_data
34
+
35
+ # Prepare the worksheet tables.
36
+ prepare_tables
37
+
38
+ # Prepare the metadata file links.
39
+ prepare_metadata
40
+
41
+ # Package the workbook.
42
+ packager = Package::Packager.new(self)
43
+ packager.set_package_dir(tempdir)
44
+ packager.create_package
45
+
46
+ # Free up the Packager object.
47
+ packager = nil
48
+
49
+ # Store the xlsx component files with the temp dir name removed.
50
+ ZipFileUtils.zip(tempdir.to_s, filename)
51
+
52
+ IO.copy_stream(filename, fileobj) if fileobj
53
+ delete_tempdir(tempdir)
54
+ end
55
+
56
+ #
57
+ # Iterate through the worksheets and store any defined names in addition to
58
+ # any user defined names. Stores the defined names for the Workbook.xml and
59
+ # the named ranges for App.xml.
60
+ #
61
+ def prepare_defined_names # :nodoc:
62
+ @worksheets.each do |sheet|
63
+ # Check for Print Area settings.
64
+ if sheet.autofilter_area
65
+ @defined_names << [
66
+ '_xlnm._FilterDatabase',
67
+ sheet.index,
68
+ sheet.autofilter_area,
69
+ 1
70
+ ]
71
+ end
72
+
73
+ # Check for Print Area settings.
74
+ unless sheet.print_area.empty?
75
+ @defined_names << [
76
+ '_xlnm.Print_Area',
77
+ sheet.index,
78
+ sheet.print_area
79
+ ]
80
+ end
81
+
82
+ # Check for repeat rows/cols. aka, Print Titles.
83
+ next unless !sheet.print_repeat_cols.empty? || !sheet.print_repeat_rows.empty?
84
+
85
+ range = if !sheet.print_repeat_cols.empty? && !sheet.print_repeat_rows.empty?
86
+ sheet.print_repeat_cols + ',' + sheet.print_repeat_rows
87
+ else
88
+ sheet.print_repeat_cols + sheet.print_repeat_rows
89
+ end
90
+
91
+ # Store the defined names.
92
+ @defined_names << ['_xlnm.Print_Titles', sheet.index, range]
93
+ end
94
+
95
+ @defined_names = sort_defined_names(@defined_names)
96
+ @named_ranges = extract_named_ranges(@defined_names)
97
+ end
98
+
99
+ #
100
+ # Iterate through the worksheets and set up the VML objects.
101
+ #
102
+ def prepare_vml_objects # :nodoc:
103
+ comment_id = 0
104
+ vml_drawing_id = 0
105
+ vml_data_id = 1
106
+ vml_header_id = 0
107
+ vml_shape_id = 1024
108
+ has_button = false
109
+
110
+ @worksheets.each do |sheet|
111
+ next if !sheet.has_vml? && !sheet.has_header_vml?
112
+
113
+ if sheet.has_vml?
114
+ if sheet.has_comments?
115
+ comment_id += 1
116
+ @has_comments = true
117
+ end
118
+ vml_drawing_id += 1
119
+
120
+ sheet.prepare_vml_objects(
121
+ vml_data_id, vml_shape_id,
122
+ vml_drawing_id, comment_id
123
+ )
124
+
125
+ # Each VML file should start with a shape id incremented by 1024.
126
+ vml_data_id += 1 * (1 + sheet.num_comments_block)
127
+ vml_shape_id += 1024 * (1 + sheet.num_comments_block)
128
+ end
129
+
130
+ if sheet.has_header_vml?
131
+ vml_header_id += 1
132
+ vml_drawing_id += 1
133
+ sheet.prepare_header_vml_objects(vml_header_id, vml_drawing_id)
134
+ end
135
+
136
+ # Set the sheet vba_codename if it has a button and the workbook
137
+ # has a vbaProject binary.
138
+ unless sheet.buttons_data.empty?
139
+ has_button = true
140
+ sheet.set_vba_name if @vba_project && !sheet.vba_codename
141
+ end
142
+ end
143
+
144
+ # Set the workbook vba_codename if one of the sheets has a button and
145
+ # the workbook has a vbaProject binary.
146
+ set_vba_name if has_button && @vba_project && !@vba_codename
147
+ end
148
+
149
+ #
150
+ # Set the table ids for the worksheet tables.
151
+ #
152
+ def prepare_tables
153
+ table_id = 0
154
+ seen = {}
155
+
156
+ sheets.each do |sheet|
157
+ table_id += sheet.prepare_tables(table_id + 1, seen)
158
+ end
159
+ end
160
+
161
+ #
162
+ # Set the metadata rel link.
163
+ #
164
+ def prepare_metadata
165
+ @worksheets.each do |sheet|
166
+ next unless sheet.has_dynamic_functions? || sheet.has_embedded_images?
167
+
168
+ @has_metadata = true
169
+ @has_dynamic_functions ||= sheet.has_dynamic_functions?
170
+ @has_embedded_images ||= sheet.has_embedded_images?
171
+ end
172
+ end
173
+
174
+ #
175
+ # Iterate through the worksheets and set up any chart or image drawings.
176
+ #
177
+ def prepare_drawings # :nodoc:
178
+ # Store the image types for any embedded images.
179
+ @embedded_images.each do |image|
180
+ store_image_types(image.type)
181
+
182
+ @has_embedded_descriptions = true if ptrue?(image.description)
183
+ end
184
+
185
+ prepare_drawings_of_all_sheets
186
+
187
+ # Sort the workbook charts references into the order that the were
188
+ # written from the worksheets above.
189
+ @charts = @charts.reject { |chart| chart.id == -1 }
190
+ .sort_by(&:id)
191
+ end
192
+
193
+ def prepare_drawings_of_all_sheets
194
+ drawing_id = 0
195
+ chart_ref_id = 0
196
+ image_ids = {}
197
+ header_image_ids = {}
198
+ background_ids = {}
199
+
200
+ # The image IDs start from after the embedded images.
201
+ image_ref_id = @embedded_images.size
202
+
203
+ @worksheets.each do |sheet|
204
+ drawing_id, chart_ref_id, image_ref_id =
205
+ sheet.prepare_drawings(
206
+ drawing_id, chart_ref_id, image_ref_id, image_ids,
207
+ header_image_ids, background_ids
208
+ )
209
+ end
210
+ end
211
+
212
+ #
213
+ # prepare_sst_string_data
214
+ #
215
+ def prepare_sst_string_data; end
216
+
217
+ def delete_tempdir(path)
218
+ if FileTest.file?(path)
219
+ File.delete(path)
220
+ elsif FileTest.directory?(path)
221
+ Dir.foreach(path) do |file|
222
+ next if file =~ /^\.\.?$/ # '.' or '..'
223
+
224
+ delete_tempdir(path.sub(%r{/+$}, "") + '/' + file)
225
+ end
226
+ Dir.rmdir(path)
227
+ end
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,164 @@
1
+ # -*- coding: utf-8 -*-
2
+ # frozen_string_literal: true
3
+
4
+ module Writexlsx
5
+ class Workbook
6
+ module Initialization
7
+ #
8
+ # user must not use. it is internal method.
9
+ #
10
+ def assemble_xml_file # :nodoc:
11
+ return unless @writer
12
+
13
+ # Prepare format object for passing to Style.rb.
14
+ prepare_format_properties
15
+
16
+ write_xml_declaration do
17
+ # Write the root workbook element.
18
+ write_workbook do
19
+ # Write the XLSX file version.
20
+ write_file_version
21
+
22
+ # Write the fileSharing element.
23
+ write_file_sharing
24
+
25
+ # Write the workbook properties.
26
+ write_workbook_pr
27
+
28
+ # Write the workbook view properties.
29
+ write_book_views
30
+
31
+ # Write the worksheet names and ids.
32
+ @worksheets.write_sheets(@writer)
33
+
34
+ # Write the workbook defined names.
35
+ write_defined_names
36
+
37
+ # Write the workbook calculation properties.
38
+ write_calc_pr
39
+
40
+ # Write the workbook extension storage.
41
+ # write_ext_lst
42
+ end
43
+ end
44
+ end
45
+
46
+ private
47
+
48
+ def write_workbook(&block) # :nodoc:
49
+ schema = 'http://schemas.openxmlformats.org'
50
+ attributes = [
51
+ ['xmlns',
52
+ schema + '/spreadsheetml/2006/main'],
53
+ ['xmlns:r',
54
+ schema + '/officeDocument/2006/relationships']
55
+ ]
56
+ @writer.tag_elements('workbook', attributes, &block)
57
+ end
58
+
59
+ def write_file_version # :nodoc:
60
+ attributes = [
61
+ %w[appName xl],
62
+ ['lastEdited', 4],
63
+ ['lowestEdited', 4],
64
+ ['rupBuild', 4505]
65
+ ]
66
+
67
+ attributes << [:codeName, '{37E998C4-C9E5-D4B9-71C8-EB1FF731991C}'] if @vba_project
68
+
69
+ @writer.empty_tag('fileVersion', attributes)
70
+ end
71
+
72
+ #
73
+ # Write the <fileSharing> element.
74
+ #
75
+ def write_file_sharing
76
+ return unless ptrue?(@read_only)
77
+
78
+ attributes = []
79
+ attributes << ['readOnlyRecommended', 1]
80
+ @writer.empty_tag('fileSharing', attributes)
81
+ end
82
+
83
+ def write_workbook_pr # :nodoc:
84
+ attributes = []
85
+ attributes << ['codeName', @vba_codename] if ptrue?(@vba_codename)
86
+ attributes << ['date1904', 1] if date_1904?
87
+ attributes << ['defaultThemeVersion', 124226]
88
+ @writer.empty_tag('workbookPr', attributes)
89
+ end
90
+
91
+ def write_book_views # :nodoc:
92
+ @writer.tag_elements('bookViews') { write_workbook_view }
93
+ end
94
+
95
+ def write_workbook_view # :nodoc:
96
+ attributes = [
97
+ ['xWindow', @x_window],
98
+ ['yWindow', @y_window],
99
+ ['windowWidth', @window_width],
100
+ ['windowHeight', @window_height]
101
+ ]
102
+ attributes << ['tabRatio', @tab_ratio] if @tab_ratio != 600
103
+ attributes << ['firstSheet', @firstsheet + 1] if @firstsheet > 0
104
+ attributes << ['activeTab', @activesheet] if @activesheet > 0
105
+ @writer.empty_tag('workbookView', attributes)
106
+ end
107
+
108
+ def write_calc_pr # :nodoc:
109
+ attributes = [['calcId', @calc_id]]
110
+
111
+ case @calc_mode
112
+ when 'manual'
113
+ attributes << %w[calcMode manual]
114
+ attributes << ['calcOnSave', 0]
115
+ when 'autoNoTable'
116
+ attributes << %w[calcMode autoNoTable]
117
+ end
118
+
119
+ attributes << ['fullCalcOnLoad', 1] if @calc_on_load
120
+
121
+ @writer.empty_tag('calcPr', attributes)
122
+ end
123
+
124
+ def write_ext_lst # :nodoc:
125
+ @writer.tag_elements('extLst') { write_ext }
126
+ end
127
+
128
+ def write_ext # :nodoc:
129
+ attributes = [
130
+ ['xmlns:mx', "#{OFFICE_URL}mac/excel/2008/main"],
131
+ ['uri', uri]
132
+ ]
133
+ @writer.tag_elements('ext', attributes) { write_mx_arch_id }
134
+ end
135
+
136
+ def write_mx_arch_id # :nodoc:
137
+ @writer.empty_tag('mx:ArchID', ['Flags', 2])
138
+ end
139
+
140
+ def write_defined_names # :nodoc:
141
+ return unless ptrue?(@defined_names)
142
+
143
+ @writer.tag_elements('definedNames') do
144
+ @defined_names.each { |defined_name| write_defined_name(defined_name) }
145
+ end
146
+ end
147
+
148
+ def write_defined_name(defined_name) # :nodoc:
149
+ name, id, range, hidden = defined_name
150
+
151
+ attributes = [['name', name]]
152
+ attributes << ['localSheetId', id.to_s] unless id == -1
153
+ attributes << %w[hidden 1] if hidden
154
+
155
+ @writer.data_element('definedName', range, attributes)
156
+ end
157
+
158
+ def write_io(str) # :nodoc:
159
+ @writer << str
160
+ str
161
+ end
162
+ end
163
+ end
164
+ end