axlsx 2.0.1 → 3.0.0.pre
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +23 -23
- data/Rakefile +9 -11
- data/examples/auto_filter.rb +10 -1
- data/examples/conditional_formatting/example_conditional_formatting.rb +18 -3
- data/examples/example.rb +102 -4
- data/examples/merge_cells.rb +17 -0
- data/examples/no_grid_with_borders.rb +18 -0
- data/examples/pivot_test.rb +63 -0
- data/examples/split.rb +16 -0
- data/lib/axlsx/content_type/abstract_content_type.rb +1 -1
- data/lib/axlsx/content_type/content_type.rb +1 -1
- data/lib/axlsx/doc_props/app.rb +1 -1
- data/lib/axlsx/doc_props/core.rb +5 -5
- data/lib/axlsx/drawing/area_chart.rb +99 -0
- data/lib/axlsx/drawing/area_series.rb +110 -0
- data/lib/axlsx/drawing/axes.rb +1 -1
- data/lib/axlsx/drawing/axis.rb +12 -9
- data/lib/axlsx/drawing/bar_3D_chart.rb +13 -13
- data/lib/axlsx/drawing/bar_chart.rb +143 -0
- data/lib/axlsx/drawing/bar_series.rb +9 -9
- data/lib/axlsx/drawing/bubble_chart.rb +59 -0
- data/lib/axlsx/drawing/bubble_series.rb +63 -0
- data/lib/axlsx/drawing/cat_axis.rb +5 -5
- data/lib/axlsx/drawing/chart.rb +52 -8
- data/lib/axlsx/drawing/d_lbls.rb +3 -3
- data/lib/axlsx/drawing/drawing.rb +6 -1
- data/lib/axlsx/drawing/graphic_frame.rb +3 -3
- data/lib/axlsx/drawing/hyperlink.rb +1 -3
- data/lib/axlsx/drawing/line_3D_chart.rb +2 -2
- data/lib/axlsx/drawing/line_chart.rb +10 -10
- data/lib/axlsx/drawing/line_series.rb +32 -3
- data/lib/axlsx/drawing/marker.rb +1 -1
- data/lib/axlsx/drawing/num_data.rb +4 -4
- data/lib/axlsx/drawing/num_data_source.rb +6 -6
- data/lib/axlsx/drawing/num_val.rb +3 -1
- data/lib/axlsx/drawing/one_cell_anchor.rb +3 -2
- data/lib/axlsx/drawing/pic.rb +25 -19
- data/lib/axlsx/drawing/picture_locking.rb +1 -3
- data/lib/axlsx/drawing/pie_3D_chart.rb +5 -6
- data/lib/axlsx/drawing/pie_series.rb +6 -6
- data/lib/axlsx/drawing/scaling.rb +6 -6
- data/lib/axlsx/drawing/scatter_chart.rb +10 -10
- data/lib/axlsx/drawing/scatter_series.rb +40 -7
- data/lib/axlsx/drawing/ser_axis.rb +2 -2
- data/lib/axlsx/drawing/series.rb +3 -3
- data/lib/axlsx/drawing/series_title.rb +2 -2
- data/lib/axlsx/drawing/str_data.rb +3 -3
- data/lib/axlsx/drawing/str_val.rb +3 -1
- data/lib/axlsx/drawing/title.rb +22 -4
- data/lib/axlsx/drawing/two_cell_anchor.rb +6 -1
- data/lib/axlsx/drawing/val_axis.rb +1 -1
- data/lib/axlsx/drawing/view_3D.rb +2 -2
- data/lib/axlsx/drawing/vml_drawing.rb +1 -1
- data/lib/axlsx/package.rb +34 -32
- data/lib/axlsx/rels/relationship.rb +1 -1
- data/lib/axlsx/rels/relationships.rb +7 -4
- data/lib/axlsx/stylesheet/border_pr.rb +2 -2
- data/lib/axlsx/stylesheet/cell_alignment.rb +1 -3
- data/lib/axlsx/stylesheet/cell_protection.rb +1 -3
- data/lib/axlsx/stylesheet/cell_style.rb +1 -3
- data/lib/axlsx/stylesheet/color.rb +1 -3
- data/lib/axlsx/stylesheet/font.rb +1 -1
- data/lib/axlsx/stylesheet/gradient_stop.rb +1 -1
- data/lib/axlsx/stylesheet/num_fmt.rb +10 -3
- data/lib/axlsx/stylesheet/pattern_fill.rb +1 -1
- data/lib/axlsx/stylesheet/styles.rb +7 -7
- data/lib/axlsx/stylesheet/table_style_element.rb +1 -3
- data/lib/axlsx/util/accessors.rb +6 -6
- data/lib/axlsx/util/constants.rb +107 -99
- data/lib/axlsx/util/mime_type_utils.rb +11 -0
- data/lib/axlsx/util/options_parser.rb +2 -1
- data/lib/axlsx/util/parser.rb +4 -4
- data/lib/axlsx/util/serialized_attributes.rb +16 -6
- data/lib/axlsx/util/simple_typed_list.rb +28 -52
- data/lib/axlsx/util/storage.rb +4 -4
- data/lib/axlsx/util/validators.rb +29 -17
- data/lib/axlsx/version.rb +1 -1
- data/lib/axlsx/workbook/defined_name.rb +11 -12
- data/lib/axlsx/workbook/defined_names.rb +2 -2
- data/lib/axlsx/workbook/shared_strings_table.rb +5 -5
- data/lib/axlsx/workbook/workbook.rb +36 -11
- data/lib/axlsx/workbook/workbook_view.rb +80 -0
- data/lib/axlsx/workbook/workbook_views.rb +22 -0
- data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +2 -2
- data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +1 -3
- data/lib/axlsx/workbook/worksheet/break.rb +1 -3
- data/lib/axlsx/workbook/worksheet/cell.rb +136 -74
- data/lib/axlsx/workbook/worksheet/cell_serializer.rb +63 -43
- data/lib/axlsx/workbook/worksheet/cfvo.rb +1 -3
- data/lib/axlsx/workbook/worksheet/cfvos.rb +4 -1
- data/lib/axlsx/workbook/worksheet/col.rb +7 -10
- data/lib/axlsx/workbook/worksheet/col_breaks.rb +2 -2
- data/lib/axlsx/workbook/worksheet/cols.rb +5 -2
- data/lib/axlsx/workbook/worksheet/comment.rb +5 -6
- data/lib/axlsx/workbook/worksheet/comments.rb +9 -12
- data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +1 -1
- data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +1 -1
- data/lib/axlsx/workbook/worksheet/data_bar.rb +4 -6
- data/lib/axlsx/workbook/worksheet/data_validation.rb +6 -4
- data/lib/axlsx/workbook/worksheet/dimension.rb +2 -2
- data/lib/axlsx/workbook/worksheet/header_footer.rb +6 -8
- data/lib/axlsx/workbook/worksheet/icon_set.rb +3 -5
- data/lib/axlsx/workbook/worksheet/merged_cells.rb +4 -2
- data/lib/axlsx/workbook/worksheet/outline_pr.rb +33 -0
- data/lib/axlsx/workbook/worksheet/page_margins.rb +1 -3
- data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +1 -1
- data/lib/axlsx/workbook/worksheet/page_setup.rb +21 -23
- data/lib/axlsx/workbook/worksheet/pane.rb +1 -3
- data/lib/axlsx/workbook/worksheet/pivot_table.rb +44 -28
- data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +4 -4
- data/lib/axlsx/workbook/worksheet/print_options.rb +1 -3
- data/lib/axlsx/workbook/worksheet/protected_range.rb +1 -3
- data/lib/axlsx/workbook/worksheet/protected_ranges.rb +5 -2
- data/lib/axlsx/workbook/worksheet/rich_text.rb +55 -0
- data/lib/axlsx/workbook/worksheet/rich_text_run.rb +250 -0
- data/lib/axlsx/workbook/worksheet/row.rb +40 -51
- data/lib/axlsx/workbook/worksheet/row_breaks.rb +2 -2
- data/lib/axlsx/workbook/worksheet/selection.rb +1 -3
- data/lib/axlsx/workbook/worksheet/sheet_data.rb +3 -1
- data/lib/axlsx/workbook/worksheet/sheet_pr.rb +21 -3
- data/lib/axlsx/workbook/worksheet/sheet_protection.rb +1 -3
- data/lib/axlsx/workbook/worksheet/table.rb +6 -6
- data/lib/axlsx/workbook/worksheet/table_style_info.rb +1 -3
- data/lib/axlsx/workbook/worksheet/tables.rb +4 -1
- data/lib/axlsx/workbook/worksheet/worksheet.rb +64 -78
- data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +10 -10
- data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +3 -3
- data/lib/axlsx.rb +34 -15
- data/test/drawing/tc_area_chart.rb +39 -0
- data/test/drawing/tc_area_series.rb +71 -0
- data/test/drawing/tc_axis.rb +27 -0
- data/test/drawing/tc_bar_chart.rb +71 -0
- data/test/drawing/tc_bubble_chart.rb +44 -0
- data/test/drawing/tc_bubble_series.rb +21 -0
- data/test/drawing/tc_chart.rb +23 -10
- data/test/drawing/tc_data_source.rb +6 -0
- data/test/drawing/tc_drawing.rb +2 -2
- data/test/drawing/tc_line_chart.rb +5 -5
- data/test/drawing/tc_line_series.rb +47 -6
- data/test/drawing/tc_pic.rb +11 -15
- data/test/drawing/tc_scatter_series.rb +36 -1
- data/test/drawing/tc_str_val.rb +9 -0
- data/test/drawing/tc_title.rb +5 -0
- data/test/stylesheet/tc_styles.rb +2 -2
- data/test/tc_axlsx.rb +31 -0
- data/test/tc_helper.rb +2 -0
- data/test/tc_package.rb +19 -1
- data/test/util/tc_mime_type_utils.rb +13 -0
- data/test/util/tc_simple_typed_list.rb +2 -3
- data/test/util/tc_validators.rb +34 -10
- data/test/workbook/tc_defined_name.rb +12 -4
- data/test/workbook/tc_shared_strings_table.rb +16 -1
- data/test/workbook/tc_workbook.rb +38 -3
- data/test/workbook/tc_workbook_view.rb +50 -0
- data/test/workbook/worksheet/auto_filter/tc_filters.rb +1 -1
- data/test/workbook/worksheet/tc_break.rb +1 -1
- data/test/workbook/worksheet/tc_cell.rb +76 -8
- data/test/workbook/worksheet/tc_col.rb +2 -2
- data/test/workbook/worksheet/tc_conditional_formatting.rb +2 -2
- data/test/workbook/worksheet/tc_data_bar.rb +1 -1
- data/test/workbook/worksheet/tc_data_validation.rb +11 -11
- data/test/workbook/worksheet/tc_header_footer.rb +2 -2
- data/test/workbook/worksheet/tc_icon_set.rb +1 -1
- data/test/workbook/worksheet/tc_outline_pr.rb +19 -0
- data/test/workbook/worksheet/tc_page_setup.rb +3 -3
- data/test/workbook/worksheet/tc_pivot_table.rb +21 -6
- data/test/workbook/worksheet/tc_print_options.rb +1 -1
- data/test/workbook/worksheet/tc_rich_text.rb +44 -0
- data/test/workbook/worksheet/tc_rich_text_run.rb +172 -0
- data/test/workbook/worksheet/tc_row.rb +7 -2
- data/test/workbook/worksheet/tc_sheet_calc_pr.rb +1 -1
- data/test/workbook/worksheet/tc_sheet_format_pr.rb +4 -4
- data/test/workbook/worksheet/tc_sheet_pr.rb +26 -4
- data/test/workbook/worksheet/tc_sheet_protection.rb +5 -5
- data/test/workbook/worksheet/tc_sheet_view.rb +4 -4
- data/test/workbook/worksheet/tc_table.rb +2 -3
- data/test/workbook/worksheet/tc_worksheet.rb +99 -45
- metadata +142 -64
@@ -8,7 +8,7 @@ module Axlsx
|
|
8
8
|
# @param [Array, Class] type An array of Class objects or a single Class object
|
9
9
|
# @param [String] serialize_as The tag name to use in serialization
|
10
10
|
# @raise [ArgumentError] if all members of type are not Class objects
|
11
|
-
def initialize type, serialize_as=nil
|
11
|
+
def initialize type, serialize_as=nil, start_size = 0
|
12
12
|
if type.is_a? Array
|
13
13
|
type.each { |item| raise ArgumentError, "All members of type must be Class objects" unless item.is_a? Class }
|
14
14
|
@allowed_types = type
|
@@ -16,9 +16,8 @@ module Axlsx
|
|
16
16
|
raise ArgumentError, "Type must be a Class object or array of Class objects" unless type.is_a? Class
|
17
17
|
@allowed_types = [type]
|
18
18
|
end
|
19
|
-
@
|
20
|
-
@
|
21
|
-
@serialize_as = serialize_as
|
19
|
+
@serialize_as = serialize_as unless serialize_as.nil?
|
20
|
+
@list = Array.new(start_size)
|
22
21
|
end
|
23
22
|
|
24
23
|
# The class constants of allowed types
|
@@ -27,7 +26,9 @@ module Axlsx
|
|
27
26
|
|
28
27
|
# The index below which items cannot be removed
|
29
28
|
# @return [Integer]
|
30
|
-
|
29
|
+
def locked_at
|
30
|
+
defined?(@locked_at) ? @locked_at : nil
|
31
|
+
end
|
31
32
|
|
32
33
|
# The tag name to use when serializing this object
|
33
34
|
# by default the parent node for all items in the list is the classname of the first allowed type with the first letter in lowercase.
|
@@ -54,6 +55,7 @@ module Axlsx
|
|
54
55
|
end
|
55
56
|
result
|
56
57
|
end
|
58
|
+
|
57
59
|
# Lock this list at the current size
|
58
60
|
# @return [self]
|
59
61
|
def lock
|
@@ -61,18 +63,18 @@ module Axlsx
|
|
61
63
|
self
|
62
64
|
end
|
63
65
|
|
64
|
-
def to_ary
|
65
|
-
@list
|
66
|
-
end
|
67
|
-
|
68
|
-
alias :to_a :to_ary
|
69
|
-
|
70
66
|
# Unlock the list
|
71
67
|
# @return [self]
|
72
68
|
def unlock
|
73
69
|
@locked_at = nil
|
74
70
|
self
|
75
71
|
end
|
72
|
+
|
73
|
+
def to_ary
|
74
|
+
@list
|
75
|
+
end
|
76
|
+
|
77
|
+
alias :to_a :to_ary
|
76
78
|
|
77
79
|
# join operator
|
78
80
|
# @param [Array] v the array to join
|
@@ -81,7 +83,7 @@ module Axlsx
|
|
81
83
|
# @return [SimpleTypedList]
|
82
84
|
def +(v)
|
83
85
|
v.each do |item|
|
84
|
-
DataTypeValidator.validate
|
86
|
+
DataTypeValidator.validate :SimpleTypedList_plus, @allowed_types, item
|
85
87
|
@list << item
|
86
88
|
end
|
87
89
|
end
|
@@ -91,19 +93,21 @@ module Axlsx
|
|
91
93
|
# @raise [ArgumentError] if the value being added is not one fo the allowed types
|
92
94
|
# @return [Integer] returns the index of the item added.
|
93
95
|
def <<(v)
|
94
|
-
DataTypeValidator.validate
|
96
|
+
DataTypeValidator.validate :SimpleTypedList_push, @allowed_types, v
|
95
97
|
@list << v
|
96
98
|
@list.size - 1
|
97
|
-
end
|
99
|
+
end
|
100
|
+
|
98
101
|
alias :push :<<
|
102
|
+
|
99
103
|
|
100
104
|
# delete the item from the list
|
101
105
|
# @param [Any] v The item to be deleted.
|
102
106
|
# @raise [ArgumentError] if the item's index is protected by locking
|
103
107
|
# @return [Any] The item deleted
|
104
108
|
def delete(v)
|
105
|
-
return unless
|
106
|
-
raise ArgumentError, "Item is protected and cannot be deleted" if protected?
|
109
|
+
return unless include? v
|
110
|
+
raise ArgumentError, "Item is protected and cannot be deleted" if protected? index(v)
|
107
111
|
@list.delete v
|
108
112
|
end
|
109
113
|
|
@@ -122,7 +126,7 @@ module Axlsx
|
|
122
126
|
# @raise [ArgumentError] if the index is protected by locking
|
123
127
|
# @raise [ArgumentError] if the item is not one of the allowed types
|
124
128
|
def []=(index, v)
|
125
|
-
DataTypeValidator.validate
|
129
|
+
DataTypeValidator.validate :SimpleTypedList_insert, @allowed_types, v
|
126
130
|
raise ArgumentError, "Item is protected and cannot be changed" if protected? index
|
127
131
|
@list[index] = v
|
128
132
|
v
|
@@ -134,7 +138,7 @@ module Axlsx
|
|
134
138
|
# @raise [ArgumentError] if the index is protected by locking
|
135
139
|
# @raise [ArgumentError] if the index is not one of the allowed types
|
136
140
|
def insert(index, v)
|
137
|
-
DataTypeValidator.validate
|
141
|
+
DataTypeValidator.validate :SimpleTypedList_insert, @allowed_types, v
|
138
142
|
raise ArgumentError, "Item is protected and cannot be changed" if protected? index
|
139
143
|
@list.insert(index, v)
|
140
144
|
v
|
@@ -143,38 +147,10 @@ module Axlsx
|
|
143
147
|
# determines if the index is protected
|
144
148
|
# @param [Integer] index
|
145
149
|
def protected? index
|
146
|
-
return false unless
|
147
|
-
index <
|
150
|
+
return false unless locked_at.is_a? Integer
|
151
|
+
index < locked_at
|
148
152
|
end
|
149
153
|
|
150
|
-
# override the equality method so that this object can be compared to a simple array.
|
151
|
-
# if this object's list is equal to the specifiec array, we return true.
|
152
|
-
def ==(v)
|
153
|
-
v == @list
|
154
|
-
end
|
155
|
-
# method_mission override to pass allowed methods to the list.
|
156
|
-
# @note
|
157
|
-
# the following methods are not allowed
|
158
|
-
# :replace
|
159
|
-
# :insert
|
160
|
-
# :collect!
|
161
|
-
# :map!
|
162
|
-
# :pop
|
163
|
-
# :delete_if
|
164
|
-
# :reverse!
|
165
|
-
# :shift
|
166
|
-
# :shuffle!
|
167
|
-
# :slice!
|
168
|
-
# :sort!
|
169
|
-
# :uniq!
|
170
|
-
# :unshift
|
171
|
-
# :zip
|
172
|
-
# :flatten!
|
173
|
-
# :fill
|
174
|
-
# :drop
|
175
|
-
# :drop_while
|
176
|
-
# :delete_if
|
177
|
-
# :clear
|
178
154
|
DESTRUCTIVE = ['replace', 'insert', 'collect!', 'map!', 'pop', 'delete_if',
|
179
155
|
'reverse!', 'shift', 'shuffle!', 'slice!', 'sort!', 'uniq!',
|
180
156
|
'unshift', 'zip', 'flatten!', 'fill', 'drop', 'drop_while',
|
@@ -188,13 +164,13 @@ module Axlsx
|
|
188
164
|
end
|
189
165
|
}
|
190
166
|
end
|
191
|
-
|
167
|
+
|
192
168
|
def to_xml_string(str = '')
|
193
169
|
classname = @allowed_types[0].name.split('::').last
|
194
170
|
el_name = serialize_as.to_s || (classname[0,1].downcase + classname[1..-1])
|
195
|
-
str << '<' << el_name << ' count="' <<
|
196
|
-
|
197
|
-
str << '</' << el_name << '>'
|
171
|
+
str << ('<' << el_name << ' count="' << size.to_s << '">')
|
172
|
+
each { |item| item.to_xml_string(str) }
|
173
|
+
str << ('</' << el_name << '>')
|
198
174
|
end
|
199
175
|
|
200
176
|
end
|
data/lib/axlsx/util/storage.rb
CHANGED
@@ -6,14 +6,14 @@ module Axlsx
|
|
6
6
|
|
7
7
|
# Packing for the Storage when pushing an array of items into a byte stream
|
8
8
|
# Name, name length, type, color, left sibling, right sibling, child, classid, state, created, modified, sector, size
|
9
|
-
PACKING = "s32 s1 c2 l3 x16 x4 q2 l q"
|
9
|
+
PACKING = "s32 s1 c2 l3 x16 x4 q2 l q".freeze
|
10
10
|
|
11
11
|
# storage types
|
12
12
|
TYPES = {
|
13
13
|
:root=>5,
|
14
14
|
:stream=>2,
|
15
15
|
:storage=>1
|
16
|
-
}
|
16
|
+
}.freeze
|
17
17
|
|
18
18
|
# Creates a byte string for this storage
|
19
19
|
# @return [String]
|
@@ -45,7 +45,7 @@ module Axlsx
|
|
45
45
|
# Sets the color for this storage
|
46
46
|
# @param [Integer] v Must be one of the COLORS constant hash values
|
47
47
|
def color=(v)
|
48
|
-
RestrictionValidator.validate
|
48
|
+
RestrictionValidator.validate :storage_color, COLORS.values, v
|
49
49
|
@color = v
|
50
50
|
end
|
51
51
|
|
@@ -116,7 +116,7 @@ module Axlsx
|
|
116
116
|
# Sets the type for this storage.
|
117
117
|
# @param [Integer] v the type to specify must be one of the TYPES constant hash values.
|
118
118
|
def type=(v)
|
119
|
-
RestrictionValidator.validate
|
119
|
+
RestrictionValidator.validate :storage_type, TYPES.values, v
|
120
120
|
@type = v
|
121
121
|
end
|
122
122
|
|
@@ -52,14 +52,12 @@ module Axlsx
|
|
52
52
|
# @return [Boolean] true if validation succeeds.
|
53
53
|
# @see validate_boolean
|
54
54
|
def self.validate(name, types, v, other=false)
|
55
|
-
types = [types] unless types.is_a? Array
|
56
55
|
if other.is_a?(Proc)
|
57
56
|
raise ArgumentError, (ERR_TYPE % [v.inspect, name, types.inspect]) unless other.call(v)
|
58
57
|
end
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
types.each { |t| return if v.is_a?(t) }
|
58
|
+
v_class = v.is_a?(Class) ? v : v.class
|
59
|
+
Array(types).each do |t|
|
60
|
+
return if v_class <= t
|
63
61
|
end
|
64
62
|
raise ArgumentError, (ERR_TYPE % [v.inspect, name, types.inspect])
|
65
63
|
end
|
@@ -80,34 +78,38 @@ module Axlsx
|
|
80
78
|
def self.validate_angle(v)
|
81
79
|
raise ArgumentError, (ERR_ANGLE % v.inspect) unless (v.to_i >= -5400000 && v.to_i <= 5400000)
|
82
80
|
end
|
83
|
-
|
81
|
+
|
82
|
+
# Validates an unsigned intger
|
83
|
+
UINT_VALIDATOR = lambda { |arg| arg.respond_to?(:>=) && arg >= 0 }
|
84
|
+
|
85
|
+
# Requires that the value is a Integer and is greater or equal to 0
|
84
86
|
# @param [Any] v The value validated
|
85
|
-
# @raise [ArgumentError] raised if the value is not a
|
87
|
+
# @raise [ArgumentError] raised if the value is not a Integer value greater or equal to 0
|
86
88
|
# @return [Boolean] true if the data is valid
|
87
89
|
def self.validate_unsigned_int(v)
|
88
|
-
DataTypeValidator.validate(:unsigned_int,
|
90
|
+
DataTypeValidator.validate(:unsigned_int, Integer, v, UINT_VALIDATOR)
|
89
91
|
end
|
90
92
|
|
91
|
-
# Requires that the value is a
|
93
|
+
# Requires that the value is a Integer or Float and is greater or equal to 0
|
92
94
|
# @param [Any] v The value validated
|
93
95
|
# @raise [ArgumentError] raised if the value is not a Fixnun, Integer, Float value greater or equal to 0
|
94
96
|
# @return [Boolean] true if the data is valid
|
95
97
|
def self.validate_unsigned_numeric(v)
|
96
|
-
DataTypeValidator.validate(
|
98
|
+
DataTypeValidator.validate(:unsigned_numeric, Numeric, v, UINT_VALIDATOR)
|
97
99
|
end
|
98
100
|
|
99
|
-
# Requires that the value is a
|
101
|
+
# Requires that the value is a Integer
|
100
102
|
# @param [Any] v The value validated
|
101
103
|
def self.validate_int(v)
|
102
|
-
DataTypeValidator.validate :
|
104
|
+
DataTypeValidator.validate :signed_int, Integer, v
|
103
105
|
end
|
104
106
|
|
105
107
|
# Requires that the value is a form that can be evaluated as a boolean in an xml document.
|
106
|
-
# The value must be an instance of
|
108
|
+
# The value must be an instance of String, Integer, Symbol, TrueClass or FalseClass and
|
107
109
|
# it must be one of 0, 1, "true", "false", :true, :false, true, false, "0", or "1"
|
108
110
|
# @param [Any] v The value validated
|
109
111
|
def self.validate_boolean(v)
|
110
|
-
DataTypeValidator.validate(:boolean, [
|
112
|
+
DataTypeValidator.validate(:boolean, [String, Integer, Symbol, TrueClass, FalseClass], v, lambda { |arg| [0, 1, "true", "false", :true, :false, true, false, "0", "1"].include?(arg) })
|
111
113
|
end
|
112
114
|
|
113
115
|
# Requires that the value is a String
|
@@ -130,12 +132,12 @@ module Axlsx
|
|
130
132
|
|
131
133
|
# Requires that the value is an integer ranging from 10 to 400.
|
132
134
|
def self.validate_scale_10_400(v)
|
133
|
-
DataTypeValidator.validate "page_scale",
|
135
|
+
DataTypeValidator.validate "page_scale", Integer, v, lambda { |arg| arg >= 10 && arg <= 400 }
|
134
136
|
end
|
135
137
|
|
136
138
|
# Requires that the value is an integer ranging from 10 to 400 or 0.
|
137
139
|
def self.validate_scale_0_10_400(v)
|
138
|
-
DataTypeValidator.validate "page_scale",
|
140
|
+
DataTypeValidator.validate "page_scale", Integer, v, lambda { |arg| arg == 0 || (arg >= 10 && arg <= 400) }
|
139
141
|
end
|
140
142
|
|
141
143
|
# Requires that the value is one of :default, :landscape, or :portrait.
|
@@ -147,7 +149,7 @@ module Axlsx
|
|
147
149
|
RestrictionValidator.validate "cell run style u", [:none, :single, :double, :singleAccounting, :doubleAccounting], v
|
148
150
|
end
|
149
151
|
|
150
|
-
# validates cell style family which must be between 1 and 5
|
152
|
+
# validates cell style family which must be between 1 and 5
|
151
153
|
def self.validate_family(v)
|
152
154
|
RestrictionValidator.validate "cell run style family", 1..5, v
|
153
155
|
end
|
@@ -297,4 +299,14 @@ module Axlsx
|
|
297
299
|
def self.validate_display_blanks_as(v)
|
298
300
|
RestrictionValidator.validate :display_blanks_as, [:gap, :span, :zero], v
|
299
301
|
end
|
302
|
+
|
303
|
+
# Requires that the value is one of :visible, :hidden, :very_hidden
|
304
|
+
def self.validate_view_visibility(v)
|
305
|
+
RestrictionValidator.validate :visibility, [:visible, :hidden, :very_hidden], v
|
306
|
+
end
|
307
|
+
|
308
|
+
# Requires that the value is one of :default, :circle, :dash, :diamond, :dot, :picture, :plus, :square, :star, :triangle, :x
|
309
|
+
def self.validate_marker_symbol(v)
|
310
|
+
RestrictionValidator.validate :marker_symbol, [:default, :circle, :dash, :diamond, :dot, :picture, :plus, :square, :star, :triangle, :x], v
|
311
|
+
end
|
300
312
|
end
|
data/lib/axlsx/version.rb
CHANGED
@@ -24,16 +24,16 @@
|
|
24
24
|
# </xsd:simpleContent>
|
25
25
|
|
26
26
|
module Axlsx
|
27
|
-
# This element defines the defined names that are defined within this workbook.
|
27
|
+
# This element defines the defined names that are defined within this workbook.
|
28
28
|
# Defined names are descriptive text that is used to represents a cell, range of cells, formula, or constant value.
|
29
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.
|
30
|
+
# A defined name in a formula can make it easier to understand the purpose of the formula.
|
31
31
|
# @example
|
32
32
|
# The formula =SUM(FirstQuarterSales) might be easier to identify than =SUM(C20:C30
|
33
33
|
#
|
34
34
|
# Names are available to any sheet.
|
35
35
|
# @example
|
36
|
-
# If the name ProjectedSales refers to the range A20:A30 on the first worksheet in a workbook,
|
36
|
+
# If the name ProjectedSales refers to the range A20:A30 on the first worksheet in a workbook,
|
37
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
38
|
# Names can also be used to represent formulas or values that do not change (constants).
|
39
39
|
#
|
@@ -71,7 +71,7 @@ module Axlsx
|
|
71
71
|
# applied. This represents the source data range, unfiltered.
|
72
72
|
# b. This defined name refers to a range to which an AutoFilter has been
|
73
73
|
# applied.
|
74
|
-
# _xlnm.Extract: this defined name refers to the range containing the filtered output
|
74
|
+
# _xlnm.Extract: this defined name refers to the range containing the filtered output
|
75
75
|
# values resulting from applying an advanced filter criteria to a source range.
|
76
76
|
# Miscellaneous
|
77
77
|
# _xlnm.Consolidate_Area: the defined name refers to a consolidation area.
|
@@ -88,14 +88,14 @@ module Axlsx
|
|
88
88
|
# This attribute is used when there is an add-in or other code project associated with the file.
|
89
89
|
# @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.
|
90
90
|
# @option [Boolean] xlm - Specifies a boolean value that indicates whether the defined name is related to an external function, command, or other executable code.
|
91
|
-
# @option [Integer] function_group_id - Specifies the function group index if the defined name refers to a function.
|
91
|
+
# @option [Integer] function_group_id - Specifies the function group index if the defined name refers to a function.
|
92
92
|
# The function group defines the general category for the function.
|
93
93
|
# This attribute is used when there is an add-in or other code project associated with the file.
|
94
94
|
# See Open Office XML Part 1 for more info.
|
95
95
|
# @option [String] short_cut_key - Specifies the keyboard shortcut for the defined name.
|
96
|
-
# @option [Boolean] publish_to_server - Specifies a boolean value that indicates whether the defined name is included in the
|
96
|
+
# @option [Boolean] publish_to_server - Specifies a boolean value that indicates whether the defined name is included in the
|
97
97
|
# version of the workbook that is published to or rendered on a Web or application server.
|
98
|
-
# @option [Boolean] workbook_parameter - Specifies a boolean value that indicates that the name is used as a workbook parameter on a
|
98
|
+
# @option [Boolean] workbook_parameter - Specifies a boolean value that indicates that the name is used as a workbook parameter on a
|
99
99
|
# version of the workbook that is published to or rendered on a Web or application server.
|
100
100
|
def initialize(formula, options={})
|
101
101
|
@formula = formula
|
@@ -116,14 +116,13 @@ module Axlsx
|
|
116
116
|
boolean_attr_accessor :workbook_parameter, :publish_to_server, :xlm, :vb_proceedure, :function, :hidden
|
117
117
|
|
118
118
|
serializable_attributes :short_cut_key, :status_bar, :help, :description, :custom_menu, :comment,
|
119
|
-
:workbook_parameter, :publish_to_server, :xlm, :vb_proceedure, :function, :hidden, :
|
119
|
+
:workbook_parameter, :publish_to_server, :xlm, :vb_proceedure, :function, :hidden, :local_sheet_id
|
120
120
|
|
121
121
|
def to_xml_string(str='')
|
122
|
-
raise ArgumentError, 'you must specify the name for this defined name. Please read the documentation for Axlsx::DefinedName for more details' unless name
|
123
|
-
str << '<definedName '
|
122
|
+
raise ArgumentError, 'you must specify the name for this defined name. Please read the documentation for Axlsx::DefinedName for more details' unless name
|
123
|
+
str << ('<definedName ' << 'name="' << name << '" ')
|
124
124
|
serialized_attributes str
|
125
|
-
str << '>' << @formula
|
126
|
-
str << '</definedName>'
|
125
|
+
str << ('>' << @formula << '</definedName>')
|
127
126
|
end
|
128
127
|
end
|
129
128
|
end
|
@@ -11,8 +11,8 @@ module Axlsx
|
|
11
11
|
# @param [String] str
|
12
12
|
# @return [String]
|
13
13
|
def to_xml_string(str = '')
|
14
|
-
return if
|
15
|
-
str <<
|
14
|
+
return if empty?
|
15
|
+
str << '<definedNames>'
|
16
16
|
each { |defined_name| defined_name.to_xml_string(str) }
|
17
17
|
str << '</definedNames>'
|
18
18
|
end
|
@@ -38,7 +38,7 @@ module Axlsx
|
|
38
38
|
@xml_space = xml_space
|
39
39
|
@unique_cells = {}
|
40
40
|
@shared_xml_string = ""
|
41
|
-
shareable_cells = cells.flatten.select{ |cell| cell.plain_string? }
|
41
|
+
shareable_cells = cells.flatten.select{ |cell| cell.plain_string? || cell.contains_rich_text? }
|
42
42
|
@count = shareable_cells.size
|
43
43
|
resolve(shareable_cells)
|
44
44
|
end
|
@@ -47,10 +47,10 @@ module Axlsx
|
|
47
47
|
# @param [String] str
|
48
48
|
# @return [String]
|
49
49
|
def to_xml_string(str='')
|
50
|
-
|
51
|
-
str << '
|
52
|
-
str << '
|
53
|
-
str =
|
50
|
+
Axlsx::sanitize(@shared_xml_string)
|
51
|
+
str << ('<?xml version="1.0" encoding="UTF-8"?><sst xmlns="' << XML_NS << '"')
|
52
|
+
str << (' count="' << @count.to_s << '" uniqueCount="' << unique_count.to_s << '"')
|
53
|
+
str << (' xml:space="' << xml_space.to_s << '">' << @shared_xml_string << '</sst>')
|
54
54
|
end
|
55
55
|
|
56
56
|
private
|
@@ -5,10 +5,13 @@ require 'axlsx/workbook/worksheet/auto_filter/auto_filter.rb'
|
|
5
5
|
require 'axlsx/workbook/worksheet/date_time_converter.rb'
|
6
6
|
require 'axlsx/workbook/worksheet/protected_range.rb'
|
7
7
|
require 'axlsx/workbook/worksheet/protected_ranges.rb'
|
8
|
+
require 'axlsx/workbook/worksheet/rich_text_run'
|
9
|
+
require 'axlsx/workbook/worksheet/rich_text'
|
8
10
|
require 'axlsx/workbook/worksheet/cell_serializer.rb'
|
9
11
|
require 'axlsx/workbook/worksheet/cell.rb'
|
10
12
|
require 'axlsx/workbook/worksheet/page_margins.rb'
|
11
13
|
require 'axlsx/workbook/worksheet/page_set_up_pr.rb'
|
14
|
+
require 'axlsx/workbook/worksheet/outline_pr.rb'
|
12
15
|
require 'axlsx/workbook/worksheet/page_setup.rb'
|
13
16
|
require 'axlsx/workbook/worksheet/header_footer.rb'
|
14
17
|
require 'axlsx/workbook/worksheet/print_options.rb'
|
@@ -37,7 +40,8 @@ require 'axlsx/workbook/worksheet/worksheet_hyperlinks'
|
|
37
40
|
require 'axlsx/workbook/worksheet/break'
|
38
41
|
require 'axlsx/workbook/worksheet/row_breaks'
|
39
42
|
require 'axlsx/workbook/worksheet/col_breaks'
|
40
|
-
|
43
|
+
require 'axlsx/workbook/workbook_view'
|
44
|
+
require 'axlsx/workbook/workbook_views'
|
41
45
|
|
42
46
|
|
43
47
|
require 'axlsx/workbook/worksheet/worksheet.rb'
|
@@ -93,6 +97,15 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
93
97
|
@use_shared_strings = v
|
94
98
|
end
|
95
99
|
|
100
|
+
# If true reverse the order in which the workbook is serialized
|
101
|
+
# @return [Boolean]
|
102
|
+
attr_reader :is_reversed
|
103
|
+
|
104
|
+
def is_reversed=(v)
|
105
|
+
Axlsx::validate_boolean(v)
|
106
|
+
@is_reversed = v
|
107
|
+
end
|
108
|
+
|
96
109
|
|
97
110
|
# A collection of worksheets associated with this workbook.
|
98
111
|
# @note The recommended way to manage worksheets is add_worksheet
|
@@ -139,6 +152,10 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
139
152
|
# @return [SimpleTypedList]
|
140
153
|
attr_reader :pivot_tables
|
141
154
|
|
155
|
+
# A collection of views for this workbook
|
156
|
+
def views
|
157
|
+
@views ||= WorkbookViews.new
|
158
|
+
end
|
142
159
|
|
143
160
|
# A collection of defined names for this workbook
|
144
161
|
# @note The recommended way to manage defined names is Workbook#add_defined_name
|
@@ -263,6 +280,14 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
263
280
|
worksheet
|
264
281
|
end
|
265
282
|
|
283
|
+
# Adds a new WorkbookView
|
284
|
+
# @return WorkbookViews
|
285
|
+
# @option options [Hash] options passed into the added WorkbookView
|
286
|
+
# @see WorkbookView#initialize
|
287
|
+
def add_view(options={})
|
288
|
+
views << WorkbookView.new(options)
|
289
|
+
end
|
290
|
+
|
266
291
|
# Adds a defined name to this workbook
|
267
292
|
# @return [DefinedName]
|
268
293
|
# @param [String] formula @see DefinedName
|
@@ -283,7 +308,7 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
283
308
|
end
|
284
309
|
r << Relationship.new(self, STYLES_R, STYLES_PN)
|
285
310
|
if use_shared_strings
|
286
|
-
r << Relationship.new(self, SHARED_STRINGS_R,
|
311
|
+
r << Relationship.new(self, SHARED_STRINGS_R, SHARED_STRINGS_PN)
|
287
312
|
end
|
288
313
|
r
|
289
314
|
end
|
@@ -327,23 +352,23 @@ require 'axlsx/workbook/worksheet/selection.rb'
|
|
327
352
|
# @param [String] str
|
328
353
|
# @return [String]
|
329
354
|
def to_xml_string(str='')
|
330
|
-
add_worksheet unless worksheets.size > 0
|
355
|
+
add_worksheet(name: 'Sheet1') unless worksheets.size > 0
|
331
356
|
str << '<?xml version="1.0" encoding="UTF-8"?>'
|
332
|
-
str << '<workbook xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '">'
|
333
|
-
str << '<workbookPr date1904="' << @@date1904.to_s << '"/>'
|
357
|
+
str << ('<workbook xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '">')
|
358
|
+
str << ('<workbookPr date1904="' << @@date1904.to_s << '"/>')
|
359
|
+
views.to_xml_string(str)
|
334
360
|
str << '<sheets>'
|
335
|
-
|
336
|
-
|
337
|
-
|
338
|
-
|
339
|
-
end
|
361
|
+
if is_reversed
|
362
|
+
worksheets.reverse_each { |sheet| sheet.to_sheet_node_xml_string(str) }
|
363
|
+
else
|
364
|
+
worksheets.each { |sheet| sheet.to_sheet_node_xml_string(str) }
|
340
365
|
end
|
341
366
|
str << '</sheets>'
|
342
367
|
defined_names.to_xml_string(str)
|
343
368
|
unless pivot_tables.empty?
|
344
369
|
str << '<pivotCaches>'
|
345
370
|
pivot_tables.each do |pivot_table|
|
346
|
-
str << '<pivotCache cacheId="' << pivot_table.cache_definition.cache_id.to_s << '" r:id="' << pivot_table.cache_definition.rId << '"/>'
|
371
|
+
str << ('<pivotCache cacheId="' << pivot_table.cache_definition.cache_id.to_s << '" r:id="' << pivot_table.cache_definition.rId << '"/>')
|
347
372
|
end
|
348
373
|
str << '</pivotCaches>'
|
349
374
|
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
# <xsd:complexType name="CT_BookView">
|
2
|
+
# <xsd:sequence>
|
3
|
+
# <xsd:element name="extLst" type="CT_ExtensionList" minOccurs="0" maxOccurs="1"/>
|
4
|
+
# </xsd:sequence>
|
5
|
+
# <xsd:attribute name="visibility" type="ST_Visibility" use="optional" default="visible"/>
|
6
|
+
# <xsd:attribute name="minimized" type="xsd:boolean" use="optional" default="false"/>
|
7
|
+
# <xsd:attribute name="showHorizontalScroll" type="xsd:boolean" use="optional" default="true"/>
|
8
|
+
# <xsd:attribute name="showVerticalScroll" type="xsd:boolean" use="optional" default="true"/>
|
9
|
+
# <xsd:attribute name="showSheetTabs" type="xsd:boolean" use="optional" default="true"/>
|
10
|
+
# <xsd:attribute name="xWindow" type="xsd:int" use="optional"/>
|
11
|
+
# <xsd:attribute name="yWindow" type="xsd:int" use="optional"/>
|
12
|
+
# <xsd:attribute name="windowWidth" type="xsd:unsignedInt" use="optional"/>
|
13
|
+
# <xsd:attribute name="windowHeight" type="xsd:unsignedInt" use="optional"/>
|
14
|
+
# <xsd:attribute name="tabRatio" type="xsd:unsignedInt" use="optional" default="600"/>
|
15
|
+
# <xsd:attribute name="firstSheet" type="xsd:unsignedInt" use="optional" default="0"/>
|
16
|
+
# <xsd:attribute name="activeTab" type="xsd:unsignedInt" use="optional" default="0"/>
|
17
|
+
# <xsd:attribute name="autoFilterDateGrouping" type="xsd:boolean" use="optional"
|
18
|
+
# default="true"/>
|
19
|
+
# </xsd:complexType>
|
20
|
+
|
21
|
+
module Axlsx
|
22
|
+
|
23
|
+
# A BookView defines the display properties for a workbook.
|
24
|
+
# Units for window widths and other dimensions are expressed in twips.
|
25
|
+
# Twip measurements are portable between different display resolutions.
|
26
|
+
# The formula is (screen pixels) * (20 * 72) / (logical device dpi),
|
27
|
+
# where the logical device dpi can be different for x and y coordinates.
|
28
|
+
class WorkbookView
|
29
|
+
|
30
|
+
include Axlsx::SerializedAttributes
|
31
|
+
include Axlsx::OptionsParser
|
32
|
+
include Axlsx::Accessors
|
33
|
+
|
34
|
+
|
35
|
+
# Creates a new BookView object
|
36
|
+
# @param [Hash] options A hash of key/value pairs that will be mapped to this instances attributes.
|
37
|
+
# @option [Symbol] visibility Specifies visible state of the workbook window. The default value for this attribute is :visible.
|
38
|
+
# @option [Boolean] minimized Specifies a boolean value that indicates whether the workbook window is minimized.
|
39
|
+
# @option [Boolean] show_horizontal_scroll Specifies a boolean value that indicates whether to display the horizontal scroll bar in the user interface.
|
40
|
+
# @option [Boolean] show_vertical_scroll Specifies a boolean value that indicates whether to display the vertical scroll bar.
|
41
|
+
# @option [Boolean] show_sheet_tabs Specifies a boolean value that indicates whether to display the sheet tabs in the user interface.
|
42
|
+
# @option [Integer] tab_ratio Specifies ratio between the workbook tabs bar and the horizontal scroll bar.
|
43
|
+
# @option [Integer] first_sheet Specifies the index to the first sheet in this book view.
|
44
|
+
# @option [Integer] active_tab Specifies an unsignedInt that contains the index to the active sheet in this book view.
|
45
|
+
# @option [Integer] x_window Specifies the X coordinate for the upper left corner of the workbook window. The unit of measurement for this value is twips.
|
46
|
+
# @option [Integer] y_window Specifies the Y coordinate for the upper left corner of the workbook window. The unit of measurement for this value is twips.
|
47
|
+
# @option [Integer] window_width Specifies the width of the workbook window. The unit of measurement for this value is twips.
|
48
|
+
# @option [Integer] window_height Specifies the height of the workbook window. The unit of measurement for this value is twips.
|
49
|
+
# @option [Boolean] auto_filter_date_grouping Specifies a boolean value that indicates whether to group dates when presenting the user with filtering options in the user interface.
|
50
|
+
def initialize(options={})
|
51
|
+
parse_options options
|
52
|
+
yield self if block_given?
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
unsigned_int_attr_accessor :x_window, :y_window, :window_width, :window_height,
|
57
|
+
:tab_ratio, :first_sheet, :active_tab
|
58
|
+
|
59
|
+
validated_attr_accessor [:visibility], :validate_view_visibility
|
60
|
+
|
61
|
+
serializable_attributes :visibility, :minimized,
|
62
|
+
:show_horizontal_scroll, :show_vertical_scroll,
|
63
|
+
:show_sheet_tabs, :tab_ratio, :first_sheet, :active_tab,
|
64
|
+
:x_window, :y_window, :window_width, :window_height,
|
65
|
+
:auto_filter_date_grouping
|
66
|
+
|
67
|
+
boolean_attr_accessor :minimized, :show_horizontal_scroll, :show_vertical_scroll,
|
68
|
+
:show_sheet_tabs, :auto_filter_date_grouping
|
69
|
+
|
70
|
+
|
71
|
+
# Serialize the WorkbookView
|
72
|
+
# @param [String] str
|
73
|
+
# @return [String]
|
74
|
+
def to_xml_string(str = '')
|
75
|
+
str << '<workbookView '
|
76
|
+
serialized_attributes str
|
77
|
+
str << '></workbookView>'
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Axlsx
|
2
|
+
# a simple types list of BookView objects
|
3
|
+
class WorkbookViews < SimpleTypedList
|
4
|
+
|
5
|
+
# creates the book views object
|
6
|
+
def initialize
|
7
|
+
super WorkbookView
|
8
|
+
end
|
9
|
+
|
10
|
+
# Serialize to xml
|
11
|
+
# @param [String] str
|
12
|
+
# @return [String]
|
13
|
+
def to_xml_string(str = '')
|
14
|
+
return if empty?
|
15
|
+
str << "<bookViews>"
|
16
|
+
each { |view| view.to_xml_string(str) }
|
17
|
+
str << '</bookViews>'
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
|
@@ -47,8 +47,8 @@ module Axlsx
|
|
47
47
|
columns.last
|
48
48
|
end
|
49
49
|
|
50
|
-
# actually performs the filtering of rows who's cells do not
|
51
|
-
# match the filter.
|
50
|
+
# actually performs the filtering of rows who's cells do not
|
51
|
+
# match the filter.
|
52
52
|
def apply
|
53
53
|
first_cell, last_cell = range.split(':')
|
54
54
|
start_point = Axlsx::name_to_indices(first_cell)
|
@@ -237,9 +237,7 @@ include Axlsx::SerializedAttributes
|
|
237
237
|
# Serialize the object to xml
|
238
238
|
# @param [String] str The string object this serialization will be concatenated to.
|
239
239
|
def to_xml_string(str = '')
|
240
|
-
|
241
|
-
serialized_attributes str
|
242
|
-
str << '/>'
|
240
|
+
serialized_tag('dateGroupItem', str)
|
243
241
|
end
|
244
242
|
end
|
245
243
|
end
|