axlsx 1.1.7 → 1.1.8

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. data/README.md +41 -5
  2. data/Rakefile +3 -2
  3. data/examples/chart_colors.rb +18 -3
  4. data/examples/example.rb +100 -46
  5. data/examples/extractive.pdf +0 -0
  6. data/lib/axlsx.rb +7 -6
  7. data/lib/axlsx/content_type/content_type.rb +2 -0
  8. data/lib/axlsx/content_type/default.rb +21 -12
  9. data/lib/axlsx/content_type/override.rb +22 -11
  10. data/lib/axlsx/doc_props/app.rb +36 -32
  11. data/lib/axlsx/doc_props/core.rb +9 -5
  12. data/lib/axlsx/drawing/ax_data_source.rb +7 -6
  13. data/lib/axlsx/drawing/axis.rb +48 -27
  14. data/lib/axlsx/drawing/bar_3D_chart.rb +47 -37
  15. data/lib/axlsx/drawing/bar_series.rb +1 -0
  16. data/lib/axlsx/drawing/cat_axis.rb +42 -38
  17. data/lib/axlsx/drawing/chart.rb +34 -27
  18. data/lib/axlsx/drawing/drawing.rb +5 -4
  19. data/lib/axlsx/drawing/line_3D_chart.rb +1 -1
  20. data/lib/axlsx/drawing/num_data_source.rb +1 -1
  21. data/lib/axlsx/drawing/pie_3D_chart.rb +7 -7
  22. data/lib/axlsx/drawing/two_cell_anchor.rb +3 -8
  23. data/lib/axlsx/drawing/view_3D.rb +41 -31
  24. data/lib/axlsx/drawing/vml_drawing.rb +1 -1
  25. data/lib/axlsx/package.rb +11 -11
  26. data/lib/axlsx/rels/relationship.rb +3 -3
  27. data/lib/axlsx/stylesheet/styles.rb +1 -1
  28. data/lib/axlsx/util/constants.rb +4 -0
  29. data/lib/axlsx/util/simple_typed_list.rb +2 -2
  30. data/lib/axlsx/util/validators.rb +2 -2
  31. data/lib/axlsx/version.rb +1 -1
  32. data/lib/axlsx/workbook/workbook.rb +1 -2
  33. data/lib/axlsx/workbook/worksheet/cell.rb +1 -1
  34. data/lib/axlsx/workbook/worksheet/data_bar.rb +1 -1
  35. data/lib/axlsx/workbook/worksheet/page_setup.rb +9 -0
  36. data/lib/axlsx/workbook/worksheet/protected_range.rb +46 -0
  37. data/lib/axlsx/workbook/worksheet/worksheet.rb +180 -56
  38. data/test/content_type/tc_content_type.rb +1 -6
  39. data/test/doc_props/tc_core.rb +1 -1
  40. data/test/drawing/tc_axis.rb +8 -0
  41. data/test/drawing/tc_bar_3D_chart.rb +12 -12
  42. data/test/drawing/tc_bar_series.rb +0 -1
  43. data/test/drawing/tc_chart.rb +1 -5
  44. data/test/drawing/tc_pie_3D_chart.rb +3 -7
  45. data/test/drawing/tc_view_3D.rb +18 -18
  46. data/test/tc_package.rb +2 -0
  47. data/test/workbook/worksheet/tc_page_setup.rb +20 -3
  48. data/test/workbook/worksheet/tc_protected_range.rb +18 -0
  49. data/test/workbook/worksheet/tc_selection.rb +1 -1
  50. data/test/workbook/worksheet/tc_worksheet.rb +39 -18
  51. metadata +54 -103
  52. data/examples/axis-titles.xlsx +0 -0
  53. data/examples/basic_charts.xlsx +0 -0
  54. data/examples/chart_colors.xlsx +0 -0
  55. data/examples/charts.xlsx +0 -0
  56. data/examples/conditional_formatting/getting_barred.xlsx +0 -0
  57. data/examples/doc/_index.html +0 -84
  58. data/examples/doc/class_list.html +0 -47
  59. data/examples/doc/css/common.css +0 -1
  60. data/examples/doc/css/full_list.css +0 -55
  61. data/examples/doc/css/style.css +0 -322
  62. data/examples/doc/file_list.html +0 -46
  63. data/examples/doc/frames.html +0 -13
  64. data/examples/doc/index.html +0 -84
  65. data/examples/doc/js/app.js +0 -205
  66. data/examples/doc/js/full_list.js +0 -173
  67. data/examples/doc/js/jquery.js +0 -16
  68. data/examples/doc/method_list.html +0 -46
  69. data/examples/doc/top-level-namespace.html +0 -95
  70. data/examples/example.xlsx +0 -0
  71. data/examples/example_streamed.xlsx +0 -0
  72. data/examples/examples_saved.xlsx +0 -0
  73. data/examples/extractive.xlsx +0 -0
  74. data/examples/fish.xlsx +0 -0
  75. data/examples/no-use_autowidth.xlsx +0 -0
  76. data/examples/pareto.rb +0 -28
  77. data/examples/pareto.xlsx +0 -0
  78. data/examples/pie_chart_excel.xlsx +0 -0
  79. data/examples/pie_chart_saved.xlsx +0 -0
  80. data/examples/shared_strings_example.xlsx +0 -0
  81. data/examples/sheet_protection.xlsx +0 -0
  82. data/examples/sheet_view.xlsx +0 -0
  83. data/examples/two_cell_anchor_image.xlsx +0 -0
  84. data/examples/~$example.xlsx +0 -0
  85. data/lib/axlsx/drawing/ax_data_source.rb~ +0 -55
  86. data/lib/axlsx/drawing/data_source.rb~ +0 -51
  87. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  88. data/lib/axlsx/drawing/hyperlink.rb~ +0 -64
  89. data/lib/axlsx/drawing/num_data.rb~ +0 -51
  90. data/lib/axlsx/drawing/num_data_source.rb~ +0 -54
  91. data/lib/axlsx/drawing/num_val.rb~ +0 -40
  92. data/lib/axlsx/drawing/picture_locking.rb~ +0 -36
  93. data/lib/axlsx/drawing/ref.rb~ +0 -41
  94. data/lib/axlsx/drawing/str_data.rb~ +0 -58
  95. data/lib/axlsx/drawing/str_val.rb~ +0 -35
  96. data/lib/axlsx/drawing/vml_drawing.rb~ +0 -6
  97. data/lib/axlsx/drawing/vml_shape.rb~ +0 -61
  98. data/lib/axlsx/util/cbf.rb +0 -333
  99. data/lib/axlsx/util/cfb.rb~ +0 -201
  100. data/lib/axlsx/util/font_tables.rb~ +0 -0
  101. data/lib/axlsx/util/ms_off_crypto.rb +0 -189
  102. data/lib/axlsx/util/ms_off_crypto.rb~ +0 -3
  103. data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
  104. data/lib/axlsx/util/parser.rb~ +0 -6
  105. data/lib/axlsx/util/storage.rb~ +0 -0
  106. data/lib/axlsx/workbook/shared_strings_table.rb~ +0 -69
  107. data/lib/axlsx/workbook/worksheet/cfvo.rb~ +0 -0
  108. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  109. data/lib/axlsx/workbook/worksheet/color_scale.rb~ +0 -46
  110. data/lib/axlsx/workbook/worksheet/comment.rb~ +0 -91
  111. data/lib/axlsx/workbook/worksheet/comments.rb~ +0 -86
  112. data/lib/axlsx/workbook/worksheet/data_bar.rb~ +0 -0
  113. data/lib/axlsx/workbook/worksheet/icon_set.rb~ +0 -95
  114. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  115. data/lib/axlsx/workbook/worksheet/table.rb~ +0 -97
  116. data/lib/schema/dc.xsd~ +0 -118
  117. data/lib/schema/dcterms.xsd~ +0 -331
  118. data/lib/schema/opc-coreProperties.xsd~ +0 -50
  119. data/test/drawing/tc_data_source.rb~ +0 -30
  120. data/test/drawing/tc_num_data.rb~ +0 -35
  121. data/test/drawing/tc_num_val.rb~ +0 -29
  122. data/test/drawing/tc_str_data.rb~ +0 -30
  123. data/test/drawing/tc_str_val.rb~ +0 -26
  124. data/test/drawing/tc_vml_drawing.rb~ +0 -0
  125. data/test/workbook/worksheet/table/tc_table.rb~ +0 -72
  126. data/test/workbook/worksheet/tc_cfvo.rb~ +0 -20
  127. data/test/workbook/worksheet/tc_col.rb~ +0 -10
  128. data/test/workbook/worksheet/tc_color_scale.rb~ +0 -0
  129. data/test/workbook/worksheet/tc_data_bar.rb~ +0 -0
  130. data/test/workbook/worksheet/tc_icon_set.rb~ +0 -0
@@ -156,18 +156,18 @@ module Axlsx
156
156
  # @return [Zip::ZipOutputStream]
157
157
  def write_parts(zip)
158
158
  p = parts
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])
169
- 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)
170
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])
169
+ end
170
+ end
171
171
  zip
172
172
  end
173
173
 
@@ -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
@@ -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
@@ -249,6 +249,10 @@ module Axlsx
249
249
 
250
250
  # error message for sheets that use a name which is longer than 31 bytes
251
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."
252
256
 
253
257
  # error message for duplicate sheet names
254
258
  ERR_DUPLICATE_SHEET_NAME = "There is already a worksheet in this workbook named '%s'. Please use a unique name"
@@ -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
@@ -149,7 +149,7 @@ module Axlsx
149
149
 
150
150
  def to_xml_string(str = '')
151
151
  classname = @allowed_types[0].name.split('::').last
152
- el_name = serialize_as || (classname[0,1].downcase + classname[1..-1])
152
+ el_name = serialize_as.to_s || (classname[0,1].downcase + classname[1..-1])
153
153
  str << '<' << el_name << ' count="' << @list.size.to_s << '">'
154
154
  @list.each { |item| item.to_xml_string(str) }
155
155
  str << '</' << el_name << '>'
@@ -181,7 +181,7 @@ module Axlsx
181
181
  # Requires that the value is a valid scatterStyle
182
182
  # must be one of :none | :line | :lineMarker | :marker | :smooth | :smoothMarker
183
183
  # must be one of "none" | "line" | "lineMarker" | "marker" | "smooth" | "smoothMarker"
184
- # @param [Symbol|String] the value to validate
184
+ # @param [Symbol|String] v the value to validate
185
185
  def self.validate_scatter_style(v)
186
186
  Axlsx::RestrictionValidator.validate "ScatterChart.scatterStyle", [:none, :line, :lineMarker, :marker, :smooth, :smoothMarker], v.to_sym
187
187
  end
@@ -262,4 +262,4 @@ module Axlsx
262
262
  def self.validate_split_state_type(v)
263
263
  RestrictionValidator.validate :split_state_type, [:frozen, :frozen_split, :split], v
264
264
  end
265
- end
265
+ end
@@ -5,6 +5,6 @@ module Axlsx
5
5
  # When using bunle exec rake and referencing the gem on github or locally
6
6
  # it will use the gemspec, which preloads this constant for the gem's version.
7
7
  # We check to make sure that it has not already been loaded
8
- VERSION="1.1.7" unless defined? Axlsx::VERSION
8
+ VERSION="1.1.8" unless defined? Axlsx::VERSION
9
9
 
10
10
  end
@@ -2,6 +2,7 @@
2
2
  module Axlsx
3
3
 
4
4
  require 'axlsx/workbook/worksheet/date_time_converter.rb'
5
+ require 'axlsx/workbook/worksheet/protected_range.rb'
5
6
  require 'axlsx/workbook/worksheet/cell.rb'
6
7
  require 'axlsx/workbook/worksheet/page_margins.rb'
7
8
  require 'axlsx/workbook/worksheet/page_setup.rb'
@@ -100,7 +101,6 @@ require 'axlsx/workbook/worksheet/selection.rb'
100
101
  # @return [SimpleTypedList]
101
102
  attr_reader :tables
102
103
 
103
-
104
104
  # A colllection of comments associated with this workbook
105
105
  # @note The recommended way to manage comments is Worksheet#add_comment
106
106
  # @see Worksheet#add_comment
@@ -143,7 +143,6 @@ require 'axlsx/workbook/worksheet/selection.rb'
143
143
  @drawings = SimpleTypedList.new Drawing
144
144
  @charts = SimpleTypedList.new Chart
145
145
  @images = SimpleTypedList.new Pic
146
-
147
146
  # Are these even used????? Check package serialization parts
148
147
  @tables = SimpleTypedList.new Table
149
148
  @comments = SimpleTypedList.new Comments
@@ -142,7 +142,7 @@ module Axlsx
142
142
  # The inline color property for the cell
143
143
  # @return [Color]
144
144
  attr_reader :color
145
- # @param [String] The 8 character representation for an rgb color #FFFFFFFF"
145
+ # @param [String] v The 8 character representation for an rgb color #FFFFFFFF"
146
146
  def color=(v)
147
147
  @color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
148
148
  @is_text_run = true
@@ -65,7 +65,7 @@ module Axlsx
65
65
  def showValue=(v); Axlsx.validate_boolean(v); @showValue = v end
66
66
 
67
67
  # Sets the color for the data bars.
68
- # @param [Color|String] The color object, or rgb string value to apply
68
+ # @param [Color|String] v The color object, or rgb string value to apply
69
69
  def color=(v)
70
70
  @color = v if v.is_a? Color
71
71
  self.color.rgb = v if v.is_a? String
@@ -92,6 +92,15 @@ module Axlsx
92
92
  [@fit_to_width, @fit_to_height]
93
93
  end
94
94
 
95
+
96
+ # helper method for worksheet to determine if the page setup is configured for fit to page printing
97
+ # We treat any page set up that has a value set for fit_to_width or fit_to_height value as fit_to_page.
98
+ # @return [Boolean]
99
+ def fit_to_page?
100
+ # is there some better what to express this?
101
+ (fit_to_width != nil || fit_to_height != nil)
102
+ end
103
+
95
104
  # Serializes the page settings element.
96
105
  # @param [String] str
97
106
  # @return [String]
@@ -0,0 +1,46 @@
1
+ module Axlsx
2
+ # The Protected Range class represents a set of cells in the worksheet
3
+ # @note the recommended way to manage protected ranges with via Worksheet#protect_range
4
+ # @see Worksheet#protect_range
5
+ class ProtectedRange
6
+
7
+ # The reference for the protected range
8
+ # @return [String]
9
+ attr_reader :sqref
10
+
11
+ # The name of the protected range
12
+ # @return [String]
13
+ attr_reader :name
14
+
15
+ # Initializes a new protected range object
16
+ # @option [String] sqref The cell range reference to protect. This can be an absolute or a relateve range however, it only applies to the current sheet.
17
+ # @option [String] name An optional name for the protected name.
18
+ def initialize(options={})
19
+ options.each do |o|
20
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
21
+ end
22
+ yield self if block_given?
23
+ end
24
+
25
+ # @see sqref
26
+ def sqref=(v)
27
+ Axlsx.validate_string(v)
28
+ @sqref = v
29
+ end
30
+
31
+ # @see name
32
+ def name=(v)
33
+ Axlsx.validate_string(v)
34
+ @name = v
35
+ end
36
+
37
+ # serializes the proteted range
38
+ # @param [String] str if this string object is provided we append
39
+ # our output to that object. Use this - it helps limit the number of
40
+ # objects created during serialization
41
+ def to_xml_string(str="")
42
+ attrs = self.instance_values.reject{ |key, value| value == nil }
43
+ str << '<protectedRange ' << attrs.map { |key, value| '' << key << '="' << value.to_s << '"' }.join(' ') << '/>'
44
+ end
45
+ end
46
+ end
@@ -16,7 +16,13 @@ module Axlsx
16
16
  yield @sheet_protection if block_given?
17
17
  @sheet_protection
18
18
  end
19
-
19
+
20
+ # A collection of protected ranges in the worksheet
21
+ # @note The recommended way to manage protected ranges is with Worksheet#protect_range
22
+ # @see Worksheet#protect_range
23
+ # @return [SimpleTypedList] The protected ranges for this worksheet
24
+ attr_reader :protected_ranges
25
+
20
26
  # The sheet view object for this worksheet
21
27
  # @return [SheetView]
22
28
  # @see [SheetView]
@@ -34,6 +40,8 @@ module Axlsx
34
40
  # @return [Array] of Table
35
41
  attr_reader :tables
36
42
 
43
+ # The comments associated with this worksheet
44
+ # @return [SimpleTypedList]
37
45
  attr_reader :comments
38
46
 
39
47
  # The rows in this worksheet
@@ -81,8 +89,9 @@ module Axlsx
81
89
  # If you want the worksheet to fit on more pages (e.g. 2x2), set {PageSetup#fit_to_width} and {PageSetup#fit_to_height} accordingly.
82
90
  # @return Boolean
83
91
  # @see #page_setup
84
- def fit_to_page
85
- (@page_setup != nil && (@page_setup.fit_to_width != nil || @page_setup.fit_to_height != nil))
92
+ def fit_to_page?
93
+ return false unless @page_setup
94
+ @page_setup.fit_to_page?
86
95
  end
87
96
 
88
97
 
@@ -110,7 +119,6 @@ module Axlsx
110
119
  @page_margins ||= PageMargins.new
111
120
  yield @page_margins if block_given?
112
121
  @page_margins
113
-
114
122
  end
115
123
 
116
124
  # Page setup settings for printing the worksheet.
@@ -188,7 +196,7 @@ module Axlsx
188
196
  @print_options = PrintOptions.new options[:print_options] if options[:print_options]
189
197
  @rows = SimpleTypedList.new Row
190
198
  @column_info = SimpleTypedList.new Col
191
- # @cols = SimpleTypedList.new Cell
199
+ @protected_ranges = SimpleTypedList.new ProtectedRange
192
200
  @tables = SimpleTypedList.new Table
193
201
 
194
202
  options.each do |o|
@@ -217,7 +225,7 @@ module Axlsx
217
225
  cf.add_rules rules
218
226
  @conditional_formattings << cf
219
227
  end
220
-
228
+
221
229
  # Add data validation to this worksheet.
222
230
  #
223
231
  # @param [String] cells The cells the validation will apply to.
@@ -237,23 +245,37 @@ module Axlsx
237
245
  # worksheet.merge_cells worksheet.rows.first.cells[(2..4)]
238
246
  # #alternatively you can do it from a single cell
239
247
  # worksheet["C1"].merge worksheet["E1"]
240
- # @param [Array, string]
248
+ # @param [Array, string] cells
241
249
  def merge_cells(cells)
242
250
  @merged_cells << if cells.is_a?(String)
243
251
  cells
244
- elsif cells.is_a?(Array)
245
- cells = cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
246
- "#{cells.first.r}:#{cells.last.r}"
247
- end
252
+ elsif cells.is_a?(Array)
253
+ cells = cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
254
+ "#{cells.first.r}:#{cells.last.r}"
255
+ end
248
256
  end
249
257
 
258
+ # Adds a new protected cell range to the worksheet. Note that protected ranges are only in effect when sheet protection is enabled.
259
+ # @param [String|Array] cells The string reference for the cells to protect or an array of cells.
260
+ # @return [ProtectedRange]
261
+ # @note When using an array of cells, a contiguous range is created from the minimum top left to the maximum top bottom of the cells provided.
262
+ def protect_range(cells)
263
+ sqref = if cells.is_a?(String)
264
+ cells
265
+ elsif cells.is_a?(SimpleTypedList)
266
+ cells = cells.sort { |x, y| [x.index, x.row.index] <=> [y.index, y.row.index] }
267
+ "#{cells.first.r}:#{cells.last.r}"
268
+ end
269
+ @protected_ranges << ProtectedRange.new(:sqref => sqref, :name => 'Range#{@protected_ranges.size}')
270
+ @protected_ranges.last
271
+ end
250
272
 
251
273
  # The demensions of a worksheet. This is not actually a required element by the spec,
252
274
  # but at least a few other document readers expect this for conversion
253
275
  # @return [String] the A1:B2 style reference for the first and last row column intersection in the workbook
254
276
  def dimension
255
277
  dim_start = rows.first.cells.first == nil ? 'A1' : rows.first.cells.first.r
256
- dim_end = rows.last.cells.last == nil ? 'AA:200' : rows.last.cells.last.r
278
+ dim_end = rows.last.cells.last == nil ? 'AA200' : rows.last.cells.last.r
257
279
  "#{dim_start}:#{dim_end}"
258
280
  end
259
281
 
@@ -281,7 +303,7 @@ module Axlsx
281
303
  # @return [Boolean]
282
304
  def fit_to_page=(v)
283
305
  warn('axlsx::DEPRECIATED: Worksheet#fit_to_page has been depreciated. This value will automatically be set for you when you use PageSetup#fit_to.')
284
- fit_to_page
306
+ fit_to_page?
285
307
  end
286
308
 
287
309
 
@@ -300,6 +322,8 @@ module Axlsx
300
322
  def name=(v)
301
323
  DataTypeValidator.validate "Worksheet.name", String, v
302
324
  raise ArgumentError, (ERR_SHEET_NAME_TOO_LONG % v) if v.size > 31
325
+ raise ArgumentError, (ERR_SHEET_NAME_COLON_FORBIDDEN % v) if v.include? ':'
326
+ v = Axlsx::coder.encode(v)
303
327
  sheet_names = @workbook.worksheets.map { |s| s.name }
304
328
  raise ArgumentError, (ERR_DUPLICATE_SHEET_NAME % v) if sheet_names.include?(v)
305
329
  @name=v
@@ -402,8 +426,9 @@ module Axlsx
402
426
 
403
427
  # Set the style for cells in a specific row
404
428
  # @param [Integer] index or range of indexes in the table
405
- # @param [Integer] the cellXfs index
406
- # @option options [Integer] col_offset only cells after this column will be updated.
429
+ # @param [Integer] style the cellXfs index
430
+ # @param [Hash] options the options used when applying the style
431
+ # @option [Integer] :col_offset only cells after this column will be updated.
407
432
  # @note You can also specify the style in the add_row call
408
433
  # @see Worksheet#add_row
409
434
  # @see README.md for an example
@@ -425,8 +450,9 @@ module Axlsx
425
450
 
426
451
  # Set the style for cells in a specific column
427
452
  # @param [Integer] index the index of the column
428
- # @param [Integer] the cellXfs index
429
- # @option options [Integer] row_offset only cells after this column will be updated.
453
+ # @param [Integer] style the cellXfs index
454
+ # @param [Hash] options
455
+ # @option [Integer] :row_offset only cells after this column will be updated.
430
456
  # @note You can also specify the style for specific columns in the call to add_row by using an array for the :styles option
431
457
  # @see Worksheet#add_row
432
458
  # @see README.md for an example
@@ -449,9 +475,9 @@ module Axlsx
449
475
  # @example This would set the first and third column widhts but leave the second column in autofit state.
450
476
  # ws.column_widths 7.2, nil, 3
451
477
  # @note For updating only a single column it is probably easier to just set the width of the ws.column_info[col_index].width directly
452
- # @param [Integer|Float|Fixnum|nil] values
453
- def column_widths(*args)
454
- args.each_with_index do |value, index|
478
+ # @param [Integer|Float|Fixnum|nil] widths
479
+ def column_widths(*widths)
480
+ widths.each_with_index do |value, index|
455
481
  next if value == nil
456
482
  Axlsx::validate_unsigned_numeric(value) unless value == nil
457
483
  @column_info[index] ||= Col.new index+1, index+1
@@ -493,55 +519,49 @@ module Axlsx
493
519
  end
494
520
 
495
521
  # Adds a media item to the worksheets drawing
496
- # @param [Class] media_type
497
- # @option options [] unknown
522
+ # @option [Hash] options options passed to drawing.add_image
498
523
  def add_image(options={})
499
524
  image = drawing.add_image(options)
500
525
  yield image if block_given?
501
526
  image
502
527
  end
503
528
 
504
- # Serializes the object
505
- # @param [String] str
529
+ # Serializes the worksheet object to an xml string
530
+ # This intentionally does not use nokogiri for performance reasons
506
531
  # @return [String]
507
532
  def to_xml_string
508
- rels = relationships
509
533
  str = '<?xml version="1.0" encoding="UTF-8"?>'
510
- str.concat "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R]
511
- str.concat "<sheetPr><pageSetUpPr fitToPage=\"%s\"></pageSetUpPr></sheetPr>" % fit_to_page if fit_to_page
512
- str.concat "<dimension ref=\"%s\"></dimension>" % dimension unless rows.size == 0
534
+ str << worksheet_node
535
+ str << sheet_pr_node
536
+ str << dimension_node
513
537
  @sheet_view.to_xml_string(str) if @sheet_view
514
- if @column_info.size > 0
515
- str << "<cols>"
516
- @column_info.each { |col| col.to_xml_string(str) }
517
- str.concat '</cols>'
518
- end
519
- str.concat '<sheetData>'
520
- @rows.each_with_index { |row, index| row.to_xml_string(index, str) }
521
- str.concat '</sheetData>'
522
- str.concat "<autoFilter ref='%s'></autoFilter>" % @auto_filter if @auto_filter
538
+ str << cols_node
539
+ str << sheet_data_node
540
+
541
+ str << auto_filter_node
523
542
  @sheet_protection.to_xml_string(str) if @sheet_protection
524
- str.concat "<mergeCells count='%s'>%s</mergeCells>" % [@merged_cells.size, @merged_cells.reduce('') { |memo, obj| memo += "<mergeCell ref='%s'></mergeCell>" % obj } ] unless @merged_cells.empty?
525
- print_options.to_xml_string(str) if @print_options
543
+ str << protected_ranges_node
544
+ str << merged_cells_node
545
+ @print_options.to_xml_string(str) if @print_options
526
546
  page_margins.to_xml_string(str) if @page_margins
527
547
  page_setup.to_xml_string(str) if @page_setup
528
- str << "<drawing r:id='rId" << (rels.index{ |r| r.Type == DRAWING_R } + 1).to_s << "'/>" if @drawing
529
- str << "<legacyDrawing r:id='rId" << (rels.index{ |r| r.Type == VML_DRAWING_R } + 1).to_s << "'/>" if @comments.size > 0
530
- unless @tables.empty?
531
- str.concat "<tableParts count='%s'>%s</tableParts>" % [@tables.size, @tables.reduce('') { |memo, obj| memo += "<tablePart r:id='%s'/>" % obj.rId }]
532
- end
533
- @conditional_formattings.each do |cf|
534
- str.concat cf.to_xml_string
535
- end
536
-
537
- unless @data_validations.empty?
538
- str.concat "<dataValidations count=\"#{@data_validations.size}\">"
539
- @data_validations.each do |df|
540
- str.concat df.to_xml_string
541
- end
542
- str.concat '</dataValidations>'
543
- end
544
- str + '</worksheet>'
548
+ str << drawing_node
549
+ str << legacy_drawing_node
550
+ str << table_parts_node
551
+ str << conditional_formattings_node
552
+ str << data_validations_node
553
+ str << '</worksheet>'
554
+ # User reported that when parsing some old data that had control characters excel chokes.
555
+ # All of the following are defined as illegal xml characters in the xml spec, but for now I am only dealing with control
556
+ # characters. Thanks to asakusarb and @hsbt's flash of code on the screen!
557
+ # [#x1-#x8], [#xB-#xC], [#xE-#x1F], [#x7F-#x84], [#x86-#x9F], [#xFDD0-#xFDDF],
558
+ # [#x1FFFE-#x1FFFF], [#x2FFFE-#x2FFFF], [#x3FFFE-#x3FFFF],
559
+ # [#x4FFFE-#x4FFFF], [#x5FFFE-#x5FFFF], [#x6FFFE-#x6FFFF],
560
+ # [#x7FFFE-#x7FFFF], [#x8FFFE-#x8FFFF], [#x9FFFE-#x9FFFF],
561
+ # [#xAFFFE-#xAFFFF], [#xBFFFE-#xBFFFF], [#xCFFFE-#xCFFFF],
562
+ # [#xDFFFE-#xDFFFF], [#xEFFFE-#xEFFFF], [#xFFFFE-#xFFFFF],
563
+ # [#x10FFFE-#x10FFFF].
564
+ str.gsub(/[[:cntrl:]]/,'')
545
565
  end
546
566
 
547
567
  # The worksheet relationships. This is managed automatically by the worksheet
@@ -584,6 +604,110 @@ module Axlsx
584
604
 
585
605
  private
586
606
 
607
+ # Helper method for parsingout the root node for worksheet
608
+ # @return [String]
609
+ def worksheet_node
610
+ "<worksheet xmlns=\"%s\" xmlns:r=\"%s\">" % [XML_NS, XML_NS_R]
611
+ end
612
+
613
+ # Helper method fo parsing out the sheetPr node
614
+ # @return [String]
615
+ def sheet_pr_node
616
+ return '' unless fit_to_page?
617
+ "<sheetPr><pageSetUpPr fitToPage=\"%s\"></pageSetUpPr></sheetPr>" % fit_to_page?
618
+ end
619
+
620
+ # Helper method for parsing out the demension node
621
+ # @return [String]
622
+ def dimension_node
623
+ return '' if rows.size == 0
624
+ "<dimension ref=\"%s\"></dimension>" % dimension
625
+ end
626
+
627
+ # Helper method for parsing out the sheetData node
628
+ # @return [String]
629
+ def sheet_data_node
630
+ str = '<sheetData>'
631
+ @rows.each_with_index { |row, index| row.to_xml_string(index, str) }
632
+ str << '</sheetData>'
633
+ end
634
+
635
+ # Helper method for parsing out the autoFilter node
636
+ # @return [String]
637
+ def auto_filter_node
638
+ return '' unless @auto_filter
639
+ "<autoFilter ref='%s'></autoFilter>" % @auto_filter
640
+ end
641
+
642
+ # Helper method for parsing out the cols node
643
+ # @return [String]
644
+ def cols_node
645
+ return '' if @column_info.empty?
646
+ str = "<cols>"
647
+ @column_info.each { |col| col.to_xml_string(str) }
648
+ str << '</cols>'
649
+ end
650
+
651
+ # Helper method for parsing out the protectedRanges node
652
+ # @return [String]
653
+ def protected_ranges_node
654
+ return '' if @protected_ranges.empty?
655
+ str = '<protectedRanges>'
656
+ @protected_ranges.each { |pr| pr.to_xml_string(str) }
657
+ str << '</protectedRanges>'
658
+ end
659
+
660
+ # Helper method for parsing out the mergedCells node
661
+ # @return [String]
662
+ def merged_cells_node
663
+ return '' if @merged_cells.size == 0
664
+ str = "<mergeCells count='#{@merged_cells.size}'>"
665
+ @merged_cells.each { |merged_cell| str << "<mergeCell ref='#{merged_cell}'></mergeCell>" }
666
+ str << '</mergeCells>'
667
+ end
668
+
669
+ # Helper method for parsing out the drawing node
670
+ # @return [String]
671
+ def drawing_node
672
+ return '' unless @drawing
673
+ "<drawing r:id='rId" << (relationships.index{ |r| r.Type == DRAWING_R } + 1).to_s << "'/>"
674
+ end
675
+
676
+ # Helper method for parsing out the legacyDrawing node required for comments
677
+ # @return [String]
678
+ def legacy_drawing_node
679
+ return '' if @comments.empty?
680
+ "<legacyDrawing r:id='rId" << (relationships.index{ |r| r.Type == VML_DRAWING_R } + 1).to_s << "'/>"
681
+ end
682
+
683
+ # Helper method for parsing out the tableParts node
684
+ # @return [String]
685
+ def table_parts_node
686
+ return '' if @tables.empty?
687
+ str = "<tableParts count='#{@tables.size}'>"
688
+ @tables.each { |table| str << "<tablePart r:id='#{table.rId}'/>" }
689
+ str << '</tableParts>'
690
+ end
691
+
692
+ # Helper method for parsing out the conditional formattings
693
+ # @return [String]
694
+ def conditional_formattings_node
695
+ return '' if @conditional_formattings.size == 0
696
+ str = ''
697
+ @conditional_formattings.each { |conditional_formatting| str << conditional_formatting.to_xml_string }
698
+ str
699
+ end
700
+
701
+ # Helper method for parsing out the dataValidations node
702
+ # @return [String]
703
+ def data_validations_node
704
+ return '' if @data_validations.size == 0
705
+ str = "<dataValidations count='#{@data_validations.size}'>"
706
+ @data_validations.each { |data_validation| str << data_validation.to_xml_string }
707
+ str << '</dataValidations>'
708
+ end
709
+
710
+
587
711
  # assigns the owner workbook for this worksheet
588
712
  def workbook=(v) DataTypeValidator.validate "Worksheet.workbook", Workbook, v; @workbook = v; end
589
713