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.
Files changed (180) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +5 -0
  3. data/README.md +23 -23
  4. data/Rakefile +9 -11
  5. data/examples/auto_filter.rb +10 -1
  6. data/examples/conditional_formatting/example_conditional_formatting.rb +18 -3
  7. data/examples/example.rb +102 -4
  8. data/examples/merge_cells.rb +17 -0
  9. data/examples/no_grid_with_borders.rb +18 -0
  10. data/examples/pivot_test.rb +63 -0
  11. data/examples/split.rb +16 -0
  12. data/lib/axlsx/content_type/abstract_content_type.rb +1 -1
  13. data/lib/axlsx/content_type/content_type.rb +1 -1
  14. data/lib/axlsx/doc_props/app.rb +1 -1
  15. data/lib/axlsx/doc_props/core.rb +5 -5
  16. data/lib/axlsx/drawing/area_chart.rb +99 -0
  17. data/lib/axlsx/drawing/area_series.rb +110 -0
  18. data/lib/axlsx/drawing/axes.rb +1 -1
  19. data/lib/axlsx/drawing/axis.rb +12 -9
  20. data/lib/axlsx/drawing/bar_3D_chart.rb +13 -13
  21. data/lib/axlsx/drawing/bar_chart.rb +143 -0
  22. data/lib/axlsx/drawing/bar_series.rb +9 -9
  23. data/lib/axlsx/drawing/bubble_chart.rb +59 -0
  24. data/lib/axlsx/drawing/bubble_series.rb +63 -0
  25. data/lib/axlsx/drawing/cat_axis.rb +5 -5
  26. data/lib/axlsx/drawing/chart.rb +52 -8
  27. data/lib/axlsx/drawing/d_lbls.rb +3 -3
  28. data/lib/axlsx/drawing/drawing.rb +6 -1
  29. data/lib/axlsx/drawing/graphic_frame.rb +3 -3
  30. data/lib/axlsx/drawing/hyperlink.rb +1 -3
  31. data/lib/axlsx/drawing/line_3D_chart.rb +2 -2
  32. data/lib/axlsx/drawing/line_chart.rb +10 -10
  33. data/lib/axlsx/drawing/line_series.rb +32 -3
  34. data/lib/axlsx/drawing/marker.rb +1 -1
  35. data/lib/axlsx/drawing/num_data.rb +4 -4
  36. data/lib/axlsx/drawing/num_data_source.rb +6 -6
  37. data/lib/axlsx/drawing/num_val.rb +3 -1
  38. data/lib/axlsx/drawing/one_cell_anchor.rb +3 -2
  39. data/lib/axlsx/drawing/pic.rb +25 -19
  40. data/lib/axlsx/drawing/picture_locking.rb +1 -3
  41. data/lib/axlsx/drawing/pie_3D_chart.rb +5 -6
  42. data/lib/axlsx/drawing/pie_series.rb +6 -6
  43. data/lib/axlsx/drawing/scaling.rb +6 -6
  44. data/lib/axlsx/drawing/scatter_chart.rb +10 -10
  45. data/lib/axlsx/drawing/scatter_series.rb +40 -7
  46. data/lib/axlsx/drawing/ser_axis.rb +2 -2
  47. data/lib/axlsx/drawing/series.rb +3 -3
  48. data/lib/axlsx/drawing/series_title.rb +2 -2
  49. data/lib/axlsx/drawing/str_data.rb +3 -3
  50. data/lib/axlsx/drawing/str_val.rb +3 -1
  51. data/lib/axlsx/drawing/title.rb +22 -4
  52. data/lib/axlsx/drawing/two_cell_anchor.rb +6 -1
  53. data/lib/axlsx/drawing/val_axis.rb +1 -1
  54. data/lib/axlsx/drawing/view_3D.rb +2 -2
  55. data/lib/axlsx/drawing/vml_drawing.rb +1 -1
  56. data/lib/axlsx/package.rb +34 -32
  57. data/lib/axlsx/rels/relationship.rb +1 -1
  58. data/lib/axlsx/rels/relationships.rb +7 -4
  59. data/lib/axlsx/stylesheet/border_pr.rb +2 -2
  60. data/lib/axlsx/stylesheet/cell_alignment.rb +1 -3
  61. data/lib/axlsx/stylesheet/cell_protection.rb +1 -3
  62. data/lib/axlsx/stylesheet/cell_style.rb +1 -3
  63. data/lib/axlsx/stylesheet/color.rb +1 -3
  64. data/lib/axlsx/stylesheet/font.rb +1 -1
  65. data/lib/axlsx/stylesheet/gradient_stop.rb +1 -1
  66. data/lib/axlsx/stylesheet/num_fmt.rb +10 -3
  67. data/lib/axlsx/stylesheet/pattern_fill.rb +1 -1
  68. data/lib/axlsx/stylesheet/styles.rb +7 -7
  69. data/lib/axlsx/stylesheet/table_style_element.rb +1 -3
  70. data/lib/axlsx/util/accessors.rb +6 -6
  71. data/lib/axlsx/util/constants.rb +107 -99
  72. data/lib/axlsx/util/mime_type_utils.rb +11 -0
  73. data/lib/axlsx/util/options_parser.rb +2 -1
  74. data/lib/axlsx/util/parser.rb +4 -4
  75. data/lib/axlsx/util/serialized_attributes.rb +16 -6
  76. data/lib/axlsx/util/simple_typed_list.rb +28 -52
  77. data/lib/axlsx/util/storage.rb +4 -4
  78. data/lib/axlsx/util/validators.rb +29 -17
  79. data/lib/axlsx/version.rb +1 -1
  80. data/lib/axlsx/workbook/defined_name.rb +11 -12
  81. data/lib/axlsx/workbook/defined_names.rb +2 -2
  82. data/lib/axlsx/workbook/shared_strings_table.rb +5 -5
  83. data/lib/axlsx/workbook/workbook.rb +36 -11
  84. data/lib/axlsx/workbook/workbook_view.rb +80 -0
  85. data/lib/axlsx/workbook/workbook_views.rb +22 -0
  86. data/lib/axlsx/workbook/worksheet/auto_filter/auto_filter.rb +2 -2
  87. data/lib/axlsx/workbook/worksheet/auto_filter/filters.rb +1 -3
  88. data/lib/axlsx/workbook/worksheet/break.rb +1 -3
  89. data/lib/axlsx/workbook/worksheet/cell.rb +136 -74
  90. data/lib/axlsx/workbook/worksheet/cell_serializer.rb +63 -43
  91. data/lib/axlsx/workbook/worksheet/cfvo.rb +1 -3
  92. data/lib/axlsx/workbook/worksheet/cfvos.rb +4 -1
  93. data/lib/axlsx/workbook/worksheet/col.rb +7 -10
  94. data/lib/axlsx/workbook/worksheet/col_breaks.rb +2 -2
  95. data/lib/axlsx/workbook/worksheet/cols.rb +5 -2
  96. data/lib/axlsx/workbook/worksheet/comment.rb +5 -6
  97. data/lib/axlsx/workbook/worksheet/comments.rb +9 -12
  98. data/lib/axlsx/workbook/worksheet/conditional_formatting.rb +1 -1
  99. data/lib/axlsx/workbook/worksheet/conditional_formatting_rule.rb +1 -1
  100. data/lib/axlsx/workbook/worksheet/data_bar.rb +4 -6
  101. data/lib/axlsx/workbook/worksheet/data_validation.rb +6 -4
  102. data/lib/axlsx/workbook/worksheet/dimension.rb +2 -2
  103. data/lib/axlsx/workbook/worksheet/header_footer.rb +6 -8
  104. data/lib/axlsx/workbook/worksheet/icon_set.rb +3 -5
  105. data/lib/axlsx/workbook/worksheet/merged_cells.rb +4 -2
  106. data/lib/axlsx/workbook/worksheet/outline_pr.rb +33 -0
  107. data/lib/axlsx/workbook/worksheet/page_margins.rb +1 -3
  108. data/lib/axlsx/workbook/worksheet/page_set_up_pr.rb +1 -1
  109. data/lib/axlsx/workbook/worksheet/page_setup.rb +21 -23
  110. data/lib/axlsx/workbook/worksheet/pane.rb +1 -3
  111. data/lib/axlsx/workbook/worksheet/pivot_table.rb +44 -28
  112. data/lib/axlsx/workbook/worksheet/pivot_table_cache_definition.rb +4 -4
  113. data/lib/axlsx/workbook/worksheet/print_options.rb +1 -3
  114. data/lib/axlsx/workbook/worksheet/protected_range.rb +1 -3
  115. data/lib/axlsx/workbook/worksheet/protected_ranges.rb +5 -2
  116. data/lib/axlsx/workbook/worksheet/rich_text.rb +55 -0
  117. data/lib/axlsx/workbook/worksheet/rich_text_run.rb +250 -0
  118. data/lib/axlsx/workbook/worksheet/row.rb +40 -51
  119. data/lib/axlsx/workbook/worksheet/row_breaks.rb +2 -2
  120. data/lib/axlsx/workbook/worksheet/selection.rb +1 -3
  121. data/lib/axlsx/workbook/worksheet/sheet_data.rb +3 -1
  122. data/lib/axlsx/workbook/worksheet/sheet_pr.rb +21 -3
  123. data/lib/axlsx/workbook/worksheet/sheet_protection.rb +1 -3
  124. data/lib/axlsx/workbook/worksheet/table.rb +6 -6
  125. data/lib/axlsx/workbook/worksheet/table_style_info.rb +1 -3
  126. data/lib/axlsx/workbook/worksheet/tables.rb +4 -1
  127. data/lib/axlsx/workbook/worksheet/worksheet.rb +64 -78
  128. data/lib/axlsx/workbook/worksheet/worksheet_drawing.rb +10 -10
  129. data/lib/axlsx/workbook/worksheet/worksheet_hyperlinks.rb +3 -3
  130. data/lib/axlsx.rb +34 -15
  131. data/test/drawing/tc_area_chart.rb +39 -0
  132. data/test/drawing/tc_area_series.rb +71 -0
  133. data/test/drawing/tc_axis.rb +27 -0
  134. data/test/drawing/tc_bar_chart.rb +71 -0
  135. data/test/drawing/tc_bubble_chart.rb +44 -0
  136. data/test/drawing/tc_bubble_series.rb +21 -0
  137. data/test/drawing/tc_chart.rb +23 -10
  138. data/test/drawing/tc_data_source.rb +6 -0
  139. data/test/drawing/tc_drawing.rb +2 -2
  140. data/test/drawing/tc_line_chart.rb +5 -5
  141. data/test/drawing/tc_line_series.rb +47 -6
  142. data/test/drawing/tc_pic.rb +11 -15
  143. data/test/drawing/tc_scatter_series.rb +36 -1
  144. data/test/drawing/tc_str_val.rb +9 -0
  145. data/test/drawing/tc_title.rb +5 -0
  146. data/test/stylesheet/tc_styles.rb +2 -2
  147. data/test/tc_axlsx.rb +31 -0
  148. data/test/tc_helper.rb +2 -0
  149. data/test/tc_package.rb +19 -1
  150. data/test/util/tc_mime_type_utils.rb +13 -0
  151. data/test/util/tc_simple_typed_list.rb +2 -3
  152. data/test/util/tc_validators.rb +34 -10
  153. data/test/workbook/tc_defined_name.rb +12 -4
  154. data/test/workbook/tc_shared_strings_table.rb +16 -1
  155. data/test/workbook/tc_workbook.rb +38 -3
  156. data/test/workbook/tc_workbook_view.rb +50 -0
  157. data/test/workbook/worksheet/auto_filter/tc_filters.rb +1 -1
  158. data/test/workbook/worksheet/tc_break.rb +1 -1
  159. data/test/workbook/worksheet/tc_cell.rb +76 -8
  160. data/test/workbook/worksheet/tc_col.rb +2 -2
  161. data/test/workbook/worksheet/tc_conditional_formatting.rb +2 -2
  162. data/test/workbook/worksheet/tc_data_bar.rb +1 -1
  163. data/test/workbook/worksheet/tc_data_validation.rb +11 -11
  164. data/test/workbook/worksheet/tc_header_footer.rb +2 -2
  165. data/test/workbook/worksheet/tc_icon_set.rb +1 -1
  166. data/test/workbook/worksheet/tc_outline_pr.rb +19 -0
  167. data/test/workbook/worksheet/tc_page_setup.rb +3 -3
  168. data/test/workbook/worksheet/tc_pivot_table.rb +21 -6
  169. data/test/workbook/worksheet/tc_print_options.rb +1 -1
  170. data/test/workbook/worksheet/tc_rich_text.rb +44 -0
  171. data/test/workbook/worksheet/tc_rich_text_run.rb +172 -0
  172. data/test/workbook/worksheet/tc_row.rb +7 -2
  173. data/test/workbook/worksheet/tc_sheet_calc_pr.rb +1 -1
  174. data/test/workbook/worksheet/tc_sheet_format_pr.rb +4 -4
  175. data/test/workbook/worksheet/tc_sheet_pr.rb +26 -4
  176. data/test/workbook/worksheet/tc_sheet_protection.rb +5 -5
  177. data/test/workbook/worksheet/tc_sheet_view.rb +4 -4
  178. data/test/workbook/worksheet/tc_table.rb +2 -3
  179. data/test/workbook/worksheet/tc_worksheet.rb +99 -45
  180. metadata +142 -64
@@ -1,6 +1,6 @@
1
1
  module Axlsx
2
2
 
3
- # The cols class manages the col object used to manage column widths.
3
+ # The cols class manages the col object used to manage column widths.
4
4
  # This is where the magic happens with autowidth
5
5
  class Cols < SimpleTypedList
6
6
 
@@ -10,11 +10,14 @@ module Axlsx
10
10
  @worksheet = worksheet
11
11
  end
12
12
 
13
+ # Serialize the Cols object
14
+ # @param [String] str
15
+ # @return [String]
13
16
  def to_xml_string(str = '')
14
17
  return if empty?
15
18
  str << '<cols>'
16
19
  each { |item| item.to_xml_string(str) }
17
- str << '</cols>'
20
+ str << '</cols>'
18
21
  end
19
22
  end
20
23
  end
@@ -24,11 +24,10 @@ module Axlsx
24
24
  string_attr_accessor :text, :author
25
25
  boolean_attr_accessor :visible
26
26
 
27
- # The owning Comments object
27
+ # The owning Comments object
28
28
  # @return [Comments]
29
29
  attr_reader :comments
30
30
 
31
-
32
31
  # The string based cell position reference (e.g. 'A1') that determines the positioning of this comment
33
32
  # @return [String|Cell]
34
33
  attr_reader :ref
@@ -53,7 +52,7 @@ module Axlsx
53
52
 
54
53
  # @see ref
55
54
  def ref=(v)
56
- Axlsx::DataTypeValidator.validate "Comment.ref", [String, Cell], v
55
+ Axlsx::DataTypeValidator.validate :comment_ref, [String, Cell], v
57
56
  @ref = v if v.is_a?(String)
58
57
  @ref = v.r if v.is_a?(Cell)
59
58
  end
@@ -63,15 +62,15 @@ module Axlsx
63
62
  # @return [String]
64
63
  def to_xml_string(str = "")
65
64
  author = @comments.authors[author_index]
66
- str << '<comment ref="' << ref << '" authorId="' << author_index.to_s << '">'
65
+ str << ('<comment ref="' << ref << '" authorId="' << author_index.to_s << '">')
67
66
  str << '<text>'
68
67
  unless author.to_s == ""
69
68
  str << '<r><rPr><b/><color indexed="81"/></rPr>'
70
- str << "<t>" << ::CGI.escapeHTML(author.to_s) << ":\n</t></r>"
69
+ str << ("<t>" << ::CGI.escapeHTML(author.to_s) << ":\n</t></r>")
71
70
  end
72
71
  str << '<r>'
73
72
  str << '<rPr><color indexed="81"/></rPr>'
74
- str << '<t>' << ::CGI.escapeHTML(text) << '</t></r></text>'
73
+ str << ('<t>' << ::CGI.escapeHTML(text) << '</t></r></text>')
75
74
  str << '</comment>'
76
75
  end
77
76
 
@@ -42,23 +42,22 @@ module Axlsx
42
42
  raise ArgumentError, "Comment require an author" unless options[:author]
43
43
  raise ArgumentError, "Comment requires text" unless options[:text]
44
44
  raise ArgumentError, "Comment requires ref" unless options[:ref]
45
- @list << Comment.new(self, options)
46
- yield @list.last if block_given?
47
- @list.last
45
+ self << Comment.new(self, options)
46
+ yield last if block_given?
47
+ last
48
48
  end
49
49
 
50
50
  # A sorted list of the unique authors in the contained comments
51
51
  # @return [Array]
52
52
  def authors
53
- @list.map { |comment| comment.author.to_s }.uniq.sort
53
+ map { |comment| comment.author.to_s }.uniq.sort
54
54
  end
55
55
 
56
56
  # The relationships required by this object
57
57
  # @return [Array]
58
58
  def relationships
59
59
  [Relationship.new(self, VML_DRAWING_R, "../#{vml_drawing.pn}"),
60
- Relationship.new(self, COMMENT_R, "../#{pn}"),
61
- Relationship.new(self, COMMENT_R_NULL, "NULL")]
60
+ Relationship.new(self, COMMENT_R, "../#{pn}")]
62
61
  end
63
62
 
64
63
  # serialize the object
@@ -66,14 +65,12 @@ module Axlsx
66
65
  # @return [String]
67
66
  def to_xml_string(str="")
68
67
  str << '<?xml version="1.0" encoding="UTF-8"?>'
69
- str << '<comments xmlns="' << XML_NS << '">'
70
- str << '<authors>'
68
+ str << ('<comments xmlns="' << XML_NS << '"><authors>')
71
69
  authors.each do |author|
72
- str << '<author>' << author.to_s << '</author>'
70
+ str << ('<author>' << author.to_s << '</author>')
73
71
  end
74
- str << '</authors>'
75
- str << '<commentList>'
76
- @list.each do |comment|
72
+ str << '</authors><commentList>'
73
+ each do |comment|
77
74
  comment.to_xml_string str
78
75
  end
79
76
  str << '</commentList></comments>'
@@ -74,7 +74,7 @@ module Axlsx
74
74
  # @param [String] str
75
75
  # @return [String]
76
76
  def to_xml_string(str = '')
77
- str << '<conditionalFormatting sqref="' << sqref << '">'
77
+ str << ('<conditionalFormatting sqref="' << sqref << '">')
78
78
  str << rules.collect{ |rule| rule.to_xml_string }.join(' ')
79
79
  str << '</conditionalFormatting>'
80
80
  end
@@ -210,7 +210,7 @@ module Axlsx
210
210
  str << '<cfRule '
211
211
  serialized_attributes str
212
212
  str << '>'
213
- str << '<formula>' << [*self.formula].join('</formula><formula>') << '</formula>' if @formula
213
+ str << ('<formula>' << [*self.formula].join('</formula><formula>') << '</formula>') if @formula
214
214
  @color_scale.to_xml_string(str) if @color_scale && @type == :colorScale
215
215
  @data_bar.to_xml_string(str) if @data_bar && @type == :dataBar
216
216
  @icon_set.to_xml_string(str) if @icon_set && @type == :iconSet
@@ -107,12 +107,10 @@ module Axlsx
107
107
  # @param [String] str
108
108
  # @return [String]
109
109
  def to_xml_string(str="")
110
- str << '<dataBar '
111
- serialized_attributes str
112
- str << '>'
113
- value_objects.to_xml_string(str)
114
- self.color.to_xml_string(str)
115
- str << '</dataBar>'
110
+ serialized_tag('dataBar', str) do
111
+ value_objects.to_xml_string(str)
112
+ self.color.to_xml_string(str)
113
+ end
116
114
  end
117
115
 
118
116
  private
@@ -33,7 +33,7 @@ module Axlsx
33
33
  end
34
34
 
35
35
  # instance values that must be serialized as their own elements - e.g. not attributes.
36
- CHILD_ELEMENTS = [:formula1, :formula2]
36
+ CHILD_ELEMENTS = [:formula1, :formula2].freeze
37
37
 
38
38
  # Formula1
39
39
  # Available for type whole, decimal, date, time, textLength, list, custom
@@ -216,10 +216,12 @@ module Axlsx
216
216
  valid_attributes = get_valid_attributes
217
217
 
218
218
  str << '<dataValidation '
219
- str << instance_values.map { |key, value| '' << key << '="' << value.to_s << '"' if (valid_attributes.include?(key.to_sym) and not CHILD_ELEMENTS.include?(key.to_sym)) }.join(' ')
219
+ str << instance_values.map do |key, value|
220
+ '' << key << '="' << Axlsx.booleanize(value).to_s << '"' if (valid_attributes.include?(key.to_sym) && !CHILD_ELEMENTS.include?(key.to_sym))
221
+ end.join(' ')
220
222
  str << '>'
221
- str << '<formula1>' << self.formula1 << '</formula1>' if @formula1 and valid_attributes.include?(:formula1)
222
- str << '<formula2>' << self.formula2 << '</formula2>' if @formula2 and valid_attributes.include?(:formula2)
223
+ str << ('<formula1>' << self.formula1 << '</formula1>') if @formula1 and valid_attributes.include?(:formula1)
224
+ str << ('<formula2>' << self.formula2 << '</formula2>') if @formula2 and valid_attributes.include?(:formula2)
223
225
  str << '</dataValidation>'
224
226
  end
225
227
 
@@ -43,13 +43,13 @@ module Axlsx
43
43
  # The first cell in the dimension
44
44
  # @return [String]
45
45
  def first_cell_reference
46
- dimension_reference(worksheet.rows.first.cells.first, Dimension.default_first)
46
+ dimension_reference(worksheet.rows.first.first, Dimension.default_first)
47
47
  end
48
48
 
49
49
  # the last cell in the dimension
50
50
  # @return [String]
51
51
  def last_cell_reference
52
- dimension_reference(worksheet.rows.last.cells.last, Dimension.default_last)
52
+ dimension_reference(worksheet.rows.last.last, Dimension.default_last)
53
53
  end
54
54
 
55
55
  private
@@ -19,8 +19,8 @@ module Axlsx
19
19
  # @option options [String] odd_footer The content for footers on odd numbered pages.
20
20
  # @option options [String] even_header The content for headers on even numbered pages.
21
21
  # @option options [String] even_footer The content for footers on even numbered pages.
22
- # @option options [String] first_header The content for headers on even numbered pages.
23
- # @option options [String] first_footer The content for footers on even numbered pages.
22
+ # @option options [String] first_header The content for headers on the first page.
23
+ # @option options [String] first_footer The content for footers on the first page.
24
24
  # @option options [Boolean] different_odd_even Setting this to true will show different headers/footers on odd and even pages. When false, the odd headers/footers are used on each page. (Default: false)
25
25
  # @option options [Boolean] different_first If true, will use the first header/footer on page 1. Otherwise, the odd header/footer is used.
26
26
  def initialize(options = {})
@@ -42,13 +42,11 @@ module Axlsx
42
42
  # @param [String] str
43
43
  # @return [String]
44
44
  def to_xml_string(str = '')
45
- str << "<headerFooter "
46
- serialized_attributes str
47
- str << ">"
48
- serialized_element_attributes(str) do |value|
49
- value = ::CGI.escapeHTML(value)
45
+ serialized_tag('headerFooter', str) do
46
+ serialized_element_attributes(str) do |value|
47
+ value = ::CGI.escapeHTML(value)
48
+ end
50
49
  end
51
- str << "</headerFooter>"
52
50
  end
53
51
  end
54
52
  end
@@ -63,11 +63,9 @@ module Axlsx
63
63
  # @param [String] str
64
64
  # @return [String]
65
65
  def to_xml_string(str="")
66
- str << '<iconSet '
67
- serialized_attributes str
68
- str << '>'
69
- @value_objects.each { |cfvo| cfvo.to_xml_string(str) }
70
- str << '</iconSet>'
66
+ serialized_tag('iconSet', str) do
67
+ @value_objects.each { |cfvo| cfvo.to_xml_string(str) }
68
+ end
71
69
  end
72
70
 
73
71
  private
@@ -15,10 +15,12 @@ module Axlsx
15
15
  # collection. This can be an array of actual cells or a string style
16
16
  # range like 'A1:C1'
17
17
  def add(cells)
18
- @list << if cells.is_a?(String)
18
+ self << if cells.is_a?(String)
19
19
  cells
20
20
  elsif cells.is_a?(Array)
21
21
  Axlsx::cell_range(cells, false)
22
+ elsif cells.is_a?(Row)
23
+ Axlsx::cell_range(cells, false)
22
24
  end
23
25
  end
24
26
 
@@ -26,7 +28,7 @@ module Axlsx
26
28
  # @param [String] str
27
29
  # @return [String]
28
30
  def to_xml_string(str = '')
29
- return if @list.empty?
31
+ return if empty?
30
32
  str << "<mergeCells count='#{size}'>"
31
33
  each { |merged_cell| str << "<mergeCell ref='#{merged_cell}'></mergeCell>" }
32
34
  str << '</mergeCells>'
@@ -0,0 +1,33 @@
1
+ module Axlsx
2
+
3
+ # The OutlinePr class manages serialization of a worksheet's outlinePr element, which provides various
4
+ # options to control outlining.
5
+ class OutlinePr
6
+ include Axlsx::OptionsParser
7
+ include Axlsx::Accessors
8
+ include Axlsx::SerializedAttributes
9
+
10
+ serializable_attributes :summary_below,
11
+ :summary_right,
12
+ :apply_styles
13
+
14
+ # These attributes are all boolean so I'm doing a bit of a hand
15
+ # waving magic show to set up the attriubte accessors
16
+ boolean_attr_accessor :summary_below,
17
+ :summary_right,
18
+ :apply_styles
19
+
20
+ # Creates a new OutlinePr object
21
+ # @param [Hash] options used to create the outline_pr
22
+ def initialize(options = {})
23
+ parse_options options
24
+ end
25
+
26
+ # Serialize the object
27
+ # @param [String] str serialized output will be appended to this object if provided.
28
+ # @return [String]
29
+ def to_xml_string(str = '')
30
+ str << "<outlinePr #{serialized_attributes} />"
31
+ end
32
+ end
33
+ end
@@ -91,9 +91,7 @@ module Axlsx
91
91
  # @note For compatibility, this is a noop unless custom margins have been specified.
92
92
  # @see #custom_margins_specified?
93
93
  def to_xml_string(str = '')
94
- str << '<pageMargins '
95
- serialized_attributes str
96
- str << '/>'
94
+ serialized_tag('pageMargins', str)
97
95
  end
98
96
  end
99
97
  end
@@ -38,7 +38,7 @@ module Axlsx
38
38
 
39
39
  # serialize to xml
40
40
  def to_xml_string(str='')
41
- str << '<pageSetUpPr ' << serialized_attributes << '/>'
41
+ str << ('<pageSetUpPr ' << serialized_attributes << '/>')
42
42
  end
43
43
  end
44
44
  end
@@ -44,13 +44,13 @@ module Axlsx
44
44
 
45
45
  # Number of horizontal pages to fit on.
46
46
  # @note PageSetup#fit_to is the recomended way to manage page fitting as only specifying one of width/height will result in the counterpart
47
- # being set to 1.
47
+ # being set to 1.
48
48
  # @return [Integer]
49
49
  attr_reader :fit_to_width
50
50
 
51
51
  # Orientation of the page (:default, :landscape, :portrait)
52
52
  # @return [Symbol]
53
- attr_reader :orientation
53
+ attr_reader :orientation
54
54
 
55
55
  # Height of paper (string containing a number followed by a unit identifier: "297mm", "11in")
56
56
  # @return [String]
@@ -74,18 +74,18 @@ module Axlsx
74
74
  #7 = Executive paper (7.25 in. by 10.5 in.)
75
75
  #8 = A3 paper (297 mm by 420 mm)
76
76
  #9 = A4 paper (210 mm by 297 mm)
77
- #10 = A4 small paper (210 mm by 297 mm)
77
+ #10 = A4 small paper (210 mm by 297 mm)
78
78
  #11 = A5 paper (148 mm by 210 mm)
79
79
  #12 = B4 paper (250 mm by 353 mm)
80
80
  #13 = B5 paper (176 mm by 250 mm)
81
81
  #14 = Folio paper (8.5 in. by 13 in.)
82
- #15 = Quarto paper (215 mm by 275 mm)
82
+ #15 = Quarto paper (215 mm by 275 mm)
83
83
  #16 = Standard paper (10 in. by 14 in.)
84
84
  #17 = Standard paper (11 in. by 17 in.)
85
85
  #18 = Note paper (8.5 in. by 11 in.)
86
- #19 = #9 envelope (3.875 in. by 8.875 in.)
87
- #20 = #10 envelope (4.125 in. by 9.5 in.)
88
- #21 = #11 envelope (4.5 in. by 10.375 in.)
86
+ #19 = #9 envelope (3.875 in. by 8.875 in.)
87
+ #20 = #10 envelope (4.125 in. by 9.5 in.)
88
+ #21 = #11 envelope (4.5 in. by 10.375 in.)
89
89
  #22 = #12 envelope (4.75 in. by 11 in.)
90
90
  #23 = #14 envelope (5 in. by 11.5 in.) 24 = C paper (17 in. by 22 in.)
91
91
  #25 = D paper (22 in. by 34 in.)
@@ -105,7 +105,7 @@ module Axlsx
105
105
  #40 = German standard fanfold (8.5 in. by 12 in.)
106
106
  #41 = German legal fanfold (8.5 in. by 13 in.)
107
107
  #42 = ISO B4 (250 mm by 353 mm)
108
- #43 = Japanese double postcard (200 mm by 148 mm)
108
+ #43 = Japanese double postcard (200 mm by 148 mm)
109
109
  #44 = Standard paper (9 in. by 11 in.)
110
110
  #45 = Standard paper (10 in. by 11 in.)
111
111
  #46 = Standard paper (15 in. by 11 in.)
@@ -116,9 +116,9 @@ module Axlsx
116
116
  #53 = A4 extra paper (236 mm by 322 mm)
117
117
  #54 = Letter transverse paper (8.275 in. by 11 in.)
118
118
  #55 = A4 transverse paper (210 mm by 297 mm)
119
- #56 = Letter extra transverse paper (9.275 in. by 12 in.)
120
- #57 = SuperA/SuperA/A4 paper (227 mm by 356 mm)
121
- #58 = SuperB/SuperB/A3 paper (305 mm by 487 mm)
119
+ #56 = Letter extra transverse paper (9.275 in. by 12 in.)
120
+ #57 = SuperA/SuperA/A4 paper (227 mm by 356 mm)
121
+ #58 = SuperB/SuperB/A3 paper (305 mm by 487 mm)
122
122
  #59 = Letter plus paper (8.5 in. by 12.69 in.)
123
123
  #60 = A4 plus paper (210 mm by 330 mm)
124
124
  #61 = A5 transverse paper (148 mm by 210 mm)
@@ -128,8 +128,8 @@ module Axlsx
128
128
  #65 = ISO B5 extra paper (201 mm by 276 mm)
129
129
  #66 = A2 paper (420 mm by 594 mm)
130
130
  #67 = A3 transverse paper (297 mm by 420 mm)
131
- #68 = A3 extra transverse paper (322 mm by 445 mm)
132
- #69 = Japanese Double Postcard (200 mm x 148 mm)
131
+ #68 = A3 extra transverse paper (322 mm by 445 mm)
132
+ #69 = Japanese Double Postcard (200 mm x 148 mm)
133
133
  #70 = A6 (105 mm x 148 mm
134
134
  #71 = Japanese Envelope Kaku #2
135
135
  #72 = Japanese Envelope Kaku #3
@@ -142,7 +142,7 @@ module Axlsx
142
142
  #79 = B4 (JIS) Rotated (364 mm x 257 mm)
143
143
  #80 = B5 (JIS) Rotated (257 mm x 182 mm)
144
144
  #81 = Japanese Postcard Rotated (148 mm x 100 mm)
145
- #82 = Double Japanese Postcard Rotated (148 mm x 200 mm)
145
+ #82 = Double Japanese Postcard Rotated (148 mm x 200 mm)
146
146
  #83 = A6 Rotated (148 mm x 105 mm)
147
147
  #84 = Japanese Envelope Kaku #2 Rotated
148
148
  #85 = Japanese Envelope Kaku #3 Rotated
@@ -210,20 +210,20 @@ module Axlsx
210
210
  # @see scale
211
211
  def scale=(v); Axlsx::validate_scale_10_400(v); @scale = v; end
212
212
 
213
- # convenience method to achieve sanity when setting fit_to_width and fit_to_height
213
+ # convenience method to achieve sanity when setting fit_to_width and fit_to_height
214
214
  # as they both default to 1 if only their counterpart is specified.
215
215
  # @note This method will overwrite any value you explicitly set via the fit_to_height or fit_to_width methods.
216
- # @option options [Integer] width The number of pages to fit this worksheet on horizontally. Default 9999
217
- # @option options [Integer] height The number of pages to fit this worksheet on vertically. Default 9999
216
+ # @option options [Integer] width The number of pages to fit this worksheet on horizontally. Default 999
217
+ # @option options [Integer] height The number of pages to fit this worksheet on vertically. Default 999
218
218
  def fit_to(options={})
219
- self.fit_to_width = options[:width] || 9999
220
- self.fit_to_height = options[:height] || 9999
219
+ self.fit_to_width = options[:width] || 999
220
+ self.fit_to_height = options[:height] || 999
221
221
  [@fit_to_width, @fit_to_height]
222
222
  end
223
223
 
224
224
 
225
225
  # helper method for worksheet to determine if the page setup is configured for fit to page printing
226
- # We treat any page set up that has a value set for fit_to_width or fit_to_height value as fit_to_page.
226
+ # We treat any page set up that has a value set for fit_to_width or fit_to_height value as fit_to_page.
227
227
  # @return [Boolean]
228
228
  def fit_to_page?
229
229
  # is there some better what to express this?
@@ -234,9 +234,7 @@ module Axlsx
234
234
  # @param [String] str
235
235
  # @return [String]
236
236
  def to_xml_string(str = '')
237
- str << '<pageSetup '
238
- serialized_attributes str
239
- str << '/>'
237
+ serialized_tag('pageSetup', str)
240
238
  end
241
239
  end
242
240
  end
@@ -124,9 +124,7 @@ module Axlsx
124
124
  # @return [String]
125
125
  def to_xml_string(str = '')
126
126
  finalize
127
- str << '<pane '
128
- serialized_attributes str
129
- str << '/>'
127
+ serialized_tag 'pane', str
130
128
  end
131
129
  private
132
130
 
@@ -25,10 +25,20 @@ module Axlsx
25
25
  @data = []
26
26
  @pages = []
27
27
  @subtotal = nil
28
+ @no_subtotals_on_headers = []
29
+ @style_info = {}
28
30
  parse_options options
29
31
  yield self if block_given?
30
32
  end
31
33
 
34
+ # Defines the headers in which subtotals are not to be included
35
+ # @return[Array]
36
+ attr_accessor :no_subtotals_on_headers
37
+
38
+ # Style info for the pivot table
39
+ # @return[Hash]
40
+ attr_accessor :style_info
41
+
32
42
  # The reference to the table data
33
43
  # @return [String]
34
44
  attr_reader :ref
@@ -159,23 +169,23 @@ module Axlsx
159
169
  # @return [String]
160
170
  def to_xml_string(str = '')
161
171
  str << '<?xml version="1.0" encoding="UTF-8"?>'
162
- str << '<pivotTableDefinition xmlns="' << XML_NS << '" name="' << name << '" cacheId="' << cache_definition.cache_id.to_s << '" dataOnRows="1" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data" showMultipleLabel="0" showMemberPropertyTips="0" useAutoFormatting="1" indent="0" compact="0" compactData="0" gridDropZones="1" multipleFieldFilters="0">'
163
- str << '<location firstDataCol="1" firstDataRow="1" firstHeaderRow="1" ref="' << ref << '"/>'
164
- str << '<pivotFields count="' << header_cells_count.to_s << '">'
172
+ str << ('<pivotTableDefinition xmlns="' << XML_NS << '" name="' << name << '" cacheId="' << cache_definition.cache_id.to_s << '" dataOnRows="1" applyNumberFormats="0" applyBorderFormats="0" applyFontFormats="0" applyPatternFormats="0" applyAlignmentFormats="0" applyWidthHeightFormats="1" dataCaption="Data" showMultipleLabel="0" showMemberPropertyTips="0" useAutoFormatting="1" indent="0" compact="0" compactData="0" gridDropZones="1" multipleFieldFilters="0">')
173
+ str << ('<location firstDataCol="1" firstDataRow="1" firstHeaderRow="1" ref="' << ref << '"/>')
174
+ str << ('<pivotFields count="' << header_cells_count.to_s << '">')
165
175
  header_cell_values.each do |cell_value|
166
- str << pivot_field_for(cell_value)
176
+ str << pivot_field_for(cell_value, !no_subtotals_on_headers.include?(cell_value))
167
177
  end
168
- str << '</pivotFields>'
178
+ str << '</pivotFields>'
169
179
  if rows.empty?
170
180
  str << '<rowFields count="1"><field x="-2"/></rowFields>'
171
181
  str << '<rowItems count="2"><i><x/></i> <i i="1"><x v="1"/></i></rowItems>'
172
182
  else
173
- str << '<rowFields count="' << rows.size.to_s << '">'
183
+ str << ('<rowFields count="' << rows.size.to_s << '">')
174
184
  rows.each do |row_value|
175
- str << '<field x="' << header_index_of(row_value).to_s << '"/>'
185
+ str << ('<field x="' << header_index_of(row_value).to_s << '"/>')
176
186
  end
177
187
  str << '</rowFields>'
178
- str << '<rowItems count="' << rows.size.to_s << '">'
188
+ str << ('<rowItems count="' << rows.size.to_s << '">')
179
189
  rows.size.times do |i|
180
190
  str << '<i/>'
181
191
  end
@@ -184,28 +194,37 @@ module Axlsx
184
194
  if columns.empty?
185
195
  str << '<colItems count="1"><i/></colItems>'
186
196
  else
187
- str << '<colFields count="' << columns.size.to_s << '">'
197
+ str << ('<colFields count="' << columns.size.to_s << '">')
188
198
  columns.each do |column_value|
189
- str << '<field x="' << header_index_of(column_value).to_s << '"/>'
199
+ str << ('<field x="' << header_index_of(column_value).to_s << '"/>')
190
200
  end
191
201
  str << '</colFields>'
192
202
  end
193
203
  unless pages.empty?
194
- str << '<pageFields count="' << pages.size.to_s << '">'
204
+ str << ('<pageFields count="' << pages.size.to_s << '">')
195
205
  pages.each do |page_value|
196
- str << '<pageField fld="' << header_index_of(page_value).to_s << '"/>'
206
+ str << ('<pageField fld="' << header_index_of(page_value).to_s << '"/>')
197
207
  end
198
208
  str << '</pageFields>'
199
209
  end
200
210
  unless data.empty?
201
211
  str << "<dataFields count=\"#{data.size}\">"
202
212
  data.each do |datum_value|
203
- str << "<dataField name='#{@subtotal} of #{datum_value[:ref]}' fld='#{header_index_of(datum_value[:ref])}' baseField='0' baseItem='0'"
213
+ # The correct name prefix in ["Sum","Average", etc...]
214
+ str << "<dataField name='#{(datum_value[:subtotal]||'')} of #{datum_value[:ref]}' fld='#{header_index_of(datum_value[:ref])}' baseField='0' baseItem='0'"
204
215
  str << " subtotal='#{datum_value[:subtotal]}' " if datum_value[:subtotal]
205
216
  str << "/>"
206
217
  end
207
218
  str << '</dataFields>'
208
219
  end
220
+ # custom pivot table style
221
+ unless style_info.empty?
222
+ str << '<pivotTableStyleInfo'
223
+ style_info.each do |k,v|
224
+ str << ' ' << k.to_s << '="' << v.to_s << '"'
225
+ end
226
+ str << ' />'
227
+ end
209
228
  str << '</pivotTableDefinition>'
210
229
  end
211
230
 
@@ -241,33 +260,30 @@ module Axlsx
241
260
 
242
261
  private
243
262
 
244
- def pivot_field_for(cell_ref)
263
+ def pivot_field_for(cell_ref, subtotal=true)
245
264
  if rows.include? cell_ref
246
- '<pivotField axis="axisRow" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' <<
247
- '<items count="1"><item t="default"/></items>' <<
248
- '</pivotField>'
265
+ if subtotal
266
+ '<pivotField axis="axisRow" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"><items count="1"><item t="default"/></items></pivotField>'
267
+ else
268
+ '<pivotField axis="axisRow" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1" defaultSubtotal="0"></pivotField>'
269
+ end
249
270
  elsif columns.include? cell_ref
250
- '<pivotField axis="axisCol" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' <<
251
- '<items count="1"><item t="default"/></items>' <<
252
- '</pivotField>'
271
+ '<pivotField axis="axisCol" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"><items count="1"><item t="default"/></items></pivotField>'
253
272
  elsif pages.include? cell_ref
254
- '<pivotField axis="axisCol" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' <<
255
- '<items count="1"><item t="default"/></items>' <<
256
- '</pivotField>'
273
+ '<pivotField axis="axisPage" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"><items count="1"><item t="default"/></items></pivotField>'
257
274
  elsif data_refs.include? cell_ref
258
- '<pivotField dataField="1" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' <<
259
- '</pivotField>'
275
+ '<pivotField dataField="1" compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"></pivotField>'
260
276
  else
261
- '<pivotField compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1">' <<
262
- '</pivotField>'
277
+ '<pivotField compact="0" outline="0" subtotalTop="0" showAll="0" includeNewItemsInFilter="1"></pivotField>'
263
278
  end
264
279
  end
280
+
265
281
  def data_refs
266
282
  data.map { |hash| hash[:ref] }
267
283
  end
284
+
268
285
  def header_range
269
286
  range.gsub(/^(\w+?)(\d+)\:(\w+?)\d+$/, '\1\2:\3\2')
270
287
  end
271
-
272
288
  end
273
289
  end
@@ -47,13 +47,13 @@ module Axlsx
47
47
  # @return [String]
48
48
  def to_xml_string(str = '')
49
49
  str << '<?xml version="1.0" encoding="UTF-8"?>'
50
- str << '<pivotCacheDefinition xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '" invalid="1" refreshOnLoad="1" recordCount="0">'
50
+ str << ('<pivotCacheDefinition xmlns="' << XML_NS << '" xmlns:r="' << XML_NS_R << '" invalid="1" refreshOnLoad="1" recordCount="0">')
51
51
  str << '<cacheSource type="worksheet">'
52
- str << '<worksheetSource ref="' << pivot_table.range << '" sheet="' << pivot_table.data_sheet.name << '"/>'
52
+ str << ( '<worksheetSource ref="' << pivot_table.range << '" sheet="' << pivot_table.data_sheet.name << '"/>')
53
53
  str << '</cacheSource>'
54
- str << '<cacheFields count="' << pivot_table.header_cells_count.to_s << '">'
54
+ str << ( '<cacheFields count="' << pivot_table.header_cells_count.to_s << '">')
55
55
  pivot_table.header_cells.each do |cell|
56
- str << '<cacheField name="' << cell.value << '" numFmtId="0">'
56
+ str << ( '<cacheField name="' << cell.value << '" numFmtId="0">')
57
57
  str << '<sharedItems count="0">'
58
58
  str << '</sharedItems>'
59
59
  str << '</cacheField>'
@@ -33,9 +33,7 @@ module Axlsx
33
33
  # @param [String] str
34
34
  # @return [String]
35
35
  def to_xml_string(str = '')
36
- str << '<printOptions '
37
- serialized_attributes str
38
- str << '/>'
36
+ serialized_tag 'printOptions', str
39
37
  end
40
38
  end
41
39
  end
@@ -41,9 +41,7 @@ module Axlsx
41
41
  # our output to that object. Use this - it helps limit the number of
42
42
  # objects created during serialization
43
43
  def to_xml_string(str="")
44
- str << '<protectedRange '
45
- serialized_attributes str
46
- str << '/>'
44
+ serialized_tag 'protectedRange', str
47
45
  end
48
46
  end
49
47
  end