axlsx 1.0.16 → 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 (173) hide show
  1. data/.yardopts +1 -0
  2. data/CHANGELOG.md +18 -3
  3. data/README.md +189 -55
  4. data/examples/example.csv +1000 -0
  5. data/examples/example.rb +264 -142
  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 +16 -12
  22. data/lib/axlsx/drawing/graphic_frame.rb +22 -21
  23. data/lib/axlsx/drawing/hyperlink.rb +13 -12
  24. data/lib/axlsx/drawing/line_3D_chart.rb +31 -28
  25. data/lib/axlsx/drawing/line_series.rb +12 -11
  26. data/lib/axlsx/drawing/marker.rb +11 -8
  27. data/lib/axlsx/drawing/named_axis_data.rb +36 -0
  28. data/lib/axlsx/drawing/one_cell_anchor.rb +18 -16
  29. data/lib/axlsx/drawing/pic.rb +26 -38
  30. data/lib/axlsx/drawing/picture_locking.rb +22 -18
  31. data/lib/axlsx/drawing/pie_3D_chart.rb +11 -8
  32. data/lib/axlsx/drawing/pie_series.rb +16 -12
  33. data/lib/axlsx/drawing/scaling.rb +11 -10
  34. data/lib/axlsx/drawing/scatter_chart.rb +69 -0
  35. data/lib/axlsx/drawing/scatter_series.rb +39 -0
  36. data/lib/axlsx/drawing/ser_axis.rb +11 -10
  37. data/lib/axlsx/drawing/series.rb +16 -15
  38. data/lib/axlsx/drawing/series_title.rb +15 -14
  39. data/lib/axlsx/drawing/title.rb +27 -26
  40. data/lib/axlsx/drawing/two_cell_anchor.rb +19 -20
  41. data/lib/axlsx/drawing/val_axis.rb +9 -7
  42. data/lib/axlsx/drawing/val_axis_data.rb +18 -17
  43. data/lib/axlsx/drawing/view_3D.rb +23 -20
  44. data/lib/axlsx/package.rb +116 -51
  45. data/lib/axlsx/rels/relationship.rb +12 -8
  46. data/lib/axlsx/rels/relationships.rb +8 -1
  47. data/lib/axlsx/stylesheet/#num_fmt.rb# +69 -0
  48. data/lib/axlsx/stylesheet/border.rb +28 -23
  49. data/lib/axlsx/stylesheet/border_pr.rb +17 -15
  50. data/lib/axlsx/stylesheet/cell_alignment.rb +24 -21
  51. data/lib/axlsx/stylesheet/cell_protection.rb +11 -7
  52. data/lib/axlsx/stylesheet/cell_style.rb +9 -5
  53. data/lib/axlsx/stylesheet/color.rb +21 -14
  54. data/lib/axlsx/stylesheet/fill.rb +8 -5
  55. data/lib/axlsx/stylesheet/font.rb +22 -14
  56. data/lib/axlsx/stylesheet/gradient_fill.rb +20 -17
  57. data/lib/axlsx/stylesheet/gradient_stop.rb +10 -6
  58. data/lib/axlsx/stylesheet/num_fmt.rb +13 -6
  59. data/lib/axlsx/stylesheet/pattern_fill.rb +26 -10
  60. data/lib/axlsx/stylesheet/styles.rb +53 -41
  61. data/lib/axlsx/stylesheet/table_style.rb +10 -4
  62. data/lib/axlsx/stylesheet/table_style_element.rb +11 -7
  63. data/lib/axlsx/stylesheet/table_styles.rb +12 -8
  64. data/lib/axlsx/stylesheet/xf.rb +30 -25
  65. data/lib/axlsx/util/cbf.rb +1 -0
  66. data/lib/axlsx/util/constants.rb +27 -14
  67. data/lib/axlsx/util/ms_off_crypto.rb +1 -1
  68. data/lib/axlsx/util/parser.rb +1 -0
  69. data/lib/axlsx/util/simple_typed_list.rb +20 -10
  70. data/lib/axlsx/util/storage.rb +1 -0
  71. data/lib/axlsx/util/validators.rb +23 -7
  72. data/lib/axlsx/version.rb +2 -1
  73. data/lib/axlsx/workbook/shared_strings_table.rb +69 -0
  74. data/lib/axlsx/workbook/shared_strings_table.rb~ +69 -0
  75. data/lib/axlsx/workbook/workbook.rb +81 -35
  76. data/lib/axlsx/workbook/worksheet/cell.rb +172 -117
  77. data/lib/axlsx/workbook/worksheet/col.rb +114 -0
  78. data/lib/axlsx/workbook/worksheet/col.rb~ +0 -0
  79. data/lib/axlsx/workbook/worksheet/date_time_converter.rb +29 -0
  80. data/lib/axlsx/workbook/worksheet/page_margins.rb +97 -0
  81. data/lib/axlsx/workbook/worksheet/row.rb +53 -21
  82. data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
  83. data/lib/axlsx/workbook/worksheet/table.rb +96 -0
  84. data/lib/axlsx/workbook/worksheet/table.rb~ +97 -0
  85. data/lib/axlsx/workbook/worksheet/worksheet.rb +269 -121
  86. data/lib/axlsx.rb +41 -14
  87. data/lib/schema/dc.xsd +5 -5
  88. data/lib/schema/dcmitype.xsd +5 -3
  89. data/lib/schema/dcterms.xsd +15 -15
  90. data/lib/schema/opc-coreProperties.xsd +6 -2
  91. data/lib/schema/xml.xsd +7 -8
  92. data/test/#benchmark.txt# +7 -0
  93. data/test/#tc_helper.rb# +3 -0
  94. data/test/benchmark.rb +81 -0
  95. data/test/benchmark.rb~ +0 -0
  96. data/test/benchmark.txt +6 -0
  97. data/test/benchmark.txt~ +6 -0
  98. data/test/content_type/tc_content_type.rb +31 -31
  99. data/test/content_type/tc_default.rb +9 -22
  100. data/test/content_type/tc_override.rb +8 -21
  101. data/test/doc_props/tc_app.rb +2 -8
  102. data/test/doc_props/tc_core.rb +6 -7
  103. data/test/drawing/tc_axis.rb +7 -3
  104. data/test/drawing/tc_bar_3D_chart.rb +6 -7
  105. data/test/drawing/tc_bar_series.rb +4 -5
  106. data/test/drawing/tc_cat_axis.rb +2 -3
  107. data/test/drawing/tc_cat_axis_data.rb +2 -3
  108. data/test/drawing/tc_chart.rb +13 -14
  109. data/test/drawing/tc_drawing.rb +7 -8
  110. data/test/drawing/tc_graphic_frame.rb +3 -4
  111. data/test/drawing/tc_hyperlink.rb +2 -3
  112. data/test/drawing/tc_line_3d_chart.rb +5 -6
  113. data/test/drawing/tc_line_series.rb +3 -4
  114. data/test/drawing/tc_marker.rb +3 -4
  115. data/test/drawing/tc_one_cell_anchor.rb +6 -7
  116. data/test/drawing/tc_pic.rb +8 -9
  117. data/test/drawing/tc_picture_locking.rb +2 -3
  118. data/test/drawing/tc_pie_3D_chart.rb +5 -6
  119. data/test/drawing/tc_pie_series.rb +4 -5
  120. data/test/drawing/tc_scaling.rb +3 -4
  121. data/test/drawing/tc_scatter_chart.rb +43 -0
  122. data/test/drawing/tc_scatter_series.rb +20 -0
  123. data/test/drawing/tc_ser_axis.rb +2 -3
  124. data/test/drawing/tc_series.rb +4 -5
  125. data/test/drawing/tc_series_title.rb +4 -5
  126. data/test/drawing/tc_title.rb +4 -5
  127. data/test/drawing/tc_two_cell_anchor.rb +4 -5
  128. data/test/drawing/tc_val_axis.rb +2 -3
  129. data/test/drawing/tc_val_axis_data.rb +2 -3
  130. data/test/drawing/tc_view_3D.rb +6 -7
  131. data/test/example.csv +1000 -0
  132. data/test/example.xlsx +0 -0
  133. data/test/example_streamed.xlsx +0 -0
  134. data/test/profile.rb +33 -0
  135. data/test/rels/tc_relationship.rb +5 -6
  136. data/test/rels/tc_relationships.rb +4 -5
  137. data/test/stylesheet/tc_border.rb +3 -4
  138. data/test/stylesheet/tc_border_pr.rb +3 -4
  139. data/test/stylesheet/tc_cell_alignment.rb +10 -6
  140. data/test/stylesheet/tc_cell_protection.rb +2 -3
  141. data/test/stylesheet/tc_cell_style.rb +2 -3
  142. data/test/stylesheet/tc_color.rb +2 -3
  143. data/test/stylesheet/tc_fill.rb +1 -2
  144. data/test/stylesheet/tc_font.rb +12 -5
  145. data/test/stylesheet/tc_gradient_fill.rb +1 -2
  146. data/test/stylesheet/tc_gradient_stop.rb +1 -2
  147. data/test/stylesheet/tc_num_fmt.rb +1 -2
  148. data/test/stylesheet/tc_pattern_fill.rb +3 -4
  149. data/test/stylesheet/tc_styles.rb +16 -6
  150. data/test/stylesheet/tc_table_style.rb +2 -3
  151. data/test/stylesheet/tc_table_style_element.rb +2 -3
  152. data/test/stylesheet/tc_table_styles.rb +3 -4
  153. data/test/stylesheet/tc_xf.rb +16 -17
  154. data/test/tc_axlsx.rb +39 -0
  155. data/test/tc_axlsx.rb~ +0 -0
  156. data/test/tc_helper.rb +3 -0
  157. data/test/tc_helper.rb~ +3 -0
  158. data/test/tc_package.rb +43 -9
  159. data/test/util/tc_simple_typed_list.rb +8 -9
  160. data/test/util/tc_validators.rb +7 -8
  161. data/test/workbook/tc_shared_strings_table.rb +38 -0
  162. data/test/workbook/tc_workbook.rb +32 -6
  163. data/test/workbook/worksheet/table/tc_table.rb +71 -0
  164. data/test/workbook/worksheet/table/tc_table.rb~ +72 -0
  165. data/test/workbook/worksheet/tc_cell.rb +70 -13
  166. data/test/workbook/worksheet/tc_col.rb +59 -0
  167. data/test/workbook/worksheet/tc_col.rb~ +10 -0
  168. data/test/workbook/worksheet/tc_date_time_converter.rb +126 -0
  169. data/test/workbook/worksheet/tc_page_margins.rb +97 -0
  170. data/test/workbook/worksheet/tc_row.rb +54 -4
  171. data/test/workbook/worksheet/tc_worksheet.rb +191 -31
  172. metadata +162 -109
  173. data/test/drawing/tc_hyperlink.rb~ +0 -71
@@ -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
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
95
123
  end
96
-
97
- # Validate all parts of the package against xsd schema.
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
@@ -1,6 +1,7 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  # A relationship defines a reference between package parts.
3
- # @note Packages automatcially manage relationships.
4
+ # @note Packages automatically manage relationships.
4
5
  class Relationship
5
6
 
6
7
  # The location of the relationship target
@@ -31,7 +32,7 @@ module Axlsx
31
32
  # creates a new relationship
32
33
  # @param [String] Type The type of the relationship
33
34
  # @param [String] Target The target for the relationship
34
- # @option [Symbol] target_mode only accepts :external.
35
+ # @option [Symbol] target_mode only accepts :external.
35
36
  def initialize(type, target, options={})
36
37
  self.Target=target
37
38
  self.Type=type
@@ -46,14 +47,17 @@ module Axlsx
46
47
  # @see TargetMode
47
48
  def TargetMode=(v) RestrictionValidator.validate 'Relationship.TargetMode', [:External, :Internal], v; @TargetMode = v; end
48
49
 
49
- # Serializes the relationship
50
- # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
51
- # @param [String] rId the reference id of the object.
50
+ # serialize relationship
51
+ # @param [String] str
52
+ # @param [Integer] rId the id for this relationship
52
53
  # @return [String]
53
- def to_xml(xml, rId)
54
+ def to_xml_string(rId, str = '')
54
55
  h = self.instance_values
55
- h[:Id] = rId
56
- xml.Relationship(h)
56
+ h[:Id] = 'rId' << rId.to_s
57
+ str << '<Relationship '
58
+ str << h.map { |key, value| '' << key.to_s << '="' << value.to_s << '"'}.join(' ')
59
+ str << '/>'
57
60
  end
61
+
58
62
  end
59
63
  end
@@ -1,3 +1,4 @@
1
+ # encoding: UTF-8
1
2
  module Axlsx
2
3
  require 'axlsx/rels/relationship.rb'
3
4
 
@@ -10,6 +11,12 @@ require 'axlsx/rels/relationship.rb'
10
11
  super Relationship
11
12
  end
12
13
 
14
+ def to_xml_string(str = '')
15
+ str << '<?xml version="1.0" encoding="UTF-8"?>'
16
+ str << '<Relationships xmlns="' << RELS_R << '">'
17
+ each_with_index { |rel, index| rel.to_xml_string(index+1, str) }
18
+ str << '</Relationships>'
19
+ end
13
20
  # Serializes the relationships document.
14
21
  # @return [String]
15
22
  def to_xml()
@@ -20,6 +27,6 @@ require 'axlsx/rels/relationship.rb'
20
27
  end
21
28
  builder.to_xml(:save_with => 0)
22
29
  end
23
-
30
+
24
31
  end
25
32
  end
@@ -0,0 +1,69 @@
1
+ # encoding: UTF-8
2
+ module Axlsx
3
+ # A NumFmt object defines an identifier and formatting code for data in cells.
4
+ # @note The recommended way to manage styles is Styles#add_style
5
+ class NumFmt
6
+ # @return [Integer] An unsinged integer referencing a standard or custom number format.
7
+ # @note
8
+ # These are the known formats I can dig up. The constant NUM_FMT_PERCENT is 9, and uses the default % formatting. Axlsx also defines a few formats for date and time that are commonly used in asia as NUM_FMT_YYYYMMDD and NUM_FRM_YYYYMMDDHHMMSS.
9
+ # 1 0
10
+ # 2 0.00
11
+ # 3 #,##0
12
+ # 4 #,##0.00
13
+ # 5 $#,##0_);($#,##0)
14
+ # 6 $#,##0_);[Red]($#,##0)
15
+ # 7 $#,##0.00_);($#,##0.00)
16
+ # 8 $#,##0.00_);[Red]($#,##0.00)
17
+ # 9 0%
18
+ # 10 0.00%
19
+ # 11 0.00E+00
20
+ # 12 # ?/?
21
+ # 13 # ??/??
22
+ # 14 m/d/yyyy
23
+ # 15 d-mmm-yy
24
+ # 16 d-mmm
25
+ # 17 mmm-yy
26
+ # 18 h:mm AM/PM
27
+ # 19 h:mm:ss AM/PM
28
+ # 20 h:mm
29
+ # 21 h:mm:ss
30
+ # 22 m/d/yyyy h:mm
31
+ # 37 #,##0_);(#,##0)
32
+ # 38 #,##0_);[Red](#,##0)
33
+ # 39 #,##0.00_);(#,##0.00)
34
+ # 40 #,##0.00_);[Red](#,##0.00)
35
+ # 45 mm:ss
36
+ # 46 [h]:mm:ss
37
+ # 47 mm:ss.0
38
+ # 48 ##0.0E+0
39
+ # 49 @
40
+ # @see Axlsx
41
+ attr_reader :numFmtId
42
+
43
+ # @return [String] The formatting to use for this number format.
44
+ # @see http://support.microsoft.com/kb/264372
45
+ attr_reader :formatCode
46
+ def initialize(options={})
47
+ @numFmtId = 0
48
+ @formatCode = ""
49
+ options.each do |o|
50
+ self.send("#{o[0]}=", o[1]) if self.respond_to? o[0]
51
+ end
52
+ end
53
+
54
+ # @see numFmtId
55
+ def numFmtId=(v) Axlsx::validate_unsigned_int v; @numFmtId = v end
56
+ # @see formatCode
57
+ def formatCode=(v) Axlsx::validate_string v; @formatCode = v end
58
+
59
+ # Serializes the object
60
+ # @param [String] str
61
+ # @return [String]
62
+ def to_xml_string(str = '')
63
+ str << '<numFmt '
64
+ str << instance_values.map { |key, value| '' << key.to_s << '="' << value.to_s << '"' }.join(' ')
65
+ str << '/>'
66
+ end
67
+
68
+ end
69
+ end