write_xlsx 1.07.0 → 1.09.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/Changes +40 -0
  3. data/README.md +1 -1
  4. data/examples/background.rb +19 -0
  5. data/examples/ignore_errors.rb +39 -0
  6. data/ignore_errors.xlsx +0 -0
  7. data/lib/write_xlsx/chart/axis.rb +3 -3
  8. data/lib/write_xlsx/chart/scatter.rb +0 -15
  9. data/lib/write_xlsx/chart/series.rb +1 -1
  10. data/lib/write_xlsx/chart.rb +31 -33
  11. data/lib/write_xlsx/chartsheet.rb +3 -3
  12. data/lib/write_xlsx/drawing.rb +118 -55
  13. data/lib/write_xlsx/format.rb +11 -179
  14. data/lib/write_xlsx/package/app.rb +5 -5
  15. data/lib/write_xlsx/package/button.rb +8 -8
  16. data/lib/write_xlsx/package/comments.rb +8 -8
  17. data/lib/write_xlsx/package/conditional_format.rb +2 -8
  18. data/lib/write_xlsx/package/content_types.rb +18 -9
  19. data/lib/write_xlsx/package/core.rb +5 -5
  20. data/lib/write_xlsx/package/custom.rb +2 -2
  21. data/lib/write_xlsx/package/metadata.rb +159 -0
  22. data/lib/write_xlsx/package/packager.rb +22 -0
  23. data/lib/write_xlsx/package/shared_strings.rb +6 -6
  24. data/lib/write_xlsx/package/styles.rb +27 -14
  25. data/lib/write_xlsx/package/table.rb +31 -23
  26. data/lib/write_xlsx/package/theme.rb +1 -1
  27. data/lib/write_xlsx/package/vml.rb +43 -43
  28. data/lib/write_xlsx/shape.rb +17 -15
  29. data/lib/write_xlsx/sparkline.rb +340 -340
  30. data/lib/write_xlsx/utility.rb +9 -24
  31. data/lib/write_xlsx/version.rb +1 -1
  32. data/lib/write_xlsx/workbook.rb +193 -643
  33. data/lib/write_xlsx/worksheet/cell_data.rb +25 -3
  34. data/lib/write_xlsx/worksheet/data_validation.rb +21 -26
  35. data/lib/write_xlsx/worksheet/hyperlink.rb +4 -4
  36. data/lib/write_xlsx/worksheet/page_setup.rb +12 -12
  37. data/lib/write_xlsx/worksheet.rb +461 -4233
  38. data/test/drawing/{test_write_ext.rb → test_write_xdr_ext.rb} +2 -2
  39. data/test/perl_output/background.xlsx +0 -0
  40. data/test/perl_output/ignore_errors.xlsx +0 -0
  41. data/test/regression/images/logo.gif +0 -0
  42. data/test/regression/images/logo.jpg +0 -0
  43. data/test/regression/images/red.gif +0 -0
  44. data/test/regression/test_background01.rb +23 -0
  45. data/test/regression/test_background02.rb +23 -0
  46. data/test/regression/test_background03.rb +24 -0
  47. data/test/regression/test_background04.rb +25 -0
  48. data/test/regression/test_background05.rb +25 -0
  49. data/test/regression/test_background06.rb +31 -0
  50. data/test/regression/test_background07.rb +37 -0
  51. data/test/regression/test_chart_axis47.rb +52 -0
  52. data/test/regression/test_chart_axis48.rb +53 -0
  53. data/test/regression/test_chart_crossing01.rb +1 -1
  54. data/test/regression/test_chart_crossing05.rb +46 -0
  55. data/test/regression/test_chart_crossing06.rb +46 -0
  56. data/test/regression/test_chart_data_labels48.rb +55 -0
  57. data/test/regression/test_chart_data_labels49.rb +55 -0
  58. data/test/regression/test_chart_data_labels50.rb +57 -0
  59. data/test/regression/test_dynamic_array01.rb +25 -0
  60. data/test/regression/test_format16.rb +24 -0
  61. data/test/regression/test_format17.rb +24 -0
  62. data/test/regression/test_header04.rb +30 -0
  63. data/test/regression/test_hyperlink50.rb +27 -0
  64. data/test/regression/test_hyperlink51.rb +27 -0
  65. data/test/regression/test_ignore_error01.rb +23 -0
  66. data/test/regression/test_ignore_error02.rb +24 -0
  67. data/test/regression/test_ignore_error03.rb +26 -0
  68. data/test/regression/test_ignore_error04.rb +26 -0
  69. data/test/regression/test_ignore_error05.rb +32 -0
  70. data/test/regression/test_ignore_error06.rb +32 -0
  71. data/test/regression/test_image52.rb +26 -0
  72. data/test/regression/test_image53.rb +26 -0
  73. data/test/regression/test_image54.rb +26 -0
  74. data/test/regression/test_image55.rb +27 -0
  75. data/test/regression/test_image56.rb +23 -0
  76. data/test/regression/test_image57.rb +23 -0
  77. data/test/regression/test_protect04.rb +32 -0
  78. data/test/regression/test_protect05.rb +35 -0
  79. data/test/regression/test_protect06.rb +35 -0
  80. data/test/regression/test_protect07.rb +23 -0
  81. data/test/regression/test_set_column10.rb +55 -0
  82. data/test/regression/test_set_column11.rb +48 -0
  83. data/test/regression/test_set_row01.rb +35 -0
  84. data/test/regression/test_set_row02.rb +35 -0
  85. data/test/regression/test_set_row03.rb +35 -0
  86. data/test/regression/test_set_row04.rb +35 -0
  87. data/test/regression/test_table26.rb +38 -0
  88. data/test/regression/xlsx_files/background01.xlsx +0 -0
  89. data/test/regression/xlsx_files/background02.xlsx +0 -0
  90. data/test/regression/xlsx_files/background03.xlsx +0 -0
  91. data/test/regression/xlsx_files/background04.xlsx +0 -0
  92. data/test/regression/xlsx_files/background05.xlsx +0 -0
  93. data/test/regression/xlsx_files/background06.xlsx +0 -0
  94. data/test/regression/xlsx_files/background07.xlsx +0 -0
  95. data/test/regression/xlsx_files/chart_axis47.xlsx +0 -0
  96. data/test/regression/xlsx_files/chart_axis48.xlsx +0 -0
  97. data/test/regression/xlsx_files/chart_crossing05.xlsx +0 -0
  98. data/test/regression/xlsx_files/chart_crossing06.xlsx +0 -0
  99. data/test/regression/xlsx_files/chart_data_labels48.xlsx +0 -0
  100. data/test/regression/xlsx_files/chart_data_labels49.xlsx +0 -0
  101. data/test/regression/xlsx_files/chart_data_labels50.xlsx +0 -0
  102. data/test/regression/xlsx_files/dynamic_array01.xlsx +0 -0
  103. data/test/regression/xlsx_files/format16.xlsx +0 -0
  104. data/test/regression/xlsx_files/format17.xlsx +0 -0
  105. data/test/regression/xlsx_files/header04.xlsx +0 -0
  106. data/test/regression/xlsx_files/hyperlink50.xlsx +0 -0
  107. data/test/regression/xlsx_files/hyperlink51.xlsx +0 -0
  108. data/test/regression/xlsx_files/ignore_error01.xlsx +0 -0
  109. data/test/regression/xlsx_files/ignore_error02.xlsx +0 -0
  110. data/test/regression/xlsx_files/ignore_error03.xlsx +0 -0
  111. data/test/regression/xlsx_files/ignore_error04.xlsx +0 -0
  112. data/test/regression/xlsx_files/ignore_error05.xlsx +0 -0
  113. data/test/regression/xlsx_files/ignore_error06.xlsx +0 -0
  114. data/test/regression/xlsx_files/image52.xlsx +0 -0
  115. data/test/regression/xlsx_files/image53.xlsx +0 -0
  116. data/test/regression/xlsx_files/image54.xlsx +0 -0
  117. data/test/regression/xlsx_files/image55.xlsx +0 -0
  118. data/test/regression/xlsx_files/image56.xlsx +0 -0
  119. data/test/regression/xlsx_files/image57.xlsx +0 -0
  120. data/test/regression/xlsx_files/protect04.xlsx +0 -0
  121. data/test/regression/xlsx_files/protect05.xlsx +0 -0
  122. data/test/regression/xlsx_files/protect06.xlsx +0 -0
  123. data/test/regression/xlsx_files/protect07.xlsx +0 -0
  124. data/test/regression/xlsx_files/set_row01.xlsx +0 -0
  125. data/test/regression/xlsx_files/set_row03.xlsx +0 -0
  126. data/test/regression/xlsx_files/table26.xlsx +0 -0
  127. data/test/test_example_match.rb +43 -0
  128. data/test/utility/test_range.rb +20 -0
  129. data/test/worksheet/test_pixels_to_row_col.rb +46 -0
  130. metadata +190 -8
@@ -2,177 +2,20 @@
2
2
  require 'write_xlsx/utility'
3
3
 
4
4
  module Writexlsx
5
- # ==CELL FORMATTING
6
- #
7
- # This section describes the methods and properties that are available
8
- # for formatting cells in Excel. The properties of a cell that can be
9
- # formatted include: fonts, colours, patterns, borders, alignment and
10
- # number formatting.
11
- #
12
- # ===Creating and using a Format object
13
- #
14
- # Cell formatting is defined through a Format object. Format objects
15
- # are created by calling the workbook add_format() method as follows:
16
- #
17
- # format1 = workbook.add_format # Set properties later
18
- # format2 = workbook.add_format(props_hash) # Set at creation
19
- #
20
- # The format object holds all the formatting properties that can be applied
21
- # to a cell, a row or a column. The process of setting these properties is
22
- # discussed in the next section.
23
- #
24
- # Once a Format object has been constructed and its properties have been
25
- # set it can be passed as an argument to the worksheet write methods as
26
- # follows:
27
- #
28
- # worksheet.write( 0, 0, 'One', format )
29
- # worksheet.write_string( 1, 0, 'Two', format )
30
- # worksheet.write_number( 2, 0, 3, format )
31
- # worksheet.write_blank( 3, 0, format )
32
- #
33
- # Formats can also be passed to the worksheet set_row() and set_column()
34
- # methods to define the default property for a row or column.
35
- #
36
- # worksheet.set_row( 0, 15, format )
37
- # worksheet.set_column( 0, 0, 15, format )
38
- #
39
- # ===Format methods and Format properties
40
- #
41
- # The following table shows the Excel format categories, the formatting
42
- # properties that can be applied and the equivalent object method:
43
- #
44
- # Category Description Property Method Name
45
- # -------- ----------- -------- -----------
46
- # Font Font type font set_font()
47
- # Font size size set_size()
48
- # Font color color set_color()
49
- # Bold bold set_bold()
50
- # Italic italic set_italic()
51
- # Underline underline set_underline()
52
- # Strikeout font_strikeout set_font_strikeout()
53
- # Super/Subscript font_script set_font_script()
54
- # Outline font_outline set_font_outline()
55
- # Shadow font_shadow set_font_shadow()
56
- #
57
- # Number Numeric format num_format set_num_format()
58
- #
59
- # Protection Lock cells locked set_locked()
60
- # Hide formulas hidden set_hidden()
61
- #
62
- # Alignment Horizontal align align set_align()
63
- # Vertical align valign set_align()
64
- # Rotation rotation set_rotation()
65
- # Text wrap text_wrap set_text_wrap()
66
- # Justify last text_justlast set_text_justlast()
67
- # Center across center_across set_center_across()
68
- # Indentation indent set_indent()
69
- # Shrink to fit shrink set_shrink()
70
- #
71
- # Pattern Cell pattern pattern set_pattern()
72
- # Background color bg_color set_bg_color()
73
- # Foreground color fg_color set_fg_color()
74
- #
75
- # Border Cell border border set_border()
76
- # Bottom border bottom set_bottom()
77
- # Top border top set_top()
78
- # Left border left set_left()
79
- # Right border right set_right()
80
- # Border color border_color set_border_color()
81
- # Bottom color bottom_color set_bottom_color()
82
- # Top color top_color set_top_color()
83
- # Left color left_color set_left_color()
84
- # Right color right_color set_right_color()
85
- #
86
- # There are two ways of setting Format properties: by using the object
87
- # method interface or by setting the property directly. For example,
88
- # a typical use of the method interface would be as follows:
89
- #
90
- # format = workbook.add_format
91
- # format.set_bold
92
- # format.set_color( 'red' )
93
- #
94
- # By comparison the properties can be set directly by passing a hash
95
- # of properties to the Format constructor:
96
- #
97
- # format = workbook.add_format( :bold => 1, :color => 'red' )
98
- #
99
- # or after the Format has been constructed by means of the
100
- # set_format_properties() method as follows:
101
- #
102
- # format = workbook.add_format
103
- # format.set_format_properties( :bold => 1, :color => 'red' )
104
- #
105
- # You can also store the properties in one or more named hashes and pass
106
- # them to the required method:
107
- #
108
- # font = {
109
- # :font => 'Arial',
110
- # :size => 12,
111
- # :color => 'blue',
112
- # :bold => 1
113
- # }
114
- #
115
- # shading = {
116
- # :bg_color => 'green',
117
- # :pattern => 1
118
- # }
119
- #
120
- # format1 = workbook.add_format( font ) # Font only
121
- # format2 = workbook.add_format( font, shading ) # Font and shading
122
- #
123
- # The provision of two ways of setting properties might lead you to wonder
124
- # which is the best way. The method mechanism may be better is you prefer
125
- # setting properties via method calls (which the author did when the code
126
- # was first written) otherwise passing properties to the constructor has
127
- # proved to be a little more flexible and self documenting in practice.
128
- # An additional advantage of working with property hashes is that it allows
129
- # you to share formatting between workbook objects as shown in the example
130
- # above.
131
- #
132
- # ===Working with formats
133
- #
134
- # The default format is Arial 10 with all other properties off.
135
- #
136
- # Each unique format in WriteXLSX must have a corresponding Format
137
- # object. It isn't possible to use a Format with a write() method and then
138
- # redefine the Format for use at a later stage. This is because a Format
139
- # is applied to a cell not in its current state but in its final state.
140
- # Consider the following example:
141
- #
142
- # format = workbook.add_format
143
- # format.set_bold
144
- # format.set_color( 'red' )
145
- # worksheet.write( 'A1', 'Cell A1', format )
146
- # format.set_color( 'green' )
147
- # worksheet.write( 'B1', 'Cell B1', format )
148
- #
149
- # Cell A1 is assigned the Format format which is initially set to the colour
150
- # red. However, the colour is subsequently set to green. When Excel displays
151
- # Cell A1 it will display the final state of the Format which in this case
152
- # will be the colour green.
153
- #
154
- # In general a method call without an argument will turn a property on,
155
- # for example:
156
- #
157
- # format1 = workbook.add_format
158
- # format1.set_bold # Turns bold on
159
- # format1.set_bold( 1 ) # Also turns bold on
160
- # format1.set_bold( 0 ) # Turns bold off
161
- #
162
5
  class Format
163
6
  include Writexlsx::Utility
164
7
 
165
- attr_reader :xf_index, :dxf_index, :num_format # :nodoc:
8
+ attr_reader :xf_index, :dxf_index, :num_format # :nodoc:
166
9
  attr_reader :underline, :font_script, :size, :theme, :font, :font_family, :hyperlink, :xf_id # :nodoc:
167
- attr_reader :diag_type, :diag_color, :font_only, :color, :color_indexed # :nodoc:
168
- attr_reader :left, :left_color, :right, :right_color, :top, :top_color, :bottom, :bottom_color # :nodoc:
169
- attr_reader :font_scheme # :nodoc:
170
- attr_accessor :num_format_index, :border_index, :font_index # :nodoc:
171
- attr_accessor :fill_index, :font_condense, :font_extend, :diag_border # :nodoc:
172
- attr_accessor :bg_color, :fg_color, :pattern # :nodoc:
10
+ attr_reader :diag_type, :diag_color, :font_only, :color, :color_indexed # :nodoc:
11
+ attr_reader :left, :left_color, :right, :right_color, :top, :top_color, :bottom, :bottom_color # :nodoc:
12
+ attr_reader :font_scheme # :nodoc:
13
+ attr_accessor :num_format_index, :border_index, :font_index # :nodoc:
14
+ attr_accessor :fill_index, :font_condense, :font_extend, :diag_border # :nodoc:
15
+ attr_accessor :bg_color, :fg_color, :pattern # :nodoc:
173
16
 
174
- attr_accessor :dxf_bg_color, :dxf_fg_color # :nodoc:
175
- attr_reader :rotation, :bold, :italic, :font_strikeout
17
+ attr_accessor :dxf_bg_color, :dxf_fg_color # :nodoc:
18
+ attr_reader :rotation, :bold, :italic, :font_strikeout # :nodoc:
176
19
 
177
20
  def initialize(formats, params = {}) # :nodoc:
178
21
  @formats = formats
@@ -268,17 +111,6 @@ module Writexlsx
268
111
  #
269
112
  # Convert hashes of properties to method calls.
270
113
  #
271
- # The properties of an existing Format object can be also be set by means
272
- # of set_format_properties():
273
- #
274
- # format = workbook.add_format
275
- # format.set_format_properties(:bold => 1, :color => 'red');
276
- #
277
- # However, this method is here mainly for legacy reasons. It is preferable
278
- # to set the properties in the format constructor:
279
- #
280
- # format = workbook.add_format(:bold => 1, :color => 'red');
281
- #
282
114
  def set_format_properties(*properties) # :nodoc:
283
115
  return if properties.empty?
284
116
  properties.each do |property|
@@ -747,7 +579,7 @@ module Writexlsx
747
579
  writer.empty_tag('sz', [ ['val', size] ]) unless dxf_format
748
580
 
749
581
  if theme == -1
750
- # Ignore for excel2003_style
582
+ # Ignore for excel2003_style
751
583
  elsif ptrue?(theme)
752
584
  write_color(writer, 'theme', theme)
753
585
  elsif ptrue?(@color_indexed)
@@ -845,7 +677,7 @@ module Writexlsx
845
677
 
846
678
  def write_font_family_scheme(writer)
847
679
  if ptrue?(@font_family)
848
- writer.empty_tag('family', [ ['val', @font_family] ])
680
+ writer.empty_tag('family', [ ['val', @font_family] ])
849
681
  end
850
682
 
851
683
  if ptrue?(@font_charset)
@@ -7,6 +7,7 @@ module Writexlsx
7
7
  class App
8
8
 
9
9
  include Writexlsx::Utility
10
+ attr_writer :doc_security
10
11
 
11
12
  def initialize(workbook)
12
13
  @writer = Package::XMLWriterSimple.new
@@ -14,6 +15,7 @@ module Writexlsx
14
15
  @part_names = []
15
16
  @heading_pairs = []
16
17
  @properties = {}
18
+ @doc_security = 0
17
19
  end
18
20
 
19
21
  def set_xml_writer(filename)
@@ -103,8 +105,8 @@ module Writexlsx
103
105
 
104
106
  schema = 'http://schemas.openxmlformats.org/officeDocument/2006/'
105
107
  attributes = [
106
- ['xmlns', "#{schema}extended-properties"],
107
- ['xmlns:vt', "#{schema}docPropsVTypes"]
108
+ ['xmlns', "#{schema}extended-properties"],
109
+ ['xmlns:vt', "#{schema}docPropsVTypes"]
108
110
  ]
109
111
 
110
112
  @writer.tag_elements('Properties', attributes) { yield }
@@ -123,9 +125,7 @@ module Writexlsx
123
125
  # Write the <DocSecurity> element.
124
126
  #
125
127
  def write_doc_security
126
- data = 0
127
-
128
- @writer.data_element('DocSecurity', data)
128
+ @writer.data_element('DocSecurity', @doc_security)
129
129
  end
130
130
 
131
131
  #
@@ -50,8 +50,8 @@ module Writexlsx
50
50
  # attributes for <v:fill> element.
51
51
  def fill_attributes
52
52
  [
53
- ['color2', 'buttonFace [67]'],
54
- ['o:detectmouseclick', 't']
53
+ ['color2', 'buttonFace [67]'],
54
+ ['o:detectmouseclick', 't']
55
55
  ]
56
56
  end
57
57
 
@@ -60,9 +60,9 @@ module Writexlsx
60
60
  #
61
61
  def write_rotation_lock
62
62
  attributes = [
63
- ['v:ext', 'edit'],
64
- ['rotation', 't']
65
- ]
63
+ ['v:ext', 'edit'],
64
+ ['rotation', 't']
65
+ ]
66
66
  @writer.empty_tag('o:lock', attributes)
67
67
  end
68
68
 
@@ -71,9 +71,9 @@ module Writexlsx
71
71
  #
72
72
  def write_textbox
73
73
  attributes = [
74
- ['style', 'mso-direction-alt:auto'],
75
- ['o:singleclick', 'f']
76
- ]
74
+ ['style', 'mso-direction-alt:auto'],
75
+ ['o:singleclick', 'f']
76
+ ]
77
77
 
78
78
  @writer.tag_elements('v:textbox', attributes) do
79
79
  # Write the div element.
@@ -177,8 +177,8 @@ module Writexlsx
177
177
  #
178
178
  def write_textbox
179
179
  attributes = [
180
- ['style', 'mso-direction-alt:auto']
181
- ]
180
+ ['style', 'mso-direction-alt:auto']
181
+ ]
182
182
 
183
183
  @writer.tag_elements('v:textbox', attributes) do
184
184
  # Write the div element.
@@ -191,8 +191,8 @@ module Writexlsx
191
191
  #
192
192
  def write_client_data
193
193
  attributes = [
194
- ['ObjectType', 'Note']
195
- ]
194
+ ['ObjectType', 'Note']
195
+ ]
196
196
 
197
197
  @writer.tag_elements('x:ClientData', attributes) do
198
198
  @writer.empty_tag('x:MoveWithCells')
@@ -225,10 +225,10 @@ module Writexlsx
225
225
  @author = options[:author]
226
226
  @start_cell = options[:start_cell]
227
227
  @start_row, @start_col = if @start_cell
228
- substitute_cellref(@start_cell)
229
- else
230
- [ options[:start_row], options[:start_col] ]
231
- end
228
+ substitute_cellref(@start_cell)
229
+ else
230
+ [ options[:start_row], options[:start_col] ]
231
+ end
232
232
  @visible = options[:visible]
233
233
  @x_offset = options[:x_offset] || default_x_offset(col)
234
234
  @y_offset = options[:y_offset] || default_y_offset(row)
@@ -397,14 +397,8 @@ module Writexlsx
397
397
  def range_start_cell_for_conditional_formatting(*args) # :nodoc:
398
398
  row1, row2, col1, col2, user_range, param =
399
399
  row_col_param_for_conditional_formatting(*args)
400
- # If the first and last cell are the same write a single cell.
401
- if row1 == row2 && col1 == col2
402
- range = xl_rowcol_to_cell(row1, col1)
403
- @start_cell = range
404
- else
405
- range = xl_range(row1, row2, col1, col2)
406
- @start_cell = xl_rowcol_to_cell(row1, col1)
407
- end
400
+ range = xl_range(row1, row2, col1, col2)
401
+ @start_cell = xl_rowcol_to_cell(row1, col1)
408
402
 
409
403
  # Override with user defined multiple range if provided.
410
404
  range = user_range if user_range
@@ -165,9 +165,9 @@ module Writexlsx
165
165
  #
166
166
  def add_table_name(table_name)
167
167
  add_override(
168
- "/xl/tables/#{table_name}.xml",
169
- "#{App_document}spreadsheetml.table+xml"
170
- )
168
+ "/xl/tables/#{table_name}.xml",
169
+ "#{App_document}spreadsheetml.table+xml"
170
+ )
171
171
  end
172
172
 
173
173
  #
@@ -187,6 +187,15 @@ module Writexlsx
187
187
  add_override(custom, "#{App_document}custom-properties+xml")
188
188
  end
189
189
 
190
+ #
191
+ # Add the metadata file to the ContentTypes overrides.
192
+ #
193
+ def add_metadata
194
+ add_override(
195
+ "/xl/metadata.xml",
196
+ "#{App_document}spreadsheetml.sheetMetadata+xml"
197
+ )
198
+ end
190
199
 
191
200
  private
192
201
 
@@ -219,10 +228,10 @@ module Writexlsx
219
228
 
220
229
  def write_default_or_override(tag, param0, a)
221
230
  @writer.empty_tag(tag,
222
- [
223
- [param0, a[0]],
224
- ['ContentType', a[1]]
225
- ])
231
+ [
232
+ [param0, a[0]],
233
+ ['ContentType', a[1]]
234
+ ])
226
235
  end
227
236
 
228
237
  #
@@ -231,8 +240,8 @@ module Writexlsx
231
240
  def write_types
232
241
  xmlns = 'http://schemas.openxmlformats.org/package/2006/content-types'
233
242
  attributes = [
234
- ['xmlns', xmlns]
235
- ]
243
+ ['xmlns', xmlns]
244
+ ]
236
245
 
237
246
  @writer.tag_elements('Types', attributes) { yield }
238
247
  end
@@ -68,11 +68,11 @@ module Writexlsx
68
68
  xmlns_xsi = 'http://www.w3.org/2001/XMLSchema-instance'
69
69
 
70
70
  attributes = [
71
- ['xmlns:cp', xmlns_cp],
72
- ['xmlns:dc', xmlns_dc],
73
- ['xmlns:dcterms', xmlns_dcterms],
74
- ['xmlns:dcmitype', xmlns_dcmitype],
75
- ['xmlns:xsi', xmlns_xsi]
71
+ ['xmlns:cp', xmlns_cp],
72
+ ['xmlns:dc', xmlns_dc],
73
+ ['xmlns:dcterms', xmlns_dcterms],
74
+ ['xmlns:dcmitype', xmlns_dcmitype],
75
+ ['xmlns:xsi', xmlns_xsi]
76
76
  ]
77
77
 
78
78
  @writer.tag_elements('cp:coreProperties', attributes) { yield }
@@ -47,7 +47,7 @@ module Writexlsx
47
47
  @properties.each do |property|
48
48
  # Write the property element.
49
49
  write_property(property)
50
- end
50
+ end
51
51
  end
52
52
  end
53
53
 
@@ -112,7 +112,7 @@ module Writexlsx
112
112
  end
113
113
 
114
114
  @writer.data_element('vt:bool', data)
115
- end
115
+ end
116
116
 
117
117
  #
118
118
  # Write the <vt:filetime> element.
@@ -0,0 +1,159 @@
1
+ # -*- coding: utf-8 -*-
2
+ require 'write_xlsx/package/xml_writer_simple'
3
+ require 'write_xlsx/utility'
4
+
5
+ module Writexlsx
6
+ module Package
7
+ #
8
+ # Metadata - A class for writing the Excel XLSX metadata.xml file.
9
+ #
10
+ class Metadata
11
+ include Writexlsx::Utility
12
+
13
+ def initialize(workbook)
14
+ @writer = Package::XMLWriterSimple.new
15
+ @workbook = workbook
16
+ end
17
+
18
+ def set_xml_writer(filename)
19
+ @writer.set_xml_writer(filename)
20
+ end
21
+
22
+ def assemble_xml_file
23
+ write_xml_declaration do
24
+ # Write the metadata element.
25
+ write_metadata
26
+ # Write the metadataTypes element.
27
+ write_metadata_types
28
+ # Write the futureMetadata element.
29
+ write_future_metadata
30
+ # Write the cellMetadata element.
31
+ write_cell_metadata
32
+ @writer.end_tag('metadata')
33
+ end
34
+ end
35
+
36
+ private
37
+
38
+ #
39
+ # Write the <metadata> element.
40
+ #
41
+ def write_metadata
42
+ xmlns = 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'
43
+ xmlns_xda =
44
+ 'http://schemas.microsoft.com/office/spreadsheetml/2017/dynamicarray'
45
+
46
+ attributes = [
47
+ ['xmlns', xmlns],
48
+ ['xmlns:xda', xmlns_xda]
49
+ ]
50
+
51
+ @writer.start_tag('metadata', attributes)
52
+ end
53
+
54
+ #
55
+ # Write the <metadataTypes> element.
56
+ #
57
+ def write_metadata_types
58
+ attributes = [['count', 1 ]]
59
+
60
+ @writer.tag_elements('metadataTypes', attributes) do
61
+ # Write the metadataType element.
62
+ write_metadata_type
63
+ end
64
+ end
65
+
66
+ #
67
+ # Write the <metadataType> element.
68
+ #
69
+ def write_metadata_type
70
+ attributes = [
71
+ ['name', 'XLDAPR'],
72
+ ['minSupportedVersion', 120000],
73
+ ['copy', 1],
74
+ ['pasteAll', 1],
75
+ ['pasteValues', 1],
76
+ ['merge', 1],
77
+ ['splitFirst', 1],
78
+ ['rowColShift', 1],
79
+ ['clearFormats', 1],
80
+ ['clearComments', 1],
81
+ ['assign', 1],
82
+ ['coerce', 1],
83
+ ['cellMeta', 1]
84
+ ]
85
+
86
+ @writer.empty_tag('metadataType', attributes)
87
+ end
88
+
89
+ #
90
+ # Write the <futureMetadata> element.
91
+ #
92
+ def write_future_metadata
93
+ attributes = [
94
+ ['name', 'XLDAPR'],
95
+ ['count', 1]
96
+ ]
97
+
98
+ @writer.tag_elements('futureMetadata', attributes) do
99
+ @writer.tag_elements('bk') do
100
+ @writer.tag_elements('extLst') do
101
+ # Write the ext element.
102
+ write_ext();
103
+ end
104
+ end
105
+ end
106
+ end
107
+
108
+ #
109
+ # Write the <ext> element.
110
+ #
111
+ def write_ext
112
+ attributes = [[ 'uri', '{bdbb8cdc-fa1e-496e-a857-3c3f30c029c3}']]
113
+ @writer.tag_elements('ext', attributes) do
114
+ # Write the xda:dynamicArrayProperties element.
115
+ write_xda_dynamic_array_properties
116
+ end
117
+ end
118
+
119
+ #
120
+ # Write the <xda:dynamicArrayProperties> element.
121
+ #
122
+ def write_xda_dynamic_array_properties
123
+ attributes = [
124
+ ['fDynamic', 1],
125
+ ['fCollapsed', 0]
126
+ ]
127
+
128
+ @writer.empty_tag('xda:dynamicArrayProperties', attributes)
129
+ end
130
+
131
+ #
132
+ # Write the <cellMetadata> element.
133
+ #
134
+ def write_cell_metadata
135
+ count = 1
136
+
137
+ attributes = [['count', count]]
138
+
139
+ @writer.tag_elements('cellMetadata', attributes) do
140
+ @writer.tag_elements('bk') do
141
+ # Write the rc element.
142
+ write_rc
143
+ end
144
+ end
145
+ end
146
+
147
+ #
148
+ # Write the <rc> element.
149
+ #
150
+ def write_rc
151
+ attributes = [
152
+ ['t', 1],
153
+ ['v', 0]
154
+ ]
155
+ @writer.empty_tag('rc', attributes)
156
+ end
157
+ end
158
+ end
159
+ end
@@ -6,6 +6,7 @@ require 'write_xlsx/package/comments'
6
6
  require 'write_xlsx/package/content_types'
7
7
  require 'write_xlsx/package/core'
8
8
  require 'write_xlsx/package/custom'
9
+ require 'write_xlsx/package/metadata'
9
10
  require 'write_xlsx/package/relationships'
10
11
  require 'write_xlsx/package/shared_strings'
11
12
  require 'write_xlsx/package/styles'
@@ -56,6 +57,7 @@ module Writexlsx
56
57
  write_drawing_rels_files
57
58
  add_image_files
58
59
  add_vba_project
60
+ write_metadata_file
59
61
  end
60
62
 
61
63
  private
@@ -155,6 +157,7 @@ module Writexlsx
155
157
  app.add_named_ranges_parts
156
158
 
157
159
  app.set_properties(@workbook.doc_properties)
160
+ app.doc_security = @workbook.read_only
158
161
 
159
162
  FileUtils.mkdir_p("#{@package_dir}/docProps")
160
163
  app.set_xml_writer("#{@package_dir}/docProps/app.xml")
@@ -174,6 +177,20 @@ module Writexlsx
174
177
  core.assemble_xml_file
175
178
  end
176
179
 
180
+ #
181
+ # Write the metadata.xml file.
182
+ #
183
+ def write_metadata_file
184
+ metadata = Package::Metadata.new(@workbook)
185
+
186
+ return unless @workbook.has_metadata?
187
+
188
+ FileUtils.mkdir_p("#{@package_dir}/xl")
189
+
190
+ metadata.set_xml_writer( "#{@package_dir}/xl/metadata.xml")
191
+ metadata.assemble_xml_file
192
+ end
193
+
177
194
  #
178
195
  # Write the custom.xml file.
179
196
  #
@@ -210,6 +227,8 @@ module Writexlsx
210
227
  content.add_vba_project if @workbook.vba_project
211
228
  # Add the custom properties if present.
212
229
  content.add_custom_properties unless @workbook.custom_properties.empty?
230
+ # Add the metadata file if present.
231
+ content.add_metadata if @workbook.has_metadata?
213
232
 
214
233
  content.set_xml_writer("#{@package_dir}/[Content_Types].xml")
215
234
  content.assemble_xml_file
@@ -304,6 +323,9 @@ module Writexlsx
304
323
  rels.add_ms_package_relationship('/vbaProject', 'vbaProject.bin')
305
324
  end
306
325
 
326
+ # Add the metadata file if required.
327
+ rels.add_document_relationship('/sheetMetadata', 'metadata.xml') if @workbook.has_metadata?
328
+
307
329
  rels.set_xml_writer("#{@package_dir}/xl/_rels/workbook.xml.rels")
308
330
  rels.assemble_xml_file
309
331
  end