axlsx 1.0.15 → 1.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (176) hide show
  1. data/.yardopts +1 -0
  2. data/CHANGELOG.md +40 -2
  3. data/README.md +223 -92
  4. data/examples/example.csv +1000 -0
  5. data/examples/example.rb +266 -132
  6. data/examples/example.xlsx +0 -0
  7. data/examples/example_streamed.xlsx +0 -0
  8. data/examples/no-use_autowidth.xlsx +0 -0
  9. data/examples/shared_strings_example.xlsx +0 -0
  10. data/lib/axlsx/content_type/content_type.rb +13 -12
  11. data/lib/axlsx/content_type/default.rb +10 -6
  12. data/lib/axlsx/content_type/override.rb +13 -8
  13. data/lib/axlsx/doc_props/app.rb +38 -41
  14. data/lib/axlsx/doc_props/core.rb +13 -17
  15. data/lib/axlsx/drawing/axis.rb +39 -19
  16. data/lib/axlsx/drawing/bar_3D_chart.rb +34 -32
  17. data/lib/axlsx/drawing/bar_series.rb +14 -14
  18. data/lib/axlsx/drawing/cat_axis.rb +16 -14
  19. data/lib/axlsx/drawing/cat_axis_data.rb +17 -18
  20. data/lib/axlsx/drawing/chart.rb +40 -41
  21. data/lib/axlsx/drawing/drawing.rb +27 -12
  22. data/lib/axlsx/drawing/graphic_frame.rb +22 -21
  23. data/lib/axlsx/drawing/hlink_click.rb~ +0 -0
  24. data/lib/axlsx/drawing/hyperlink.rb +96 -0
  25. data/lib/axlsx/drawing/hyperlink.rb~ +64 -0
  26. data/lib/axlsx/drawing/line_3D_chart.rb +31 -28
  27. data/lib/axlsx/drawing/line_series.rb +12 -11
  28. data/lib/axlsx/drawing/marker.rb +11 -8
  29. data/lib/axlsx/drawing/named_axis_data.rb +36 -0
  30. data/lib/axlsx/drawing/one_cell_anchor.rb +18 -16
  31. data/lib/axlsx/drawing/pic.rb +47 -33
  32. data/lib/axlsx/drawing/picture_locking.rb +22 -18
  33. data/lib/axlsx/drawing/pie_3D_chart.rb +11 -8
  34. data/lib/axlsx/drawing/pie_series.rb +16 -12
  35. data/lib/axlsx/drawing/scaling.rb +11 -10
  36. data/lib/axlsx/drawing/scatter_chart.rb +69 -0
  37. data/lib/axlsx/drawing/scatter_series.rb +39 -0
  38. data/lib/axlsx/drawing/ser_axis.rb +11 -10
  39. data/lib/axlsx/drawing/series.rb +16 -15
  40. data/lib/axlsx/drawing/series_title.rb +15 -14
  41. data/lib/axlsx/drawing/title.rb +27 -26
  42. data/lib/axlsx/drawing/two_cell_anchor.rb +19 -20
  43. data/lib/axlsx/drawing/val_axis.rb +9 -7
  44. data/lib/axlsx/drawing/val_axis_data.rb +18 -17
  45. data/lib/axlsx/drawing/view_3D.rb +23 -20
  46. data/lib/axlsx/package.rb +117 -52
  47. data/lib/axlsx/rels/relationship.rb +27 -8
  48. data/lib/axlsx/rels/relationships.rb +9 -2
  49. data/lib/axlsx/stylesheet/#num_fmt.rb# +69 -0
  50. data/lib/axlsx/stylesheet/border.rb +28 -23
  51. data/lib/axlsx/stylesheet/border_pr.rb +17 -15
  52. data/lib/axlsx/stylesheet/cell_alignment.rb +24 -21
  53. data/lib/axlsx/stylesheet/cell_protection.rb +11 -7
  54. data/lib/axlsx/stylesheet/cell_style.rb +9 -5
  55. data/lib/axlsx/stylesheet/color.rb +21 -14
  56. data/lib/axlsx/stylesheet/fill.rb +8 -5
  57. data/lib/axlsx/stylesheet/font.rb +22 -14
  58. data/lib/axlsx/stylesheet/gradient_fill.rb +20 -17
  59. data/lib/axlsx/stylesheet/gradient_stop.rb +10 -6
  60. data/lib/axlsx/stylesheet/num_fmt.rb +13 -6
  61. data/lib/axlsx/stylesheet/pattern_fill.rb +26 -10
  62. data/lib/axlsx/stylesheet/styles.rb +53 -41
  63. data/lib/axlsx/stylesheet/table_style.rb +10 -4
  64. data/lib/axlsx/stylesheet/table_style_element.rb +11 -7
  65. data/lib/axlsx/stylesheet/table_styles.rb +12 -8
  66. data/lib/axlsx/stylesheet/xf.rb +30 -25
  67. data/lib/axlsx/util/cbf.rb +69 -33
  68. data/lib/axlsx/util/constants.rb +39 -20
  69. data/lib/axlsx/util/ms_off_crypto.rb +10 -10
  70. data/lib/axlsx/util/parser.rb +1 -0
  71. data/lib/axlsx/util/simple_typed_list.rb +20 -10
  72. data/lib/axlsx/util/storage.rb +1 -1
  73. data/lib/axlsx/util/validators.rb +23 -7
  74. data/lib/axlsx/version.rb +5 -2
  75. data/lib/axlsx/workbook/shared_strings_table.rb +69 -0
  76. data/lib/axlsx/workbook/shared_strings_table.rb~ +69 -0
  77. data/lib/axlsx/workbook/workbook.rb +82 -26
  78. data/lib/axlsx/workbook/worksheet/cell.rb +172 -117
  79. data/lib/axlsx/workbook/worksheet/col.rb +114 -0
  80. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  81. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +29 -0
  82. data/lib/axlsx/workbook/worksheet/page_margins.rb +97 -0
  83. data/lib/axlsx/workbook/worksheet/row.rb +53 -21
  84. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  85. data/lib/axlsx/workbook/worksheet/table.rb +96 -0
  86. data/lib/axlsx/workbook/worksheet/table.rb~ +97 -0
  87. data/lib/axlsx/workbook/worksheet/worksheet.rb +270 -121
  88. data/lib/axlsx.rb +41 -14
  89. data/lib/schema/dc.xsd +5 -5
  90. data/lib/schema/dcmitype.xsd +5 -3
  91. data/lib/schema/dcterms.xsd +15 -15
  92. data/lib/schema/opc-coreProperties.xsd +6 -2
  93. data/lib/schema/xml.xsd +7 -8
  94. data/test/#benchmark.txt# +7 -0
  95. data/test/#tc_helper.rb# +3 -0
  96. data/test/benchmark.rb +81 -0
  97. data/test/benchmark.rb~ +0 -0
  98. data/test/benchmark.txt +6 -0
  99. data/test/benchmark.txt~ +6 -0
  100. data/test/content_type/tc_content_type.rb +31 -31
  101. data/test/content_type/tc_default.rb +9 -22
  102. data/test/content_type/tc_override.rb +8 -21
  103. data/test/doc_props/tc_app.rb +2 -8
  104. data/test/doc_props/tc_core.rb +6 -7
  105. data/test/drawing/tc_axis.rb +7 -3
  106. data/test/drawing/tc_bar_3D_chart.rb +6 -7
  107. data/test/drawing/tc_bar_series.rb +4 -5
  108. data/test/drawing/tc_cat_axis.rb +2 -3
  109. data/test/drawing/tc_cat_axis_data.rb +2 -3
  110. data/test/drawing/tc_chart.rb +13 -14
  111. data/test/drawing/tc_drawing.rb +7 -8
  112. data/test/drawing/tc_graphic_frame.rb +3 -4
  113. data/test/drawing/tc_hyperlink.rb +69 -0
  114. data/test/drawing/tc_line_3d_chart.rb +5 -6
  115. data/test/drawing/tc_line_series.rb +3 -4
  116. data/test/drawing/tc_marker.rb +3 -4
  117. data/test/drawing/tc_one_cell_anchor.rb +6 -7
  118. data/test/drawing/tc_pic.rb +13 -8
  119. data/test/drawing/tc_picture_locking.rb +2 -3
  120. data/test/drawing/tc_pie_3D_chart.rb +5 -6
  121. data/test/drawing/tc_pie_series.rb +4 -5
  122. data/test/drawing/tc_scaling.rb +3 -4
  123. data/test/drawing/tc_scatter_chart.rb +43 -0
  124. data/test/drawing/tc_scatter_series.rb +20 -0
  125. data/test/drawing/tc_ser_axis.rb +2 -3
  126. data/test/drawing/tc_series.rb +4 -5
  127. data/test/drawing/tc_series_title.rb +4 -5
  128. data/test/drawing/tc_title.rb +4 -5
  129. data/test/drawing/tc_two_cell_anchor.rb +4 -5
  130. data/test/drawing/tc_val_axis.rb +2 -3
  131. data/test/drawing/tc_val_axis_data.rb +2 -3
  132. data/test/drawing/tc_view_3D.rb +6 -7
  133. data/test/example.csv +1000 -0
  134. data/test/example.xlsx +0 -0
  135. data/test/example_streamed.xlsx +0 -0
  136. data/test/profile.rb +33 -0
  137. data/test/rels/tc_relationship.rb +10 -6
  138. data/test/rels/tc_relationships.rb +4 -5
  139. data/test/stylesheet/tc_border.rb +3 -4
  140. data/test/stylesheet/tc_border_pr.rb +3 -4
  141. data/test/stylesheet/tc_cell_alignment.rb +10 -6
  142. data/test/stylesheet/tc_cell_protection.rb +2 -3
  143. data/test/stylesheet/tc_cell_style.rb +2 -3
  144. data/test/stylesheet/tc_color.rb +2 -3
  145. data/test/stylesheet/tc_fill.rb +1 -2
  146. data/test/stylesheet/tc_font.rb +12 -5
  147. data/test/stylesheet/tc_gradient_fill.rb +1 -2
  148. data/test/stylesheet/tc_gradient_stop.rb +1 -2
  149. data/test/stylesheet/tc_num_fmt.rb +1 -2
  150. data/test/stylesheet/tc_pattern_fill.rb +3 -4
  151. data/test/stylesheet/tc_styles.rb +16 -6
  152. data/test/stylesheet/tc_table_style.rb +2 -3
  153. data/test/stylesheet/tc_table_style_element.rb +2 -3
  154. data/test/stylesheet/tc_table_styles.rb +3 -4
  155. data/test/stylesheet/tc_xf.rb +16 -17
  156. data/test/tc_axlsx.rb +39 -0
  157. data/test/tc_axlsx.rb~ +0 -0
  158. data/test/tc_helper.rb +3 -0
  159. data/test/tc_helper.rb~ +3 -0
  160. data/test/tc_package.rb +43 -9
  161. data/test/util/tc_simple_typed_list.rb +8 -9
  162. data/test/util/tc_validators.rb +7 -8
  163. data/test/workbook/tc_shared_strings_table.rb +38 -0
  164. data/test/workbook/tc_workbook.rb +32 -6
  165. data/test/workbook/worksheet/table/tc_table.rb +71 -0
  166. data/test/workbook/worksheet/table/tc_table.rb~ +72 -0
  167. data/test/workbook/worksheet/tc_cell.rb +70 -13
  168. data/test/workbook/worksheet/tc_col.rb +59 -0
  169. data/test/workbook/worksheet/tc_col.rb~ +10 -0
  170. data/test/workbook/worksheet/tc_date_time_converter.rb +126 -0
  171. data/test/workbook/worksheet/tc_page_margins.rb +97 -0
  172. data/test/workbook/worksheet/tc_row.rb +54 -4
  173. data/test/workbook/worksheet/tc_worksheet.rb +198 -31
  174. metadata +167 -111
  175. data/test/drawing/tc_line_series.tc~ +0 -34
  176. data/test/drawing/tc_picture_locking.rb~ +0 -77
@@ -1,22 +1,23 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # A series title is a Title with a slightly different serialization than chart titles.
3
4
  class SeriesTitle < Title
4
5
 
5
- # Serializes the series title
6
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
6
+ # Serializes the object
7
+ # @param [String] str
7
8
  # @return [String]
8
- def to_xml(xml)
9
- xml[:c].tx {
10
- xml[:c].strRef {
11
- xml[:c].f Axlsx::cell_range([@cell])
12
- xml[:c].strCache {
13
- xml[:c].ptCount :val=>1
14
- xml[:c].pt(:idx=>0) {
15
- xml[:c].v @text
16
- }
17
- }
18
- }
19
- }
9
+ def to_xml_string(str = '')
10
+ str << '<c:tx>'
11
+ str << '<c:strRef>'
12
+ str << '<c:f>' << Axlsx::cell_range([@cell]) << '</c:f>'
13
+ str << '<c:strCache>'
14
+ str << '<c:ptCount val="1"/>'
15
+ str << '<c:pt idx="0">'
16
+ str << '<c:v>' << @text << '</c:v>'
17
+ str << '</c:pt>'
18
+ str << '</c:strCache>'
19
+ str << '</c:strRef>'
20
+ str << '</c:tx>'
20
21
  end
21
22
  end
22
23
  end
@@ -1,7 +1,8 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # A Title stores information about the title of a chart
3
4
  class Title
4
-
5
+
5
6
  # The text to be shown. Setting this property directly with a string will remove the cell reference.
6
7
  # @return [String]
7
8
  attr_reader :text
@@ -16,9 +17,9 @@ module Axlsx
16
17
  self.cell = title if title.is_a?(Cell)
17
18
  self.text = title.to_s unless title.is_a?(Cell)
18
19
  end
19
-
20
+
20
21
  # @see text
21
- def text=(v)
22
+ def text=(v)
22
23
  DataTypeValidator.validate 'Title.text', String, v
23
24
  @text = v
24
25
  @cell = nil
@@ -29,7 +30,7 @@ module Axlsx
29
30
  def cell=(v)
30
31
  DataTypeValidator.validate 'Title.text', Cell, v
31
32
  @cell = v
32
- @text = v.value.to_s
33
+ @text = v.value.to_s
33
34
  v
34
35
  end
35
36
 
@@ -37,29 +38,29 @@ module Axlsx
37
38
  #def layout=(v) DataTypeValidator.validate 'Title.layout', Layout, v; @layout = v; end
38
39
  #def overlay=(v) Axlsx::validate_boolean v; @overlay=v; end
39
40
  #def spPr=(v) DataTypeValidator.validate 'Title.spPr', SpPr, v; @spPr = v; end
40
-
41
- # Serializes the chart title
42
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
41
+
42
+ # Serializes the object
43
+ # @param [String] str
43
44
  # @return [String]
44
- def to_xml(xml)
45
- xml[:c].title {
46
- unless @text.empty?
47
- xml[:c].tx {
48
- xml[:c].strRef {
49
- xml[:c].f Axlsx::cell_range([@cell])
50
- xml[:c].strCache {
51
- xml[:c].ptCount :val=>1
52
- xml[:c].pt(:idx=>0) {
53
- xml[:c].v @text
54
- }
55
- }
56
- }
57
- }
58
- end
59
- xml[:c].layout
60
- xml[:c].overlay :val=>0
61
- }
45
+ def to_xml_string(str = '')
46
+ str << '<c:title>'
47
+ unless @text.empty?
48
+ str << '<c:tx>'
49
+ str << '<c:strRef>'
50
+ str << '<c:f>' << Axlsx::cell_range([@cell]) << '</c:f>'
51
+ str << '<c:strCache>'
52
+ str << '<c:ptCount val="1"/>'
53
+ str << '<c:pt idx="0">'
54
+ str << '<c:v>' << @text << '</c:v>'
55
+ str << '</c:pt>'
56
+ str << '</c:strCache>'
57
+ str << '</c:strRef>'
58
+ str << '</c:tx>'
59
+ end
60
+ str << '<c:layout/>'
61
+ str << '<c:overlay val="0"/>'
62
+ str << '</c:title>'
62
63
  end
63
-
64
+
64
65
  end
65
66
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # This class details the anchor points for drawings.
3
4
  # @note The recommended way to manage drawings and charts is Worksheet#add_chart. Anchors are specified by the :start_at and :end_at options to that method.
@@ -25,7 +26,7 @@ module Axlsx
25
26
  attr_reader :drawing
26
27
 
27
28
 
28
- # Creates a new TwoCellAnchor object and sets up a reference to the from and to markers in the
29
+ # Creates a new TwoCellAnchor object and sets up a reference to the from and to markers in the
29
30
  # graphic_frame's chart. That means that you can do stuff like
30
31
  # c = worksheet.add_chart Axlsx::Chart
31
32
  # c.start_at 5, 9
@@ -37,13 +38,13 @@ module Axlsx
37
38
  # @option options [Array] end_at the col, row to end at
38
39
  def initialize(drawing, options={})
39
40
  @drawing = drawing
40
- drawing.anchors << self
41
+ drawing.anchors << self
41
42
  @from, @to = Marker.new, Marker.new(:col => 5, :row=>10)
42
43
  end
43
44
 
44
45
  # Creates a graphic frame and chart object associated with this anchor
45
46
  # @return [Chart]
46
- def add_chart(chart_type, options)
47
+ def add_chart(chart_type, options)
47
48
  @object = GraphicFrame.new(self, chart_type, options)
48
49
  @object.chart
49
50
  end
@@ -53,24 +54,22 @@ module Axlsx
53
54
  def index
54
55
  @drawing.anchors.index(self)
55
56
  end
56
- # Serializes the two cell anchor
57
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
58
- # @return [String]
59
- def to_xml(xml)
60
- #build it for now, break it down later!
61
- xml[:xdr].twoCellAnchor {
62
- xml.from {
63
- from.to_xml(xml)
64
- }
65
- xml.to {
66
- to.to_xml(xml)
67
- }
68
- @object.to_xml(xml)
69
- xml.clientData
70
- }
71
- end
72
57
 
73
- private
58
+ # Serializes the object
59
+ # @param [String] str
60
+ # @return [String]
61
+ def to_xml_string(str = '')
62
+ str << '<xdr:twoCellAnchor>'
63
+ str << '<xdr:from>'
64
+ from.to_xml_string str
65
+ str << '</xdr:from>'
66
+ str << '<xdr:to>'
67
+ to.to_xml_string str
68
+ str << '</xdr:to>'
69
+ object.to_xml_string(str)
70
+ str << '<xdr:clientData/>'
71
+ str << '</xdr:twoCellAnchor>'
72
+ end
74
73
 
75
74
  end
76
75
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # the ValAxis class defines a chart value axis.
3
4
  class ValAxis < Axis
@@ -21,14 +22,15 @@ module Axlsx
21
22
  # @see crossBetween
22
23
  def crossBetween=(v) RestrictionValidator.validate "ValAxis.crossBetween", [:between, :midCat], v; @crossBetween = v; end
23
24
 
24
- # Serializes the value axis
25
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
25
+ # Serializes the object
26
+ # @param [String] str
26
27
  # @return [String]
27
- def to_xml(xml)
28
- xml.valAx {
29
- super(xml)
30
- xml.crossBetween :val=>@crossBetween
31
- }
28
+ def to_xml_string(str = '')
29
+ str << '<c:valAx>'
30
+ super(str)
31
+ str << '<c:crossBetween val="' << @crossBetween.to_s << '"/>'
32
+ str << '</c:valAx>'
32
33
  end
34
+
33
35
  end
34
36
  end
@@ -1,26 +1,27 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # The ValAxisData class manages the values for a chart value series.
3
4
  class ValAxisData < CatAxisData
4
5
 
5
- # Serializes the value axis data
6
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
6
+ # Serializes the object
7
+ # @param [String] str
7
8
  # @return [String]
8
- def to_xml(xml)
9
- xml.val {
10
- xml.numRef {
11
- xml.f Axlsx::cell_range(@list)
12
- xml.numCache {
13
- xml.formatCode 'General'
14
- xml.ptCount :val=>size
15
- each_with_index do |item, index|
16
- v = item.is_a?(Cell) ? item.value : item
17
- xml.pt(:idx=>index) { xml.v v }
18
- end
19
- }
20
- }
21
- }
9
+ def to_xml_string(str = '')
10
+ str << '<c:val>'
11
+ str << '<c:numRef>'
12
+ str << '<c:f>' << Axlsx::cell_range(@list) << '</c:f>'
13
+ str << '<c:numCache>'
14
+ str << '<c:formatCode>General</c:formatCode>'
15
+ str << '<c:ptCount val="' << size.to_s << '"/>'
16
+ each_with_index do |item, index|
17
+ v = item.is_a?(Cell) ? item.value.to_s : item
18
+ str << '<c:pt idx="' << index.to_s << '"><c:v>' << v << '</c:v></c:pt>'
19
+ end
20
+ str << '</c:numCache>'
21
+ str << '</c:numRef>'
22
+ str << '</c:val>'
22
23
  end
23
24
 
24
25
  end
25
-
26
+
26
27
  end
@@ -1,37 +1,38 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # 3D attributes for a chart.
3
4
  class View3D
4
5
 
5
6
  # Validation for hPercent
6
7
  H_PERCENT_REGEX = /0*(([5-9])|([1-9][0-9])|([1-4][0-9][0-9])|500)%/
7
-
8
+
8
9
  # validation for depthPercent
9
10
  DEPTH_PERCENT_REGEX = /0*(([2-9][0-9])|([1-9][0-9][0-9])|(1[0-9][0-9][0-9])|2000)%/
10
11
 
11
- # x rotation for the chart
12
+ # x rotation for the chart
12
13
  # must be between -90 and 90
13
14
  # @return [Integer]
14
15
  attr_reader :rotX
15
-
16
+
16
17
  # height of chart as % of chart
17
18
  # must be between 5% and 500%
18
19
  # @return [String]
19
20
  attr_reader :hPercent
20
-
21
+
21
22
  # y rotation for the chart
22
23
  # must be between 0 and 360
23
24
  # @return [Integer]
24
25
  attr_reader :rotY
25
-
26
+
26
27
  # depth or chart as % of chart width
27
28
  # must be between 20% and 2000%
28
29
  # @return [String]
29
30
  attr_reader :depthPercent
30
-
31
+
31
32
  # Chart axis are at right angles
32
33
  # @return [Boolean]
33
34
  attr_reader :rAngAx
34
-
35
+
35
36
  # field of view angle
36
37
  # @return [Integer]
37
38
  attr_reader :perspective
@@ -44,10 +45,10 @@ module Axlsx
44
45
  # @option options [Boolean] rAngAx
45
46
  # @option options [Integer] perspective
46
47
  def initialize(options={})
47
- @rotX, @hPercent, @rotY, @depthPercent, @rAngAx, @perspective = nil, nil, nil, nil, nil, nil
48
+ @rotX, @hPercent, @rotY, @depthPercent, @rAngAx, @perspective = nil, nil, nil, nil, nil, nil
48
49
  options.each do |o|
49
50
  self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
50
- end
51
+ end
51
52
  end
52
53
 
53
54
  # @see rotX
@@ -68,18 +69,20 @@ module Axlsx
68
69
  # @see perspective
69
70
  def perspective=(v) DataTypeValidator.validate "#{self.class}.perspective", [Integer, Fixnum], v, lambda {|arg| arg >= 0 && arg <= 240 }; @perspective = v; end
70
71
 
71
- # Serializes the view3D properties
72
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
72
+
73
+ # Serializes the object
74
+ # @param [String] str
73
75
  # @return [String]
74
- def to_xml(xml)
75
- xml[:c].view3D {
76
- xml[:c].rotX :val=>@rotX unless @rotX.nil?
77
- xml[:c].hPercent :val=>@hPercent unless @hPercent.nil?
78
- xml[:c].rotY :val=>@rotY unless @rotY.nil?
79
- xml[:c].depthPercent :val=>@depthPercent unless @depthPercent.nil?
80
- xml[:c].rAngAx :val=>@rAngAx unless @rAngAx.nil?
81
- xml[:c].perspective :val=>@perspective unless @perspective.nil?
82
- }
76
+ def to_xml_string(str = '')
77
+ str << '<c:view3D>'
78
+ str << '<c:rotX val="' << @rotX.to_s << '"/>' unless @rotX.nil?
79
+ str << '<c:hPercent val="' << @hPercent.to_s << '"/>' unless @hPercent.nil?
80
+ str << '<c:rotY val="' << @rotY.to_s << '"/>' unless @rotY.nil?
81
+ str << '<c:depthPercent val="' << @depthPercent.to_s << '"/>' unless @depthPercent.nil?
82
+ str << '<c:rAngAx val="' << @rAngAx.to_s << '"/>' unless @rAngAx.nil?
83
+ str << '<c:perspective val="' << @perspective.to_s << '"/>' unless @perspective.nil?
84
+ str << '</c:view3D>'
83
85
  end
86
+
84
87
  end
85
88
  end
data/lib/axlsx/package.rb CHANGED
@@ -1,10 +1,10 @@
1
- # -*- coding: utf-8 -*-
1
+ # encoding: UTF-8
2
2
  module Axlsx
3
3
  # Package is responsible for managing all the bits and peices that Open Office XML requires to make a valid
4
4
  # xlsx document including valdation and serialization.
5
5
  class Package
6
6
 
7
- # plain text password
7
+
8
8
  # provides access to the app doc properties for this package
9
9
  # see App
10
10
  attr_reader :app
@@ -17,18 +17,43 @@ module Axlsx
17
17
  #
18
18
  # @param [Hash] options A hash that you can use to specify the author and workbook for this package.
19
19
  # @option options [String] :author The author of the document
20
+ # @option options [Boolean] :use_shared_strings This is passed to the workbook to specify that shared strings should be used when serializing the package.
20
21
  # @example Package.new :author => 'you!', :workbook => Workbook.new
21
22
  def initialize(options={})
22
23
  @workbook = nil
23
24
  @core, @app = Core.new, App.new
24
25
  @core.creator = options[:author] || @core.creator
26
+ options.each do |o|
27
+ self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
28
+ end
25
29
  yield self if block_given?
26
30
  end
27
31
 
32
+ # Shortcut to specify that the workbook should use autowidth
33
+ # @see Workbook#use_autowidth
34
+ def use_autowidth=(v)
35
+ Axlsx::validate_boolean(v);
36
+ workbook.use_autowidth = v
37
+ end
38
+
39
+
40
+ # Shortcut to specify that the workbook should use shared strings
41
+ # @see Workbook#use_shared_strings
42
+ def use_shared_strings=(v)
43
+ Axlsx::validate_boolean(v);
44
+ workbook.use_shared_strings = v
45
+ end
46
+
47
+ # Shortcut to determine if the workbook is configured to use shared strings
48
+ # @see Workbook#use_shared_strings
49
+ def use_shared_strings
50
+ workbook.use_shared_strings
51
+ end
52
+
28
53
  # The workbook this package will serialize or validate.
29
54
  # @return [Workbook] If no workbook instance has been assigned with this package a new Workbook instance is returned.
30
55
  # @raise ArgumentError if workbook parameter is not a Workbook instance.
31
- # @note As there are multiple ways to instantiate a workbook for the package,
56
+ # @note As there are multiple ways to instantiate a workbook for the package,
32
57
  # here are a few examples:
33
58
  # # assign directly during package instanciation
34
59
  # wb = Package.new(:workbook => Workbook.new).workbook
@@ -42,13 +67,13 @@ module Axlsx
42
67
  yield @workbook if block_given?
43
68
  @workbook
44
69
  end
45
-
70
+
46
71
  #def self.parse(input, confirm_valid = false)
47
72
  # p = Package.new
48
73
  # z = Zip::ZipFile.open(input)
49
74
  # p.workbook = Workbook.parse z.get_entry(WORKBOOK_PN)
50
75
  # p
51
- #end
76
+ #end
52
77
 
53
78
  # @see workbook
54
79
  def workbook=(workbook) DataTypeValidator.validate "Package.workbook", Workbook, workbook; @workbook = workbook; end
@@ -57,9 +82,10 @@ module Axlsx
57
82
  #
58
83
  # @param [File] output The file you want to serialize your package to
59
84
  # @param [Boolean] confirm_valid Validate the package prior to serialization.
85
+ # @option options stream indicates if we should be writing to a stream or a file. True for stream, nil for file
60
86
  # @return [Boolean] False if confirm_valid and validation errors exist. True if the package was serialized
61
87
  # @note A tremendous amount of effort has gone into ensuring that you cannot create invalid xlsx documents.
62
- # confirm_valid should be used in the rare case that you cannot open the serialized file.
88
+ # confirm_valid should be used in the rare case that you cannot open the serialized file.
63
89
  # @see Package#validate
64
90
  # @example
65
91
  # # This is how easy it is to create a valid xlsx file. Of course you might want to add a sheet or two, and maybe some data, styles and charts.
@@ -70,35 +96,37 @@ module Axlsx
70
96
  # # You will find a file called test.xlsx
71
97
  def serialize(output, confirm_valid=false)
72
98
  return false unless !confirm_valid || self.validate.empty?
73
- p = parts
74
99
  Zip::ZipOutputStream.open(output) do |zip|
75
- p.each do |part|
76
- unless part[:doc].nil?
77
- zip.put_next_entry(part[:entry]);
78
- entry = ['1.9.2', '1.9.3'].include?(RUBY_VERSION) ? part[:doc].force_encoding('BINARY') : part[:doc]
79
- zip.puts(entry)
80
- end
81
- unless part[:path].nil?
82
- zip.put_next_entry(part[:entry]);
83
- # binread for 1.9.3
84
- zip.write IO.respond_to?(:binread) ? IO.binread(part[:path]) : IO.read(part[:path])
85
- end
86
- end
100
+ write_parts(zip)
87
101
  end
88
102
  true
89
103
  end
90
-
104
+
105
+
106
+ # Serialize your workbook to a StringIO instance
107
+ # @param [Boolean] confirm_valid Validate the package prior to serialization.
108
+ # @return [StringIO|Boolean] False if confirm_valid and validation errors exist. rewound string IO if not.
109
+ def to_stream(confirm_valid=false)
110
+ return false unless !confirm_valid || self.validate.empty?
111
+ zip = write_parts(Zip::ZipOutputStream.new("streamed", true))
112
+ stream = zip.close_buffer
113
+ stream.rewind
114
+ stream
115
+ end
116
+
91
117
  # Encrypt the package into a CFB using the password provided
92
- # def encrypt(file_name, password)
93
- # moc = MsOffCrypto.new(file_name, password)
94
- # moc.save
95
- # end
96
-
97
- # Validate all parts of the package against xsd schema.
118
+ # This is not ready yet
119
+ def encrypt(file_name, password)
120
+ return false
121
+ # moc = MsOffCrypto.new(file_name, password)
122
+ # moc.save
123
+ end
124
+
125
+ # Validate all parts of the package against xsd schema.
98
126
  # @return [Array] An array of all validation errors found.
99
127
  # @note This gem includes all schema from OfficeOpenXML-XMLSchema-Transitional.zip and OpenPackagingConventions-XMLSchema.zip
100
128
  # as per ECMA-376, Third edition. opc schema require an internet connection to import remote schema from dublin core for dc,
101
- # dcterms and xml namespaces. Those remote schema are included in this gem, and the original files have been altered to
129
+ # dcterms and xml namespaces. Those remote schema are included in this gem, and the original files have been altered to
102
130
  # refer to the local versions.
103
131
  #
104
132
  # If by chance you are able to creat a package that does not validate it indicates that the internal
@@ -111,41 +139,71 @@ module Axlsx
111
139
  # p.validate.each { |error| puts error.message }
112
140
  def validate
113
141
  errors = []
114
- parts.each { |part| errors.concat validate_single_doc(part[:schema], part[:doc]) unless part[:schema].nil? }
142
+ parts.each do |part|
143
+ errors.concat validate_single_doc(part[:schema], part[:doc]) unless part[:schema].nil?
144
+ end
115
145
  errors
116
146
  end
117
147
 
118
- private
148
+ private
149
+
150
+ # Writes the package parts to a zip archive.
151
+ # @param [Zip::ZipOutputStream] zip
152
+ # @return [Zip::ZipOutputStream]
153
+ def write_parts(zip)
154
+ p = parts
155
+ p.each do |part|
156
+ unless part[:doc].nil?
157
+ zip.put_next_entry(part[:entry]);
158
+ entry = ['1.9.2', '1.9.3'].include?(RUBY_VERSION) ? part[:doc].force_encoding('BINARY') : part[:doc]
159
+ zip.puts(entry)
160
+ end
161
+ unless part[:path].nil?
162
+ zip.put_next_entry(part[:entry]);
163
+ # binread for 1.9.3
164
+ zip.write IO.respond_to?(:binread) ? IO.binread(part[:path]) : IO.read(part[:path])
165
+ end
166
+ end
167
+ zip
168
+ end
119
169
 
120
170
  # The parts of a package
121
- # @return [Array] An array of hashes that define the entry, document and schema for each part of the package.
171
+ # @return [Array] An array of hashes that define the entry, document and schema for each part of the package.
122
172
  # @private
123
173
  def parts
124
174
  @parts = [
125
- {:entry => RELS_PN, :doc => relationships.to_xml, :schema => RELS_XSD},
126
- {:entry => "xl/#{STYLES_PN}", :doc => workbook.styles.to_xml, :schema => SML_XSD},
127
- {:entry => CORE_PN, :doc => @core.to_xml, :schema => CORE_XSD},
128
- {:entry => APP_PN, :doc => @app.to_xml, :schema => APP_XSD},
129
- {:entry => WORKBOOK_RELS_PN, :doc => workbook.relationships.to_xml, :schema => RELS_XSD},
130
- {:entry => CONTENT_TYPES_PN, :doc => content_types.to_xml, :schema => CONTENT_TYPES_XSD},
131
- {:entry => WORKBOOK_PN, :doc => workbook.to_xml, :schema => SML_XSD}
175
+ {:entry => RELS_PN, :doc => relationships.to_xml_string, :schema => RELS_XSD},
176
+ {:entry => "xl/#{STYLES_PN}", :doc => workbook.styles.to_xml_string, :schema => SML_XSD},
177
+ {:entry => CORE_PN, :doc => @core.to_xml_string, :schema => CORE_XSD},
178
+ {:entry => APP_PN, :doc => @app.to_xml_string, :schema => APP_XSD},
179
+ {:entry => WORKBOOK_RELS_PN, :doc => workbook.relationships.to_xml_string, :schema => RELS_XSD},
180
+ {:entry => CONTENT_TYPES_PN, :doc => content_types.to_xml_string, :schema => CONTENT_TYPES_XSD},
181
+ {:entry => WORKBOOK_PN, :doc => workbook.to_xml_string, :schema => SML_XSD}
132
182
  ]
133
183
  workbook.drawings.each do |drawing|
134
- @parts << {:entry => "xl/#{drawing.rels_pn}", :doc => drawing.relationships.to_xml, :schema => RELS_XSD}
135
- @parts << {:entry => "xl/#{drawing.pn}", :doc => drawing.to_xml, :schema => DRAWING_XSD}
184
+ @parts << {:entry => "xl/#{drawing.rels_pn}", :doc => drawing.relationships.to_xml_string, :schema => RELS_XSD}
185
+ @parts << {:entry => "xl/#{drawing.pn}", :doc => drawing.to_xml_string, :schema => DRAWING_XSD}
186
+ end
187
+
188
+ workbook.tables.each do |table|
189
+ @parts << {:entry => "xl/#{table.pn}", :doc => table.to_xml_string, :schema => SML_XSD}
190
+ end
191
+
192
+ workbook.charts.each do |chart|
193
+ @parts << {:entry => "xl/#{chart.pn}", :doc => chart.to_xml_string, :schema => DRAWING_XSD}
136
194
  end
137
-
138
- workbook.charts.each do |chart|
139
- @parts << {:entry => "xl/#{chart.pn}", :doc => chart.to_xml, :schema => DRAWING_XSD}
140
- end
141
195
 
142
196
  workbook.images.each do |image|
143
197
  @parts << {:entry => "xl/#{image.pn}", :path => image.image_src}
144
198
  end
145
199
 
146
- workbook.worksheets.each do |sheet|
147
- @parts << {:entry => "xl/#{sheet.rels_pn}", :doc => sheet.relationships.to_xml, :schema => RELS_XSD}
148
- @parts << {:entry => "xl/#{sheet.pn}", :doc => sheet.to_xml, :schema => SML_XSD}
200
+ if use_shared_strings
201
+ @parts << {:entry => "xl/#{SHARED_STRINGS_PN}", :doc => workbook.shared_strings.to_xml_string, :schema => SML_XSD}
202
+ end
203
+
204
+ workbook.worksheets.each do |sheet|
205
+ @parts << {:entry => "xl/#{sheet.rels_pn}", :doc => sheet.relationships.to_xml_string, :schema => RELS_XSD}
206
+ @parts << {:entry => "xl/#{sheet.pn}", :doc => sheet.to_xml_string, :schema => SML_XSD}
149
207
  end
150
208
  @parts
151
209
  end
@@ -159,7 +217,6 @@ module Axlsx
159
217
  def validate_single_doc(schema, doc)
160
218
  schema = Nokogiri::XML::Schema(File.open(schema))
161
219
  doc = Nokogiri::XML(doc)
162
-
163
220
  errors = []
164
221
  schema.validate(doc).each do |error|
165
222
  errors << error
@@ -173,15 +230,19 @@ module Axlsx
173
230
  def content_types
174
231
  c_types = base_content_types
175
232
  workbook.drawings.each do |drawing|
176
- c_types << Axlsx::Override.new(:PartName => "/xl/#{drawing.pn}",
233
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{drawing.pn}",
177
234
  :ContentType => DRAWING_CT)
178
235
  end
179
236
  workbook.charts.each do |chart|
180
- c_types << Axlsx::Override.new(:PartName => "/xl/#{chart.pn}",
181
- :ContentType => CHART_CT)
237
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{chart.pn}",
238
+ :ContentType => CHART_CT)
239
+ end
240
+ workbook.tables.each do |table|
241
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{table.pn}",
242
+ :ContentType => TABLE_CT)
182
243
  end
183
244
  workbook.worksheets.each do |sheet|
184
- c_types << Axlsx::Override.new(:PartName => "/xl/#{sheet.pn}",
245
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{sheet.pn}",
185
246
  :ContentType => WORKSHEET_CT)
186
247
  end
187
248
  exts = workbook.images.map { |image| image.extname }
@@ -195,6 +256,10 @@ module Axlsx
195
256
  end
196
257
  c_types << Axlsx::Default.new(:ContentType => ct, :Extension => ext )
197
258
  end
259
+ if use_shared_strings
260
+ c_types << Axlsx::Override.new(:PartName => "/xl/#{SHARED_STRINGS_PN}",
261
+ :ContentType => SHARED_STRINGS_CT)
262
+ end
198
263
  c_types
199
264
  end
200
265
 
@@ -208,7 +273,7 @@ module Axlsx
208
273
  c_types << Override.new(:PartName => "/#{APP_PN}", :ContentType => APP_CT)
209
274
  c_types << Override.new(:PartName => "/#{CORE_PN}", :ContentType => CORE_CT)
210
275
  c_types << Override.new(:PartName => "/xl/#{STYLES_PN}", :ContentType => STYLES_CT)
211
- c_types << Axlsx::Override.new(:PartName => "/#{WORKBOOK_PN}", :ContentType => WORKBOOK_CT)
276
+ c_types << Axlsx::Override.new(:PartName => "/#{WORKBOOK_PN}", :ContentType => WORKBOOK_CT)
212
277
  c_types.lock
213
278
  c_types
214
279
  end