axlsx 1.1.4 → 1.2.0

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 (196) hide show
  1. data/.yardopts +5 -2
  2. data/CHANGELOG.md +39 -0
  3. data/README.md +108 -31
  4. data/Rakefile +11 -3
  5. data/examples/basic_charts.rb +54 -0
  6. data/examples/chart_colors.rb +17 -2
  7. data/examples/data_validation.rb +50 -0
  8. data/examples/example.rb +130 -47
  9. data/examples/example.xlsx +0 -0
  10. data/examples/example_streamed.xlsx +0 -0
  11. data/examples/extractive.pdf +0 -0
  12. data/examples/extractive.rb +3 -0
  13. data/examples/no-use_autowidth.xlsx +0 -0
  14. data/examples/scraping_html.rb +91 -0
  15. data/examples/shared_strings_example.xlsx +0 -0
  16. data/examples/sheet_protection.rb +10 -0
  17. data/examples/sheet_view.rb +34 -0
  18. data/examples/two_cell_anchor_image.rb +11 -0
  19. data/lib/axlsx/content_type/content_type.rb +2 -0
  20. data/lib/axlsx/content_type/default.rb +30 -15
  21. data/lib/axlsx/content_type/override.rb +29 -14
  22. data/lib/axlsx/doc_props/app.rb +161 -104
  23. data/lib/axlsx/doc_props/core.rb +9 -5
  24. data/lib/axlsx/drawing/ax_data_source.rb +7 -6
  25. data/lib/axlsx/drawing/axis.rb +82 -36
  26. data/lib/axlsx/drawing/bar_3D_chart.rb +49 -45
  27. data/lib/axlsx/drawing/bar_series.rb +2 -1
  28. data/lib/axlsx/drawing/cat_axis.rb +43 -39
  29. data/lib/axlsx/drawing/chart.rb +65 -54
  30. data/lib/axlsx/drawing/d_lbls.rb +100 -0
  31. data/lib/axlsx/drawing/drawing.rb +20 -8
  32. data/lib/axlsx/drawing/graphic_frame.rb +2 -1
  33. data/lib/axlsx/drawing/line_3D_chart.rb +3 -10
  34. data/lib/axlsx/drawing/num_data.rb +2 -2
  35. data/lib/axlsx/drawing/num_data_source.rb +4 -1
  36. data/lib/axlsx/drawing/pic.rb +44 -4
  37. data/lib/axlsx/drawing/pie_3D_chart.rb +10 -7
  38. data/lib/axlsx/drawing/scatter_chart.rb +2 -8
  39. data/lib/axlsx/drawing/title.rb +21 -9
  40. data/lib/axlsx/drawing/two_cell_anchor.rb +46 -9
  41. data/lib/axlsx/drawing/view_3D.rb +41 -31
  42. data/lib/axlsx/drawing/vml_drawing.rb +42 -0
  43. data/lib/axlsx/drawing/vml_shape.rb +125 -0
  44. data/lib/axlsx/package.rb +44 -16
  45. data/lib/axlsx/rels/relationship.rb +3 -3
  46. data/lib/axlsx/rels/relationships.rb +1 -11
  47. data/lib/axlsx/stylesheet/gradient_fill.rb +1 -1
  48. data/lib/axlsx/stylesheet/styles.rb +1 -1
  49. data/lib/axlsx/stylesheet/table_style.rb +3 -3
  50. data/lib/axlsx/util/constants.rb +28 -0
  51. data/lib/axlsx/util/simple_typed_list.rb +15 -21
  52. data/lib/axlsx/util/validators.rb +80 -7
  53. data/lib/axlsx/version.rb +2 -7
  54. data/lib/axlsx/workbook/defined_name.rb +174 -0
  55. data/lib/axlsx/workbook/defined_names.rb +21 -0
  56. data/lib/axlsx/workbook/workbook.rb +65 -13
  57. data/lib/axlsx/workbook/worksheet/auto_filter.rb +34 -0
  58. data/lib/axlsx/workbook/worksheet/cell.rb +35 -7
  59. data/lib/axlsx/workbook/worksheet/col.rb +15 -0
  60. data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
  61. data/lib/axlsx/workbook/worksheet/comment.rb +101 -0
  62. data/lib/axlsx/workbook/worksheet/comments.rb +85 -0
  63. data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
  64. data/lib/axlsx/workbook/worksheet/data_bar.rb +1 -1
  65. data/lib/axlsx/workbook/worksheet/data_validation.rb +245 -0
  66. data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
  67. data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
  68. data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
  69. data/lib/axlsx/workbook/worksheet/page_setup.rb +113 -0
  70. data/lib/axlsx/workbook/worksheet/pane.rb +144 -0
  71. data/lib/axlsx/workbook/worksheet/print_options.rb +63 -0
  72. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
  73. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
  74. data/lib/axlsx/workbook/worksheet/row.rb +36 -20
  75. data/lib/axlsx/workbook/worksheet/selection.rb +111 -0
  76. data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
  77. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +24 -0
  78. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +224 -0
  79. data/lib/axlsx/workbook/worksheet/sheet_view.rb +379 -0
  80. data/lib/axlsx/workbook/worksheet/table.rb +2 -2
  81. data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
  82. data/lib/axlsx/workbook/worksheet/worksheet.rb +377 -255
  83. data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
  84. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
  85. data/lib/axlsx.rb +30 -15
  86. data/test/content_type/tc_content_type.rb +1 -6
  87. data/test/doc_props/tc_app.rb +31 -1
  88. data/test/doc_props/tc_core.rb +3 -1
  89. data/test/drawing/tc_axis.rb +38 -3
  90. data/test/drawing/tc_bar_3D_chart.rb +12 -12
  91. data/test/drawing/tc_bar_series.rb +1 -2
  92. data/test/drawing/tc_cat_axis.rb +3 -3
  93. data/test/drawing/tc_chart.rb +29 -9
  94. data/test/drawing/tc_d_lbls.rb +47 -0
  95. data/test/drawing/tc_drawing.rb +11 -5
  96. data/test/drawing/tc_hyperlink.rb +4 -5
  97. data/test/drawing/tc_line_series.rb +7 -3
  98. data/test/drawing/tc_num_data.rb +5 -1
  99. data/test/drawing/tc_pic.rb +22 -2
  100. data/test/drawing/tc_pie_3D_chart.rb +4 -8
  101. data/test/drawing/tc_pie_series.rb +7 -2
  102. data/test/drawing/tc_scatter_chart.rb +6 -1
  103. data/test/drawing/tc_scatter_series.rb +1 -1
  104. data/test/drawing/tc_series.rb +1 -1
  105. data/test/drawing/tc_title.rb +16 -0
  106. data/test/drawing/tc_two_cell_anchor.rb +1 -2
  107. data/test/drawing/tc_view_3D.rb +18 -18
  108. data/test/drawing/tc_vml_drawing.rb +25 -0
  109. data/test/drawing/tc_vml_shape.rb +100 -0
  110. data/test/rels/tc_relationship.rb +1 -0
  111. data/test/stylesheet/tc_gradient_fill.rb +8 -0
  112. data/test/stylesheet/tc_pattern_fill.rb +7 -1
  113. data/test/stylesheet/tc_styles.rb +3 -4
  114. data/test/stylesheet/tc_table_style.rb +8 -0
  115. data/test/stylesheet/tc_table_style_element.rb +10 -1
  116. data/test/tc_helper.rb +1 -0
  117. data/test/tc_package.rb +93 -17
  118. data/test/util/tc_simple_typed_list.rb +13 -0
  119. data/test/util/tc_validators.rb +95 -9
  120. data/test/workbook/tc_defined_name.rb +41 -0
  121. data/test/workbook/tc_workbook.rb +5 -3
  122. data/test/workbook/worksheet/table/tc_table.rb +3 -11
  123. data/test/workbook/worksheet/tc_cell.rb +30 -6
  124. data/test/workbook/worksheet/tc_col.rb +9 -0
  125. data/test/workbook/worksheet/tc_comment.rb +57 -0
  126. data/test/workbook/worksheet/tc_comments.rb +57 -0
  127. data/test/workbook/worksheet/tc_conditional_formatting.rb +44 -0
  128. data/test/workbook/worksheet/tc_data_bar.rb +1 -1
  129. data/test/workbook/worksheet/tc_data_validation.rb +265 -0
  130. data/test/workbook/worksheet/tc_page_setup.rb +138 -0
  131. data/test/workbook/worksheet/tc_pane.rb +94 -0
  132. data/test/workbook/worksheet/tc_print_options.rb +72 -0
  133. data/test/workbook/worksheet/tc_protected_range.rb +17 -0
  134. data/test/workbook/worksheet/tc_row.rb +32 -14
  135. data/test/workbook/worksheet/tc_selection.rb +94 -0
  136. data/test/workbook/worksheet/tc_sheet_protection.rb +117 -0
  137. data/test/workbook/worksheet/tc_sheet_view.rb +214 -0
  138. data/test/workbook/worksheet/tc_worksheet.rb +138 -48
  139. metadata +140 -80
  140. data/examples/#extractive.csv# +0 -0
  141. data/examples/#extractive.rb# +0 -45
  142. data/examples/chart_colors.rb~ +0 -0
  143. data/examples/chart_colors.xlsx +0 -0
  144. data/examples/colored_series_data.xlsx +0 -0
  145. data/examples/conditional_formatting/getting_barred.xlsx +0 -0
  146. data/examples/example.csv +0 -1000
  147. data/examples/extractive.csv +0 -1
  148. data/examples/extractive.csv~ +0 -1
  149. data/examples/extractive.rb~ +0 -3
  150. data/examples/extractive.xlsx +0 -0
  151. data/examples/stack.rb +0 -21
  152. data/examples/stack.rb~ +0 -27
  153. data/examples/stack.xlsx +0 -0
  154. data/examples/~$chart_colors.xlsx +0 -0
  155. data/examples/~$extractive.xlsx +0 -0
  156. data/lib/axlsx/drawing/ax_data_source.rb~ +0 -55
  157. data/lib/axlsx/drawing/data_source.rb~ +0 -51
  158. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  159. data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
  160. data/lib/axlsx/drawing/num_data.rb~ +0 -51
  161. data/lib/axlsx/drawing/num_data_source.rb~ +0 -54
  162. data/lib/axlsx/drawing/num_val.rb~ +0 -40
  163. data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
  164. data/lib/axlsx/drawing/ref.rb~ +0 -41
  165. data/lib/axlsx/drawing/str_data.rb~ +0 -58
  166. data/lib/axlsx/drawing/str_val.rb~ +0 -35
  167. data/lib/axlsx/util/cbf.rb +0 -333
  168. data/lib/axlsx/util/cfb.rb~ +0 -201
  169. data/lib/axlsx/util/font_tables.rb~ +0 -0
  170. data/lib/axlsx/util/ms_off_crypto.rb +0 -189
  171. data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
  172. data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
  173. data/lib/axlsx/util/parser.rb~ +0 -6
  174. data/lib/axlsx/util/storage.rb~ +0 -0
  175. data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
  176. data/lib/axlsx/workbook/worksheet/cfvo.rb~ +0 -0
  177. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  178. data/lib/axlsx/workbook/worksheet/color_scale.rb~ +0 -46
  179. data/lib/axlsx/workbook/worksheet/data_bar.rb~ +0 -0
  180. data/lib/axlsx/workbook/worksheet/icon_set.rb~ +0 -95
  181. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  182. data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
  183. data/lib/schema/dc.xsd~ +0 -118
  184. data/lib/schema/dcterms.xsd~ +0 -331
  185. data/lib/schema/opc-coreProperties.xsd~ +0 -50
  186. data/test/drawing/tc_data_source.rb~ +0 -30
  187. data/test/drawing/tc_num_data.rb~ +0 -35
  188. data/test/drawing/tc_num_val.rb~ +0 -29
  189. data/test/drawing/tc_str_data.rb~ +0 -30
  190. data/test/drawing/tc_str_val.rb~ +0 -26
  191. data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
  192. data/test/workbook/worksheet/tc_cfvo.rb~ +0 -20
  193. data/test/workbook/worksheet/tc_col.rb~ +0 -10
  194. data/test/workbook/worksheet/tc_color_scale.rb~ +0 -0
  195. data/test/workbook/worksheet/tc_data_bar.rb~ +0 -0
  196. data/test/workbook/worksheet/tc_icon_set.rb~ +0 -0
data/lib/axlsx/package.rb CHANGED
@@ -80,9 +80,8 @@ module Axlsx
80
80
 
81
81
  # Serialize your workbook to disk as an xlsx document.
82
82
  #
83
- # @param [File] output The file you want to serialize your package to
83
+ # @param [String] output The name of the file you want to serialize your package to
84
84
  # @param [Boolean] confirm_valid Validate the package prior to serialization.
85
- # @option options stream indicates if we should be writing to a stream or a file. True for stream, nil for file
86
85
  # @return [Boolean] False if confirm_valid and validation errors exist. True if the package was serialized
87
86
  # @note A tremendous amount of effort has gone into ensuring that you cannot create invalid xlsx documents.
88
87
  # confirm_valid should be used in the rare case that you cannot open the serialized file.
@@ -90,10 +89,15 @@ module Axlsx
90
89
  # @example
91
90
  # # This is how easy it is to create a valid xlsx file. Of course you might want to add a sheet or two, and maybe some data, styles and charts.
92
91
  # # Take a look at the README for an example of how to do it!
93
- # f = File.open('test.xlsx', 'w')
94
- # Package.new.serialize(f)
95
92
  #
96
- # # You will find a file called test.xlsx
93
+ # #serialize to a file
94
+ # p = Axlsx::Package.new
95
+ # # ......add cool stuff to your workbook......
96
+ # p.serialize("example.xlsx")
97
+ #
98
+ # # Serialize to a stream
99
+ # s = p.to_stream()
100
+ # File.open('example_streamed.xlsx', 'w') { |f| f.write(s.read) }
97
101
  def serialize(output, confirm_valid=false)
98
102
  return false unless !confirm_valid || self.validate.empty?
99
103
  Zip::ZipOutputStream.open(output) do |zip|
@@ -152,18 +156,18 @@ module Axlsx
152
156
  # @return [Zip::ZipOutputStream]
153
157
  def write_parts(zip)
154
158
  p = parts
155
- p.each do |part|
156
- unless part[:doc].nil?
157
- zip.put_next_entry(part[:entry]);
158
- entry = ['1.9.2', '1.9.3'].include?(RUBY_VERSION) ? part[:doc].force_encoding('BINARY') : part[:doc]
159
- zip.puts(entry)
160
- end
161
- unless part[:path].nil?
162
- zip.put_next_entry(part[:entry]);
163
- # binread for 1.9.3
164
- zip.write IO.respond_to?(:binread) ? IO.binread(part[:path]) : IO.read(part[:path])
165
- end
159
+ p.each do |part|
160
+ unless part[:doc].nil?
161
+ zip.put_next_entry(part[:entry])
162
+ entry = ['1.9.2', '1.9.3'].include?(RUBY_VERSION) ? part[:doc].force_encoding('BINARY') : part[:doc]
163
+ zip.puts(entry)
164
+ end
165
+ unless part[:path].nil?
166
+ zip.put_next_entry(part[:entry]);
167
+ # binread for 1.9.3
168
+ zip.write IO.respond_to?(:binread) ? IO.binread(part[:path]) : IO.read(part[:path])
166
169
  end
170
+ end
167
171
  zip
168
172
  end
169
173
 
@@ -180,15 +184,24 @@ module Axlsx
180
184
  {:entry => CONTENT_TYPES_PN, :doc => content_types.to_xml_string, :schema => CONTENT_TYPES_XSD},
181
185
  {:entry => WORKBOOK_PN, :doc => workbook.to_xml_string, :schema => SML_XSD}
182
186
  ]
187
+
183
188
  workbook.drawings.each do |drawing|
184
189
  @parts << {:entry => "xl/#{drawing.rels_pn}", :doc => drawing.relationships.to_xml_string, :schema => RELS_XSD}
185
190
  @parts << {:entry => "xl/#{drawing.pn}", :doc => drawing.to_xml_string, :schema => DRAWING_XSD}
186
191
  end
187
192
 
193
+
188
194
  workbook.tables.each do |table|
189
195
  @parts << {:entry => "xl/#{table.pn}", :doc => table.to_xml_string, :schema => SML_XSD}
190
196
  end
191
197
 
198
+ workbook.comments.each do|comment|
199
+ if comment.size > 0
200
+ @parts << { :entry => "xl/#{comment.pn}", :doc => comment.to_xml_string, :schema => SML_XSD }
201
+ @parts << { :entry => "xl/#{comment.vml_drawing.pn}", :doc => comment.vml_drawing.to_xml_string, :schema => nil }
202
+ end
203
+ end
204
+
192
205
  workbook.charts.each do |chart|
193
206
  @parts << {:entry => "xl/#{chart.pn}", :doc => chart.to_xml_string, :schema => DRAWING_XSD}
194
207
  end
@@ -229,18 +242,33 @@ module Axlsx
229
242
  # @private
230
243
  def content_types
231
244
  c_types = base_content_types
245
+
232
246
  workbook.drawings.each do |drawing|
233
247
  c_types << Axlsx::Override.new(:PartName => "/xl/#{drawing.pn}",
234
248
  :ContentType => DRAWING_CT)
235
249
  end
250
+
236
251
  workbook.charts.each do |chart|
237
252
  c_types << Axlsx::Override.new(:PartName => "/xl/#{chart.pn}",
238
253
  :ContentType => CHART_CT)
239
254
  end
255
+
240
256
  workbook.tables.each do |table|
241
257
  c_types << Axlsx::Override.new(:PartName => "/xl/#{table.pn}",
242
258
  :ContentType => TABLE_CT)
243
259
  end
260
+
261
+ workbook.comments.each do |comment|
262
+ if comment.size > 0
263
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{comment.pn}",
264
+ :ContentType => COMMENT_CT)
265
+ end
266
+ end
267
+
268
+ if workbook.comments.size > 0
269
+ c_types << Axlsx::Default.new(:Extension => "vml", :ContentType => VML_DRAWING_CT)
270
+ end
271
+
244
272
  workbook.worksheets.each do |sheet|
245
273
  c_types << Axlsx::Override.new(:PartName => "/xl/#{sheet.pn}",
246
274
  :ContentType => WORKSHEET_CT)
@@ -30,9 +30,9 @@ module Axlsx
30
30
  attr_reader :TargetMode
31
31
 
32
32
  # creates a new relationship
33
- # @param [String] Type The type of the relationship
34
- # @param [String] Target The target for the relationship
35
- # @option [Symbol] target_mode only accepts :external.
33
+ # @param [String] type The type of the relationship
34
+ # @param [String] target The target for the relationship
35
+ # @option [Symbol] :target_mode only accepts :external.
36
36
  def initialize(type, target, options={})
37
37
  self.Target=target
38
38
  self.Type=type
@@ -10,23 +10,13 @@ require 'axlsx/rels/relationship.rb'
10
10
  def initialize
11
11
  super Relationship
12
12
  end
13
-
13
+
14
14
  def to_xml_string(str = '')
15
15
  str << '<?xml version="1.0" encoding="UTF-8"?>'
16
16
  str << '<Relationships xmlns="' << RELS_R << '">'
17
17
  each_with_index { |rel, index| rel.to_xml_string(index+1, str) }
18
18
  str << '</Relationships>'
19
19
  end
20
- # Serializes the relationships document.
21
- # @return [String]
22
- def to_xml()
23
- builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
24
- xml.Relationships(:xmlns => Axlsx::RELS_R) {
25
- each_with_index { |rel, index| rel.to_xml(xml, "rId#{index+1}") }
26
- }
27
- end
28
- builder.to_xml(:save_with => 0)
29
- end
30
20
 
31
21
  end
32
22
  end
@@ -68,7 +68,7 @@ module Axlsx
68
68
  # @param [String] str
69
69
  # @return [String]
70
70
  def to_xml_string(str = '')
71
- str << '<gradientFill'
71
+ str << '<gradientFill '
72
72
  h = self.instance_values.reject { |k,v| k.to_sym == :stop }
73
73
  str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
74
74
  str << '>'
@@ -133,7 +133,7 @@ module Axlsx
133
133
  # @option options [Integer] family The font family to use.
134
134
  # @option options [String] font_name The name of the font to use
135
135
  # @option options [Integer] num_fmt The number format to apply
136
- # @option options [String] format_code The formatting to apply. If this is specified, num_fmt is ignored.
136
+ # @option options [String] format_code The formatting to apply.
137
137
  # @option options [Integer|Hash] border The border style to use.
138
138
  # @option options [String] bg_color The background color to apply to the cell
139
139
  # @option options [Boolean] hidden Indicates if the cell should be hidden
@@ -40,10 +40,10 @@ module Axlsx
40
40
  # @param [String] str
41
41
  # @return [String]
42
42
  def to_xml_string(str = '')
43
- attr = self.instance_values.select { |k, v| [:name, :pivot, :table].include? k }
44
- attr[:count] = self.size
43
+ attrs = instance_values.reject { |k, v| ![:name, :pivot, :table].include?(k) }
44
+ attrs[:count] = self.size
45
45
  str << '<tableStyle '
46
- str << attr.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
46
+ str << attrs.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
47
47
  str << '>'
48
48
  each { |table_style_el| table_style_el.to_xml_string(str) }
49
49
  str << '</tableStyle>'
@@ -79,6 +79,18 @@ module Axlsx
79
79
  # image rels namespace
80
80
  HYPERLINK_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink"
81
81
 
82
+ # comment rels namespace
83
+ COMMENT_R = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"
84
+
85
+ # comment relation for nil target
86
+ COMMENT_R_NULL = "http://purl.oclc.org/ooxml/officeDocument/relationships/comments"
87
+
88
+ #vml drawing relation namespace
89
+ VML_DRAWING_R = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing'
90
+
91
+ # VML Drawing content type
92
+ VML_DRAWING_CT = "application/vnd.openxmlformats-officedocument.vmlDrawing"
93
+
82
94
  # table content type
83
95
  TABLE_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml"
84
96
 
@@ -109,6 +121,9 @@ module Axlsx
109
121
  # chart content type
110
122
  CHART_CT = "application/vnd.openxmlformats-officedocument.drawingml.chart+xml"
111
123
 
124
+ # comments content type
125
+ COMMENT_CT = "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml"
126
+
112
127
  # jpeg content type
113
128
  JPEG_CT = "image/jpeg"
114
129
 
@@ -172,6 +187,9 @@ module Axlsx
172
187
  # drawing rels part
173
188
  DRAWING_RELS_PN = "drawings/_rels/drawing%d.xml.rels"
174
189
 
190
+ # vml drawing part
191
+ VML_DRAWING_PN = "drawings/vmlDrawing%d.vml"
192
+
175
193
  # drawing part
176
194
  TABLE_PN = "tables/table%d.xml"
177
195
 
@@ -181,6 +199,9 @@ module Axlsx
181
199
  # chart part
182
200
  IMAGE_PN = "media/image%d.%s"
183
201
 
202
+ # comment part
203
+ COMMENT_PN = "comments%d.xml"
204
+
184
205
  # location of schema files for validation
185
206
  SCHEMA_BASE = File.dirname(__FILE__)+'/../../schema/'
186
207
 
@@ -228,6 +249,10 @@ module Axlsx
228
249
 
229
250
  # error message for sheets that use a name which is longer than 31 bytes
230
251
  ERR_SHEET_NAME_TOO_LONG = "Your worksheet name '%s' is too long. Worksheet names must be 31 characters (bytes) or less"
252
+
253
+ # error message for sheets that use a name which includes a colon
254
+
255
+ ERR_SHEET_NAME_COLON_FORBIDDEN = "Your worksheet name '%s' contains a colon, which is not allowed by MS Excel and will cause repair warnings. Please change the name of your sheet."
231
256
 
232
257
  # error message for duplicate sheet names
233
258
  ERR_DUPLICATE_SHEET_NAME = "There is already a worksheet in this workbook named '%s'. Please use a unique name"
@@ -240,4 +265,7 @@ module Axlsx
240
265
 
241
266
  # error message for invalid angles
242
267
  ERR_ANGLE = "Angles must be a value between -90 and 90. You provided: %s"
268
+
269
+ # error message for non 'integerish' value
270
+ ERR_INTEGERISH = "You value must be, or be castable via to_i, an Integer. You provided %s"
243
271
  end
@@ -18,7 +18,7 @@ module Axlsx
18
18
 
19
19
  # Creats a new typed list
20
20
  # @param [Array, Class] type An array of Class objects or a single Class object
21
- # @param [String] serialize The tag name to use in serialization
21
+ # @param [String] serialize_as The tag name to use in serialization
22
22
  # @raise [ArgumentError] if all members of type are not Class objects
23
23
  def initialize type, serialize_as=nil
24
24
  if type.is_a? Array
@@ -50,6 +50,18 @@ module Axlsx
50
50
  @locked_at = nil
51
51
  self
52
52
  end
53
+
54
+ # join operator
55
+ # @param [Array] v the array to join
56
+ # @raise [ArgumentError] if any of the values being joined are not
57
+ # one of the allowed types
58
+ # @return [SimpleTypedList]
59
+ def +(v)
60
+ v.each do |item|
61
+ DataTypeValidator.validate "SimpleTypedList.+", @allowed_types, item
62
+ @list << item
63
+ end
64
+ end
53
65
 
54
66
  # Concat operator
55
67
  # @param [Any] v the data to be added
@@ -60,12 +72,7 @@ module Axlsx
60
72
  @list << v
61
73
  @list.size - 1
62
74
  end
63
-
64
- # alternate of << method
65
- # @see <<
66
- def push(v)
67
- self.<< v
68
- end
75
+ alias :push :<<
69
76
 
70
77
  # delete the item from the list
71
78
  # @param [Any] v The item to be deleted.
@@ -149,25 +156,12 @@ module Axlsx
149
156
 
150
157
  def to_xml_string(str = '')
151
158
  classname = @allowed_types[0].name.split('::').last
152
- el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
159
+ el_name = serialize_as.to_s || (classname[0,1].downcase + classname[1..-1])
153
160
  str << '<' << el_name << ' count="' << @list.size.to_s << '">'
154
161
  @list.each { |item| item.to_xml_string(str) }
155
162
  str << '</' << el_name << '>'
156
163
  end
157
164
 
158
- # Serializes the list
159
- # If the serialize_as property is set, it is used as the parent node name.
160
- # If the serialize_as property is nil, the first item in the list of allowed_types will be used, having the first letter of the class changed to lower case.
161
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
162
- # @return [String]
163
- def to_xml(xml)
164
- classname = @allowed_types[0].name.split('::').last
165
- el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
166
- xml.send(el_name, :count=>@list.size) {
167
- @list.each { |item| item.to_xml(xml) }
168
- }
169
- end
170
-
171
165
  end
172
166
 
173
167
 
@@ -45,8 +45,20 @@ module Axlsx
45
45
  true
46
46
  end
47
47
 
48
+
49
+ # Requires that the value can be converted to an integer
50
+ # @para, [Any] v the value to validate
51
+ # @raise [ArgumentError] raised if the value cannot be converted to an integer
52
+ def self.validate_integerish(v)
53
+ raise ArgumentError, (ERR_INTEGERISH % v.inspect) unless (v.respond_to?(:to_i) && v.to_i.is_a?(Integer))
54
+ end
55
+
56
+ # Requires that the value is between -54000000 and 54000000
57
+ # @param [Any] v The value validated
58
+ # @raise [ArgumentError] raised if the value cannot be converted to an integer between the allowed angle values for chart label rotation.
59
+ # @return [Boolean] true if the data is valid
48
60
  def self.validate_angle(v)
49
- raise ArgumentError, (ERR_ANGLE % v.inspect) unless (v >= -5400000 && v <= 5400000)
61
+ raise ArgumentError, (ERR_ANGLE % v.inspect) unless (v.to_i >= -5400000 && v.to_i <= 5400000)
50
62
  end
51
63
  # Requires that the value is a Fixnum or Integer and is greater or equal to 0
52
64
  # @param [Any] v The value validated
@@ -90,6 +102,27 @@ module Axlsx
90
102
  DataTypeValidator.validate :float, Float, v
91
103
  end
92
104
 
105
+ # Requires that the value is a string containing a positive decimal number followed by one of the following units:
106
+ # "mm", "cm", "in", "pt", "pc", "pi"
107
+ def self.validate_number_with_unit(v)
108
+ RegexValidator.validate "number_with_unit", /\A[0-9]+(\.[0-9]+)?(mm|cm|in|pt|pc|pi)\Z/, v
109
+ end
110
+
111
+ # Requires that the value is an integer ranging from 10 to 400.
112
+ def self.validate_scale_10_400(v)
113
+ DataTypeValidator.validate "page_scale", [Fixnum, Integer], v, lambda { |arg| arg >= 10 && arg <= 400 }
114
+ end
115
+
116
+ # Requires that the value is an integer ranging from 10 to 400 or 0.
117
+ def self.validate_scale_0_10_400(v)
118
+ DataTypeValidator.validate "page_scale", [Fixnum, Integer], v, lambda { |arg| arg == 0 || (arg >= 10 && arg <= 400) }
119
+ end
120
+
121
+ # Requires that the value is one of :default, :landscape, or :portrait.
122
+ def self.validate_page_orientation(v)
123
+ RestrictionValidator.validate "page_orientation", [:default, :landscape, :portrait], v
124
+ end
125
+
93
126
  # Requires that the value is valid pattern type.
94
127
  # valid pattern types must be one of :none, :solid, :mediumGray, :darkGray, :lightGray, :darkHorizontal, :darkVertical, :darkDown,
95
128
  # :darkUp, :darkGrid, :darkTrellis, :lightHorizontal, :lightVertical, :lightDown, :lightUp, :lightGrid, :lightTrellis, :gray125, or :gray0625.
@@ -104,8 +137,6 @@ module Axlsx
104
137
  # thisMonth, lastMonth, nextMonth, thisWeek, lastWeek, nextWeek
105
138
  def self.validate_time_period_type(v)
106
139
  RestrictionValidator.validate :time_period_type, [:today, :yesterday, :tomorrow, :last7Days, :thisMonth, :lastMonth, :nextMonth, :thisWeek, :lastWeek, :nextWeek], v
107
-
108
-
109
140
  end
110
141
 
111
142
  # Requires that the value is one of the valid ST_IconSet types
@@ -150,7 +181,7 @@ module Axlsx
150
181
  # Requires that the value is a valid scatterStyle
151
182
  # must be one of :none | :line | :lineMarker | :marker | :smooth | :smoothMarker
152
183
  # must be one of "none" | "line" | "lineMarker" | "marker" | "smooth" | "smoothMarker"
153
- # @param [Symbol|String] the value to validate
184
+ # @param [Symbol|String] v the value to validate
154
185
  def self.validate_scatter_style(v)
155
186
  Axlsx::RestrictionValidator.validate "ScatterChart.scatterStyle", [:none, :line, :lineMarker, :marker, :smooth, :smoothMarker], v.to_sym
156
187
  end
@@ -169,17 +200,17 @@ module Axlsx
169
200
  end
170
201
 
171
202
  # Requires that the value is a valid content_type
172
- # TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, DRAWING_CT are allowed
203
+ # TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, DRAWING_CT, COMMENT_CT are allowed
173
204
  # @param [Any] v The value validated
174
205
  def self.validate_content_type(v)
175
- RestrictionValidator.validate :content_type, [TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, JPEG_CT, GIF_CT, PNG_CT, DRAWING_CT], v
206
+ RestrictionValidator.validate :content_type, [TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, JPEG_CT, GIF_CT, PNG_CT, DRAWING_CT, COMMENT_CT, VML_DRAWING_CT], v
176
207
  end
177
208
 
178
209
  # Requires that the value is a valid relationship_type
179
210
  # XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R, IMAGE_R, HYPERLINK_R, SHARED_STRINGS_R are allowed
180
211
  # @param [Any] v The value validated
181
212
  def self.validate_relationship_type(v)
182
- RestrictionValidator.validate :relationship_type, [XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R, IMAGE_R, HYPERLINK_R, SHARED_STRINGS_R], v
213
+ RestrictionValidator.validate :relationship_type, [XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R, IMAGE_R, HYPERLINK_R, SHARED_STRINGS_R, COMMENT_R, VML_DRAWING_R, COMMENT_R_NULL], v
183
214
  end
184
215
 
185
216
  # Requires that the value is a valid table element type
@@ -189,4 +220,46 @@ module Axlsx
189
220
  RestrictionValidator.validate :table_element_type, [:wholeTable, :headerRow, :totalRow, :firstColumn, :lastColumn, :firstRowStripe, :secondRowStripe, :firstColumnStripe, :secondColumnStripe, :firstHeaderCell, :lastHeaderCell, :firstTotalCell, :lastTotalCell, :firstSubtotalColumn, :secondSubtotalColumn, :thirdSubtotalColumn, :firstSubtotalRow, :secondSubtotalRow, :thirdSubtotalRow, :blankRow, :firstColumnSubheading, :secondColumnSubheading, :thirdColumnSubheading, :firstRowSubheading, :secondRowSubheading, :thirdRowSubheading, :pageFieldLabels, :pageFieldValues], v
190
221
  end
191
222
 
223
+ # Requires that the value is a valid data_validation_error_style
224
+ # :information, :stop, :warning
225
+ # @param [Any] v The value validated
226
+ def self.validate_data_validation_error_style(v)
227
+ RestrictionValidator.validate :validate_data_validation_error_style, [:information, :stop, :warning], v
228
+ end
229
+
230
+ # Requires that the value is valid data validation operator.
231
+ # valid operators must be one of lessThan, lessThanOrEqual, equal,
232
+ # notEqual, greaterThanOrEqual, greaterThan, between, notBetween
233
+ # @param [Any] v The value validated
234
+ def self.validate_data_validation_operator(v)
235
+ RestrictionValidator.validate :data_validation_operator, [:lessThan, :lessThanOrEqual, :equal, :notEqual, :greaterThanOrEqual, :greaterThan, :between, :notBetween], v
236
+ end
237
+
238
+ # Requires that the value is valid data validation type.
239
+ # valid types must be one of custom, data, decimal, list, none, textLength, time, whole
240
+ # @param [Any] v The value validated
241
+ def self.validate_data_validation_type(v)
242
+ RestrictionValidator.validate :data_validation_type, [:custom, :data, :decimal, :list, :none, :textLength, :time, :whole], v
243
+ end
244
+
245
+ # Requires that the value is a valid sheet view type.
246
+ # valid types must be one of normal, page_break_preview, page_layout
247
+ # @param [Any] v The value validated
248
+ def self.validate_sheet_view_type(v)
249
+ RestrictionValidator.validate :sheet_view_type, [:normal, :page_break_preview, :page_layout], v
250
+ end
251
+
252
+ # Requires that the value is a valid active pane type.
253
+ # valid types must be one of bottom_left, bottom_right, top_left, top_right
254
+ # @param [Any] v The value validated
255
+ def self.validate_pane_type(v)
256
+ RestrictionValidator.validate :active_pane_type, [:bottom_left, :bottom_right, :top_left, :top_right], v
257
+ end
258
+
259
+ # Requires that the value is a valid split state type.
260
+ # valid types must be one of frozen, frozen_split, split
261
+ # @param [Any] v The value validated
262
+ def self.validate_split_state_type(v)
263
+ RestrictionValidator.validate :split_state_type, [:frozen, :frozen_split, :split], v
264
+ end
192
265
  end
data/lib/axlsx/version.rb CHANGED
@@ -1,10 +1,5 @@
1
1
  # encoding: UTF-8
2
2
  module Axlsx
3
-
4
- # The version of the gem
5
- # When using bunle exec rake and referencing the gem on github or locally
6
- # it will use the gemspec, which preloads this constant for the gem's version.
7
- # We check to make sure that it has not already been loaded
8
- VERSION="1.1.4" unless defined? Axlsx::VERSION
9
-
3
+ # The current version
4
+ VERSION="1.2.0"
10
5
  end
@@ -0,0 +1,174 @@
1
+ # <definedNames>
2
+ # <definedName name="_xlnm.Print_Titles" localSheetId="0">Sheet1!$1:$1</definedName>
3
+ # </definedNames>
4
+
5
+ #<xsd:complexType name="CT_DefinedName">
6
+ # <xsd:simpleContent>
7
+ # <xsd:extension base="ST_Formula">
8
+ # <xsd:attribute name="name" type="s:ST_Xstring" use="required"/>
9
+ # <xsd:attribute name="comment" type="s:ST_Xstring" use="optional"/>
10
+ # <xsd:attribute name="customMenu" type="s:ST_Xstring" use="optional"/>
11
+ # <xsd:attribute name="description" type="s:ST_Xstring" use="optional"/>
12
+ # <xsd:attribute name="help" type="s:ST_Xstring" use="optional"/>
13
+ # <xsd:attribute name="statusBar" type="s:ST_Xstring" use="optional"/>
14
+ # <xsd:attribute name="localSheetId" type="xsd:unsignedInt" use="optional"/>
15
+ # <xsd:attribute name="hidden" type="xsd:boolean" use="optional" default="false"/>
16
+ # <xsd:attribute name="function" type="xsd:boolean" use="optional" default="false"/>
17
+ # <xsd:attribute name="vbProcedure" type="xsd:boolean" use="optional" default="false"/>
18
+ # <xsd:attribute name="xlm" type="xsd:boolean" use="optional" default="false"/>
19
+ # <xsd:attribute name="functionGroupId" type="xsd:unsignedInt" use="optional"/>
20
+ # <xsd:attribute name="shortcutKey" type="s:ST_Xstring" use="optional"/>
21
+ # <xsd:attribute name="publishToServer" type="xsd:boolean" use="optional" default="false"/>
22
+ # <xsd:attribute name="workbookParameter" type="xsd:boolean" use="optional" default="false"/>
23
+ # </xsd:extenstion>
24
+ # </xsd:simpleContent>
25
+
26
+ module Axlsx
27
+ # This element defines the defined names that are defined within this workbook.
28
+ # Defined names are descriptive text that is used to represents a cell, range of cells, formula, or constant value.
29
+ # Use easy-to-understand names, such as Products, to refer to hard to understand ranges, such as Sales!C20:C30.
30
+ # A defined name in a formula can make it easier to understand the purpose of the formula.
31
+ # @example
32
+ # The formula =SUM(FirstQuarterSales) might be easier to identify than =SUM(C20:C30
33
+ #
34
+ # Names are available to any sheet.
35
+ # @example
36
+ # If the name ProjectedSales refers to the range A20:A30 on the first worksheet in a workbook,
37
+ # you can use the name ProjectedSales on any other sheet in the same workbook to refer to range A20:A30 on the first worksheet.
38
+ # Names can also be used to represent formulas or values that do not change (constants).
39
+ #
40
+ # @example
41
+ # The name SalesTax can be used to represent the sales tax amount (such as 6.2 percent) applied to sales transactions.
42
+ # You can also link to a defined name in another workbook, or define a name that refers to cells in another workbook.
43
+ #
44
+ # @example
45
+ # The formula =SUM(Sales.xls!ProjectedSales) refers to the named range ProjectedSales in the workbook named Sales.
46
+ # A compliant producer or consumer considers a defined name in the range A1-XFD1048576 to be an error.
47
+ # All other names outside this range can be defined as names and overrides a cell reference if an ambiguity exists.
48
+ #
49
+ # @example
50
+ # For clarification: LOG10 is always a cell reference, LOG10() is always formula, LOGO1000 can be a defined name that overrides a cell reference.
51
+ class DefinedName
52
+ # creates a new DefinedName.
53
+ # @param [String] formula - the formula the defined name references
54
+ # @param [Hash] options - A hash of key/value pairs that will be mapped to this instances attributes.
55
+ #
56
+ # @option [String] name - Specifies the name that appears in the user interface for the defined name.
57
+ # This attribute is required.
58
+ # The following built-in names are defined in this SpreadsheetML specification:
59
+ # Print
60
+ # _xlnm.Print_Area: this defined name specifies the workbook's print area.
61
+ # _xlnm.Print_Titles: this defined name specifies the row(s) or column(s) to repeat
62
+ # the top of each printed page.
63
+ # Filter & Advanced Filter
64
+ # _xlnm.Criteria: this defined name refers to a range containing the criteria values
65
+ # to be used in applying an advanced filter to a range of data.
66
+ # _xlnm._FilterDatabase: can be one of the following
67
+ # a. this defined name refers to a range to which an advanced filter has been
68
+ # applied. This represents the source data range, unfiltered.
69
+ # b. This defined name refers to a range to which an AutoFilter has been
70
+ # applied.
71
+ # _xlnm.Extract: this defined name refers to the range containing the filtered output
72
+ # values resulting from applying an advanced filter criteria to a source range.
73
+ # Miscellaneous
74
+ # _xlnm.Consolidate_Area: the defined name refers to a consolidation area.
75
+ # _xlnm.Database: the range specified in the defined name is from a database data source.
76
+ # _xlnm.Sheet_Title: the defined name refers to a sheet title.
77
+ # @option [String] comment - A comment to optionally associate with the name
78
+ # @option [String] custom_menu - The menu text for the defined name
79
+ # @option [String] description - An optional description for the defined name
80
+ # @option [String] help - The help topic to display for this defined name
81
+ # @option [String] status_bar - The text to display on the application status bar when this defined name has focus
82
+ # @option [String] local_sheet_id - Specifies the sheet index in this workbook where data from an external reference is displayed
83
+ # @option [Boolean] hidden - Specifies a boolean value that indicates whether the defined name is hidden in the user interface.
84
+ # @option [Boolean] function - Specifies a boolean value that indicates that the defined name refers to a user-defined function.
85
+ # This attribute is used when there is an add-in or other code project associated with the file.
86
+ # @option [Boolean] vb_proceedure - Specifies a boolean value that indicates whether the defined name is related to an external function, command, or other executable code.
87
+ # @option [Boolean] xlm - Specifies a boolean value that indicates whether the defined name is related to an external function, command, or other executable code.
88
+ # @option [Integer] function_group_id - Specifies the function group index if the defined name refers to a function.
89
+ # The function group defines the general category for the function.
90
+ # This attribute is used when there is an add-in or other code project associated with the file.
91
+ # See Open Office XML Part 1 for more info.
92
+ # @option [String] short_cut_key - Specifies the keyboard shortcut for the defined name.
93
+ # @option [Boolean] publish_to_server - Specifies a boolean value that indicates whether the defined name is included in the
94
+ # version of the workbook that is published to or rendered on a Web or application server.
95
+ # @option [Boolean] workbook_parameter - Specifies a boolean value that indicates that the name is used as a workbook parameter on a
96
+ # version of the workbook that is published to or rendered on a Web or application server.
97
+ def initialize(formula, options={})
98
+ @formula = formula
99
+ options.each do |o|
100
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
101
+ end
102
+ end
103
+ attr_reader :local_sheet_id
104
+
105
+ # The local sheet index (0-based)
106
+ # @param [Integer] value the unsinged integer index of the sheet this defined_name applies to.
107
+ def local_sheet_id=(value)
108
+ Axlsx::validate_unsigned_int(value)
109
+ @local_sheet_id = value
110
+ end
111
+
112
+ # string attributes that will be added when this class is evaluated
113
+ STRING_ATTRIBUTES = [:short_cut_key, :status_bar, :help, :description, :custom_menu, :comment]
114
+
115
+ # boolean attributes that will be added when this class is evaluated
116
+ BOOLEAN_ATTRIBUTES = [:workbook_parameter, :publish_to_server, :xlm, :vb_proceedure, :function, :hidden]
117
+
118
+ # Dynamically create string attribute accessors
119
+ STRING_ATTRIBUTES.each do |attr|
120
+ class_eval %{
121
+ # The #{attr} attribute reader
122
+ # @return [String]
123
+ attr_reader :#{attr}
124
+
125
+ # The #{attr} writer
126
+ # @param [String] value The value to assign to #{attr}
127
+ # @return [String]
128
+ def #{attr}=(value)
129
+ Axlsx::validate_string(value)
130
+ @#{attr}= value
131
+ end
132
+ }
133
+ end
134
+
135
+ # Dynamically create boolean attribute accessors
136
+ BOOLEAN_ATTRIBUTES.each do |attr|
137
+ class_eval %{
138
+ # The #{attr} attribute reader
139
+ # @return [Boolean]
140
+ attr_reader :#{attr}
141
+
142
+ # The #{attr} writer
143
+ # @param [Boolean] value The value to assign to #{attr}
144
+ # @return [Boolean]
145
+ def #{attr}=(value)
146
+ Axlsx::validate_boolean(value)
147
+ @#{attr} = value
148
+ end
149
+ }
150
+ end
151
+
152
+ attr_reader :name
153
+ # The name of this defined name. Please refer to the class documentation for more information
154
+ def name=(value)
155
+ Axlsx::RestrictionValidator.validate 'DefinedName.name', %w(_xlnm.Print_Area _xlnm.Print_Titles _xlnm.Criteria _xlnm._FilterDatabase _xlnm.Extract _xlnm.Consolidate_Area _xlnm.Database _xlnm.Sheet_Title), value
156
+ @name = value
157
+ end
158
+
159
+ # The formula this defined name references
160
+ attr_reader :formula
161
+
162
+ def to_xml_string(str='')
163
+ raise ArgumentError, 'you must specify the name for this defined name. Please read the documentation for Axlsx::DefinedName for more details' unless name
164
+ str << '<definedName'
165
+ instance_values.each do |name, value|
166
+ unless name == 'formula'
167
+ str << ' ' << Axlsx::camel(name, false) << "='#{value}'"
168
+ end
169
+ end
170
+ str << '>' << @formula
171
+ str << '</definedName>'
172
+ end
173
+ end
174
+ end