axlsx 1.1.8 → 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.
- data/.yardopts +5 -2
- data/CHANGELOG.md +39 -0
- data/README.md +48 -46
- data/Rakefile +3 -3
- data/examples/basic_charts.rb +8 -0
- data/examples/example.rb +7 -1
- data/examples/example.xlsx +0 -0
- data/examples/example_streamed.xlsx +0 -0
- data/examples/no-use_autowidth.xlsx +0 -0
- data/examples/scraping_html.rb +91 -0
- data/examples/shared_strings_example.xlsx +0 -0
- data/lib/axlsx.rb +14 -8
- data/lib/axlsx/drawing/bar_3D_chart.rb +2 -8
- data/lib/axlsx/drawing/chart.rb +29 -25
- data/lib/axlsx/drawing/d_lbls.rb +100 -0
- data/lib/axlsx/drawing/drawing.rb +2 -0
- data/lib/axlsx/drawing/line_3D_chart.rb +2 -9
- data/lib/axlsx/drawing/pie_3D_chart.rb +3 -0
- data/lib/axlsx/drawing/scatter_chart.rb +2 -8
- data/lib/axlsx/drawing/two_cell_anchor.rb +38 -1
- data/lib/axlsx/util/simple_typed_list.rb +13 -6
- data/lib/axlsx/version.rb +2 -7
- data/lib/axlsx/workbook/defined_name.rb +174 -0
- data/lib/axlsx/workbook/defined_names.rb +21 -0
- data/lib/axlsx/workbook/workbook.rb +39 -13
- data/lib/axlsx/workbook/worksheet/auto_filter.rb +34 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +24 -1
- data/lib/axlsx/workbook/worksheet/col.rb +15 -0
- data/lib/axlsx/workbook/worksheet/cols.rb +20 -0
- data/lib/axlsx/workbook/worksheet/comments.rb +8 -0
- data/lib/axlsx/workbook/worksheet/conditional_formattings.rb +25 -0
- data/lib/axlsx/workbook/worksheet/data_validations.rb +28 -0
- data/lib/axlsx/workbook/worksheet/dimension.rb +65 -0
- data/lib/axlsx/workbook/worksheet/merged_cells.rb +35 -0
- data/lib/axlsx/workbook/worksheet/protected_ranges.rb +34 -0
- data/lib/axlsx/workbook/worksheet/row.rb +1 -1
- data/lib/axlsx/workbook/worksheet/sheet_data.rb +25 -0
- data/lib/axlsx/workbook/worksheet/sheet_pr.rb +24 -0
- data/lib/axlsx/workbook/worksheet/tables.rb +31 -0
- data/lib/axlsx/workbook/worksheet/worksheet.rb +263 -380
- data/lib/axlsx/workbook/worksheet/worksheet_comments.rb +57 -0
- data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +64 -0
- data/test/drawing/tc_bar_series.rb +1 -1
- data/test/drawing/tc_chart.rb +7 -1
- data/test/drawing/tc_d_lbls.rb +47 -0
- data/test/drawing/tc_drawing.rb +5 -4
- data/test/drawing/tc_line_series.rb +1 -1
- data/test/drawing/tc_pie_3D_chart.rb +1 -1
- data/test/drawing/tc_pie_series.rb +1 -1
- data/test/drawing/tc_scatter_series.rb +1 -1
- data/test/drawing/tc_series.rb +1 -1
- data/test/tc_package.rb +16 -1
- data/test/workbook/tc_defined_name.rb +41 -0
- data/test/workbook/tc_workbook.rb +5 -3
- data/test/workbook/worksheet/table/tc_table.rb +0 -8
- data/test/workbook/worksheet/tc_cell.rb +2 -4
- data/test/workbook/worksheet/tc_protected_range.rb +0 -1
- data/test/workbook/worksheet/tc_row.rb +2 -2
- data/test/workbook/worksheet/tc_worksheet.rb +19 -21
- metadata +48 -7
@@ -0,0 +1,21 @@
|
|
1
|
+
module Axlsx
|
2
|
+
# a simple types list of DefinedName objects
|
3
|
+
class DefinedNames < SimpleTypedList
|
4
|
+
|
5
|
+
# creates the DefinedNames object
|
6
|
+
def initialize
|
7
|
+
super DefinedName
|
8
|
+
end
|
9
|
+
|
10
|
+
# Serialize to xml
|
11
|
+
# @param [String] str
|
12
|
+
# @return [String]
|
13
|
+
def to_xml_string(str = '')
|
14
|
+
return if @list.empty?
|
15
|
+
str << "<definedNames>"
|
16
|
+
each { |defined_name| defined_name.to_xml_string(str) }
|
17
|
+
str << '</definedNames>'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
@@ -1,8 +1,9 @@
|
|
1
1
|
# -*- coding: utf-8 -*-
|
2
2
|
module Axlsx
|
3
|
-
|
3
|
+
require 'axlsx/workbook/worksheet/auto_filter.rb'
|
4
4
|
require 'axlsx/workbook/worksheet/date_time_converter.rb'
|
5
5
|
require 'axlsx/workbook/worksheet/protected_range.rb'
|
6
|
+
require 'axlsx/workbook/worksheet/protected_ranges.rb'
|
6
7
|
require 'axlsx/workbook/worksheet/cell.rb'
|
7
8
|
require 'axlsx/workbook/worksheet/page_margins.rb'
|
8
9
|
require 'axlsx/workbook/worksheet/page_setup.rb'
|
@@ -13,15 +14,27 @@ require 'axlsx/workbook/worksheet/data_bar.rb'
|
|
13
14
|
require 'axlsx/workbook/worksheet/icon_set.rb'
|
14
15
|
require 'axlsx/workbook/worksheet/conditional_formatting.rb'
|
15
16
|
require 'axlsx/workbook/worksheet/conditional_formatting_rule.rb'
|
17
|
+
require 'axlsx/workbook/worksheet/conditional_formattings.rb'
|
16
18
|
require 'axlsx/workbook/worksheet/row.rb'
|
17
19
|
require 'axlsx/workbook/worksheet/col.rb'
|
20
|
+
require 'axlsx/workbook/worksheet/cols.rb'
|
18
21
|
require 'axlsx/workbook/worksheet/comments.rb'
|
19
22
|
require 'axlsx/workbook/worksheet/comment.rb'
|
23
|
+
require 'axlsx/workbook/worksheet/merged_cells.rb'
|
20
24
|
require 'axlsx/workbook/worksheet/sheet_protection.rb'
|
25
|
+
require 'axlsx/workbook/worksheet/sheet_pr.rb'
|
26
|
+
require 'axlsx/workbook/worksheet/dimension.rb'
|
27
|
+
require 'axlsx/workbook/worksheet/sheet_data.rb'
|
28
|
+
require 'axlsx/workbook/worksheet/worksheet_drawing.rb'
|
29
|
+
require 'axlsx/workbook/worksheet/worksheet_comments.rb'
|
21
30
|
require 'axlsx/workbook/worksheet/worksheet.rb'
|
22
31
|
require 'axlsx/workbook/shared_strings_table.rb'
|
32
|
+
require 'axlsx/workbook/defined_name.rb'
|
33
|
+
require 'axlsx/workbook/defined_names.rb'
|
23
34
|
require 'axlsx/workbook/worksheet/table.rb'
|
35
|
+
require 'axlsx/workbook/worksheet/tables.rb'
|
24
36
|
require 'axlsx/workbook/worksheet/data_validation.rb'
|
37
|
+
require 'axlsx/workbook/worksheet/data_validations.rb'
|
25
38
|
require 'axlsx/workbook/worksheet/sheet_view.rb'
|
26
39
|
require 'axlsx/workbook/worksheet/pane.rb'
|
27
40
|
require 'axlsx/workbook/worksheet/selection.rb'
|
@@ -101,13 +114,22 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
101
114
|
# @return [SimpleTypedList]
|
102
115
|
attr_reader :tables
|
103
116
|
|
104
|
-
|
105
|
-
#
|
117
|
+
|
118
|
+
# A collection of defined names for this workbook
|
119
|
+
# @note The recommended way to manage defined names is Workbook#add_defined_name
|
120
|
+
# @see DefinedName
|
121
|
+
# @return [DefinedNames]
|
122
|
+
def defined_names
|
123
|
+
@defined_names ||= DefinedNames.new
|
124
|
+
end
|
125
|
+
|
126
|
+
# A collection of comments associated with this workbook
|
127
|
+
# @note The recommended way to manage comments is WOrksheet#add_comment
|
106
128
|
# @see Worksheet#add_comment
|
107
129
|
# @see Comment
|
108
130
|
# @return [Comments]
|
109
131
|
def comments
|
110
|
-
|
132
|
+
worksheets.map { |sheet| sheet.comments }.compact
|
111
133
|
end
|
112
134
|
|
113
135
|
# The styles associated with this workbook
|
@@ -190,6 +212,14 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
190
212
|
worksheet
|
191
213
|
end
|
192
214
|
|
215
|
+
# Adds a defined name to this workbook
|
216
|
+
# @return [DefinedName]
|
217
|
+
# @param [String] formula @see DefinedName
|
218
|
+
# @param [Hash] options @see DefinedName
|
219
|
+
def add_defined_name(formula, options)
|
220
|
+
defined_names << DefinedName.new(formula, options)
|
221
|
+
end
|
222
|
+
|
193
223
|
# The workbook relationships. This is managed automatically by the workbook
|
194
224
|
# @return [Relationships]
|
195
225
|
def relationships
|
@@ -231,17 +261,13 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
231
261
|
str << '<workbookPr date1904="' << @@date1904.to_s << '"/>'
|
232
262
|
str << '<sheets>'
|
233
263
|
@worksheets.each_with_index do |sheet, index|
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
str << '<definedNames>'
|
238
|
-
@worksheets.each_with_index do |sheet, index|
|
239
|
-
if sheet.auto_filter
|
240
|
-
str << '<definedName name="_xlnm._FilterDatabase" localSheetId="' << index.to_s << '" hidden="1">'
|
241
|
-
str << sheet.abs_auto_filter << '</definedName>'
|
264
|
+
str << '<sheet name="' << sheet.name << '" sheetId="' << (index+1).to_s << '" r:id="' << sheet.rId << '"/>'
|
265
|
+
if defined_name = sheet.auto_filter.defined_name
|
266
|
+
add_defined_name defined_name, :name => '_xlnm._FilterDatabase', :local_sheet_id => index, :hidden => 1
|
242
267
|
end
|
243
268
|
end
|
244
|
-
str << '</
|
269
|
+
str << '</sheets>'
|
270
|
+
defined_names.to_xml_string(str)
|
245
271
|
str << '</workbook>'
|
246
272
|
end
|
247
273
|
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
#This class represents an auto filter range in a worksheet
|
4
|
+
class AutoFilter
|
5
|
+
|
6
|
+
# creates a new Autofilter object
|
7
|
+
# @param [Worksheet] worksheet
|
8
|
+
def initialize(worksheet)
|
9
|
+
raise ArgumentError, 'you must provide a worksheet' unless worksheet.is_a?(Worksheet)
|
10
|
+
@worksheet = worksheet
|
11
|
+
end
|
12
|
+
|
13
|
+
attr_reader :worksheet
|
14
|
+
|
15
|
+
# The range the autofilter should be applied to.
|
16
|
+
# This should be a string like 'A1:B8'
|
17
|
+
# @return [String]
|
18
|
+
attr_accessor :range
|
19
|
+
|
20
|
+
# the formula for the defined name required for this auto filter
|
21
|
+
# @return [String]
|
22
|
+
def defined_name
|
23
|
+
return unless range
|
24
|
+
Axlsx.cell_range(range.split(':').collect { |name| worksheet.name_to_cell(name)})
|
25
|
+
end
|
26
|
+
|
27
|
+
# serialize the object
|
28
|
+
# @return [String]
|
29
|
+
def to_xml_string(str='')
|
30
|
+
str << "<autoFilter ref='#{range}'></autoFilter>"
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
end
|
@@ -318,11 +318,34 @@ module Axlsx
|
|
318
318
|
end
|
319
319
|
|
320
320
|
def is_formula?
|
321
|
-
@type == :string && @value.start_with?('=')
|
321
|
+
@type == :string && @value.to_s.start_with?('=')
|
322
322
|
end
|
323
323
|
|
324
|
+
# This is still not perfect...
|
325
|
+
# - scaling is not linear as font sizes increst
|
326
|
+
# - different fonts have different mdw and char widths
|
327
|
+
def autowidth
|
328
|
+
return if is_formula? || value == nil
|
329
|
+
mdw = 1.78 #This is the widest width of 0..9 in arial@10px)
|
330
|
+
font_scale = (font_size/10.0).to_f
|
331
|
+
((value.to_s.count(Worksheet.thin_chars) * mdw + 5) / mdw * 256) / 256.0 * font_scale
|
332
|
+
end
|
333
|
+
|
334
|
+
# returns the absolute or relative string style reference for
|
335
|
+
# this cell.
|
336
|
+
# @param [Boolean] absolute -when false a relative reference will be
|
337
|
+
# returned.
|
338
|
+
# @return [String]
|
339
|
+
def reference(absolute=true)
|
340
|
+
absolute ? r_abs : r
|
341
|
+
end
|
342
|
+
|
324
343
|
private
|
325
344
|
|
345
|
+
def font_size
|
346
|
+
sz || @styles.fonts[@styles.cellXfs[style].fontId].sz
|
347
|
+
end
|
348
|
+
|
326
349
|
# Utility method for setting inline style attributes
|
327
350
|
def set_run_style( validator, attr, value)
|
328
351
|
return unless INLINE_STYLES.include?(attr.to_s)
|
@@ -102,6 +102,21 @@ module Axlsx
|
|
102
102
|
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
103
103
|
end
|
104
104
|
end
|
105
|
+
|
106
|
+
# updates the width for this col based on the cells autowidth and
|
107
|
+
# an optionally specified fixed width
|
108
|
+
# @param [Cell] cell The cell to use in updating this col's width
|
109
|
+
# @param [Integer] fixed_width If this is specified the width is set
|
110
|
+
# to this value and the cell's attributes are ignored.
|
111
|
+
# @param [Boolean] use_autowidth If this is false, the cell's
|
112
|
+
# autowidth value will be ignored.
|
113
|
+
def update_width(cell, fixed_width=nil, use_autowidth=true)
|
114
|
+
if fixed_width.is_a? Numeric
|
115
|
+
self.width = fixed_width
|
116
|
+
elsif use_autowidth
|
117
|
+
self.width = [width || 0, cell.autowidth || 0].max
|
118
|
+
end
|
119
|
+
end
|
105
120
|
|
106
121
|
# Serialize this columns data to an xml string
|
107
122
|
# @param [String] str
|
@@ -0,0 +1,20 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
# The cols class manages the col object used to manage column widths.
|
4
|
+
# This is where the magic happens with autowidth
|
5
|
+
class Cols < SimpleTypedList
|
6
|
+
|
7
|
+
def initialize(worksheet)
|
8
|
+
raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
|
9
|
+
super Col
|
10
|
+
@worksheet = worksheet
|
11
|
+
end
|
12
|
+
|
13
|
+
def to_xml_string(str = '')
|
14
|
+
return if empty?
|
15
|
+
str << '<cols>'
|
16
|
+
each { |item| item.to_xml_string(str) }
|
17
|
+
str << '</cols>'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -53,6 +53,14 @@ module Axlsx
|
|
53
53
|
@list.map { |comment| comment.author.to_s }.uniq.sort
|
54
54
|
end
|
55
55
|
|
56
|
+
# The relationships required by this object
|
57
|
+
# @return [Array]
|
58
|
+
def relationships
|
59
|
+
[Relationship.new(VML_DRAWING_R, "../#{vml_drawing.pn}"),
|
60
|
+
Relationship.new(COMMENT_R, "../#{pn}"),
|
61
|
+
Relationship.new(COMMENT_R_NULL, "NULL")]
|
62
|
+
end
|
63
|
+
|
56
64
|
# serialize the object
|
57
65
|
# @param [String] str
|
58
66
|
# @return [String]
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
# A simple, self serializing class for storing conditional formattings
|
4
|
+
class ConditionalFormattings < SimpleTypedList
|
5
|
+
|
6
|
+
# creates a new Tables object
|
7
|
+
def initialize(worksheet)
|
8
|
+
raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
|
9
|
+
super ConditionalFormatting
|
10
|
+
@worksheet = worksheet
|
11
|
+
end
|
12
|
+
|
13
|
+
# The worksheet that owns this collection of tables
|
14
|
+
# @return [Worksheet]
|
15
|
+
attr_reader :worksheet
|
16
|
+
|
17
|
+
# serialize the conditional formattings
|
18
|
+
def to_xml_string(str = "")
|
19
|
+
return if empty?
|
20
|
+
each { |item| item.to_xml_string(str) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
end
|
25
|
+
|
@@ -0,0 +1,28 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
# A simple, self serializing class for storing conditional formattings
|
4
|
+
class DataValidations < SimpleTypedList
|
5
|
+
|
6
|
+
# creates a new Tables object
|
7
|
+
def initialize(worksheet)
|
8
|
+
raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
|
9
|
+
super DataValidation
|
10
|
+
@worksheet = worksheet
|
11
|
+
end
|
12
|
+
|
13
|
+
# The worksheet that owns this collection of tables
|
14
|
+
# @return [Worksheet]
|
15
|
+
attr_reader :worksheet
|
16
|
+
|
17
|
+
# serialize the conditional formattings
|
18
|
+
def to_xml_string(str = "")
|
19
|
+
return if empty?
|
20
|
+
str << "<dataValidations count='#{size}'>"
|
21
|
+
each { |item| item.to_xml_string(str) }
|
22
|
+
str << '</dataValidations>'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
|
28
|
+
|
@@ -0,0 +1,65 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
# This class manages the dimensions for a worksheet.
|
4
|
+
# While this node is optional in the specification some readers like
|
5
|
+
# LibraOffice require this node to render the sheet
|
6
|
+
class Dimension
|
7
|
+
|
8
|
+
# the default value for the first cell in the dimension
|
9
|
+
# @return [String]
|
10
|
+
def self.default_first
|
11
|
+
@@default_first ||= 'A1'
|
12
|
+
end
|
13
|
+
|
14
|
+
# the default value for the last cell in the dimension
|
15
|
+
# @return [String]
|
16
|
+
def self.default_last
|
17
|
+
@@default_last ||= 'AA200'
|
18
|
+
end
|
19
|
+
|
20
|
+
|
21
|
+
# Creates a new dimension object
|
22
|
+
# @param[Worksheet] worksheet - the worksheet this dimension applies
|
23
|
+
# to.
|
24
|
+
def initialize(worksheet)
|
25
|
+
raise ArgumentError, "you must provide a worksheet" unless worksheet.is_a?(Worksheet)
|
26
|
+
@worksheet = worksheet
|
27
|
+
end
|
28
|
+
|
29
|
+
attr_reader :worksheet
|
30
|
+
|
31
|
+
# the full refernece for this dimension
|
32
|
+
# @return [String]
|
33
|
+
def sqref
|
34
|
+
"#{first_cell_reference}:#{last_cell_reference}"
|
35
|
+
end
|
36
|
+
|
37
|
+
# serialize the object
|
38
|
+
# @return [String]
|
39
|
+
def to_xml_string(str = '')
|
40
|
+
return if worksheet.rows.empty?
|
41
|
+
str << "<dimension ref=\"%s\"></dimension>" % sqref
|
42
|
+
end
|
43
|
+
|
44
|
+
# The first cell in the dimension
|
45
|
+
# @return [String]
|
46
|
+
def first_cell_reference
|
47
|
+
dimension_reference(worksheet.rows.first.cells.first, Dimension.default_first)
|
48
|
+
end
|
49
|
+
|
50
|
+
# the last cell in the dimension
|
51
|
+
# @return [String]
|
52
|
+
def last_cell_reference
|
53
|
+
dimension_reference(worksheet.rows.last.cells.last, Dimension.default_last)
|
54
|
+
end
|
55
|
+
|
56
|
+
private
|
57
|
+
|
58
|
+
# Returns the reference of a cell or the default specified
|
59
|
+
# @return [String]
|
60
|
+
def dimension_reference(cell, default)
|
61
|
+
return default unless cell.respond_to?(:r)
|
62
|
+
cell.r
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
# A simple list of merged cells
|
4
|
+
class MergedCells < SimpleTypedList
|
5
|
+
|
6
|
+
# creates a new MergedCells object
|
7
|
+
# @param [Worksheet] worksheet
|
8
|
+
def initialize(worksheet)
|
9
|
+
raise ArgumentError, 'you must provide a worksheet' unless worksheet.is_a?(Worksheet)
|
10
|
+
super String
|
11
|
+
end
|
12
|
+
|
13
|
+
# adds cells to the merged cells collection
|
14
|
+
# @param [Array||String] cells The cells to add to the merged cells
|
15
|
+
# collection. This can be an array of actual cells or a string style
|
16
|
+
# range like 'A1:C1'
|
17
|
+
def add(cells)
|
18
|
+
@list << if cells.is_a?(String)
|
19
|
+
cells
|
20
|
+
elsif cells.is_a?(Array)
|
21
|
+
Axlsx::cell_range(cells, false)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# serialize the object
|
26
|
+
# @param [String] str
|
27
|
+
# @return [String]
|
28
|
+
def to_xml_string(str = '')
|
29
|
+
return if @list.empty?
|
30
|
+
str << "<mergeCells count='#{size}'>"
|
31
|
+
each { |merged_cell| str << "<mergeCell ref='#{merged_cell}'></mergeCell>" }
|
32
|
+
str << '</mergeCells>'
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
module Axlsx
|
2
|
+
|
3
|
+
# A self serializing collection of ranges that should be protected in
|
4
|
+
# the worksheet
|
5
|
+
class ProtectedRanges < SimpleTypedList
|
6
|
+
|
7
|
+
attr_reader :worksheet
|
8
|
+
|
9
|
+
def initialize(worksheet)
|
10
|
+
raise ArgumentError, 'You must provide a worksheet' unless worksheet.is_a?(Worksheet)
|
11
|
+
super ProtectedRange
|
12
|
+
@worksheet = worksheet
|
13
|
+
end
|
14
|
+
|
15
|
+
# Adds a protected range
|
16
|
+
# @param [Array|String] cells A string range reference or array of cells that will be protected
|
17
|
+
def add_range(cells)
|
18
|
+
sqref = if cells.is_a?(String)
|
19
|
+
cells
|
20
|
+
elsif cells.is_a?(SimpleTypedList) || cells.is_a?(Array)
|
21
|
+
Axlsx::cell_range(cells, false)
|
22
|
+
end
|
23
|
+
@list << ProtectedRange.new(:sqref => sqref, :name => "Range#{size}")
|
24
|
+
last
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_xml_string(str = '')
|
28
|
+
return if empty?
|
29
|
+
str << '<protectedRanges>'
|
30
|
+
each { |range| range.to_xml_string(str) }
|
31
|
+
str << '</protectedRanges>'
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|