axlsx 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (179) hide show
  1. data/Rakefile +13 -0
  2. data/lib/axlsx.rb +38 -0
  3. data/lib/axlsx/content_type/content_type.rb +23 -0
  4. data/lib/axlsx/content_type/default.rb +32 -0
  5. data/lib/axlsx/content_type/override.rb +30 -0
  6. data/lib/axlsx/doc_props/app.rb +148 -0
  7. data/lib/axlsx/doc_props/core.rb +34 -0
  8. data/lib/axlsx/drawing/axis.rb +78 -0
  9. data/lib/axlsx/drawing/bar_3D_chart.rb +138 -0
  10. data/lib/axlsx/drawing/bar_series.rb +91 -0
  11. data/lib/axlsx/drawing/cat_axis.rb +58 -0
  12. data/lib/axlsx/drawing/chart.rb +120 -0
  13. data/lib/axlsx/drawing/drawing.rb +121 -0
  14. data/lib/axlsx/drawing/graphic_frame.rb +55 -0
  15. data/lib/axlsx/drawing/marker.rb +57 -0
  16. data/lib/axlsx/drawing/pie_3D_chart.rb +59 -0
  17. data/lib/axlsx/drawing/pie_series.rb +88 -0
  18. data/lib/axlsx/drawing/scaling.rb +53 -0
  19. data/lib/axlsx/drawing/series.rb +70 -0
  20. data/lib/axlsx/drawing/title.rb +69 -0
  21. data/lib/axlsx/drawing/two_cell_anchor.rb +88 -0
  22. data/lib/axlsx/drawing/val_axis.rb +34 -0
  23. data/lib/axlsx/drawing/view_3D.rb +72 -0
  24. data/lib/axlsx/package.rb +181 -0
  25. data/lib/axlsx/rels/relationship.rb +43 -0
  26. data/lib/axlsx/rels/relationships.rb +25 -0
  27. data/lib/axlsx/stylesheet/border.rb +52 -0
  28. data/lib/axlsx/stylesheet/border_pr.rb +65 -0
  29. data/lib/axlsx/stylesheet/cell_alignment.rb +96 -0
  30. data/lib/axlsx/stylesheet/cell_protection.rb +33 -0
  31. data/lib/axlsx/stylesheet/cell_style.rb +60 -0
  32. data/lib/axlsx/stylesheet/color.rb +57 -0
  33. data/lib/axlsx/stylesheet/fill.rb +31 -0
  34. data/lib/axlsx/stylesheet/font.rb +128 -0
  35. data/lib/axlsx/stylesheet/gradient_fill.rb +70 -0
  36. data/lib/axlsx/stylesheet/gradient_stop.rb +31 -0
  37. data/lib/axlsx/stylesheet/num_fmt.rb +61 -0
  38. data/lib/axlsx/stylesheet/pattern_fill.rb +64 -0
  39. data/lib/axlsx/stylesheet/styles.rb +296 -0
  40. data/lib/axlsx/stylesheet/table_style.rb +44 -0
  41. data/lib/axlsx/stylesheet/table_style_element.rb +66 -0
  42. data/lib/axlsx/stylesheet/table_styles.rb +39 -0
  43. data/lib/axlsx/stylesheet/xf.rb +117 -0
  44. data/lib/axlsx/util/constants.rb +189 -0
  45. data/lib/axlsx/util/simple_typed_list.rb +150 -0
  46. data/lib/axlsx/util/validators.rb +132 -0
  47. data/lib/axlsx/workbook/workbook.rb +130 -0
  48. data/lib/axlsx/workbook/worksheet/cell.rb +184 -0
  49. data/lib/axlsx/workbook/worksheet/row.rb +92 -0
  50. data/lib/axlsx/workbook/worksheet/worksheet.rb +194 -0
  51. data/lib/schema/dc.xsd +118 -0
  52. data/lib/schema/dcmitype.xsd +50 -0
  53. data/lib/schema/dcterms.xsd +331 -0
  54. data/lib/schema/dml-chart.xsd +1499 -0
  55. data/lib/schema/dml-chartDrawing.xsd +146 -0
  56. data/lib/schema/dml-compatibility.xsd +14 -0
  57. data/lib/schema/dml-diagram.xsd +1091 -0
  58. data/lib/schema/dml-lockedCanvas.xsd +11 -0
  59. data/lib/schema/dml-main.xsd +3048 -0
  60. data/lib/schema/dml-picture.xsd +23 -0
  61. data/lib/schema/dml-spreadsheetDrawing.xsd +185 -0
  62. data/lib/schema/dml-wordprocessingDrawing.xsd +185 -0
  63. data/lib/schema/opc-contentTypes.xsd +42 -0
  64. data/lib/schema/opc-coreProperties.xsd +50 -0
  65. data/lib/schema/opc-digSig.xsd +49 -0
  66. data/lib/schema/opc-relationships.xsd +33 -0
  67. data/lib/schema/pml.xsd +1676 -0
  68. data/lib/schema/shared-additionalCharacteristics.xsd +28 -0
  69. data/lib/schema/shared-bibliography.xsd +144 -0
  70. data/lib/schema/shared-commonSimpleTypes.xsd +166 -0
  71. data/lib/schema/shared-customXmlDataProperties.xsd +25 -0
  72. data/lib/schema/shared-customXmlSchemaProperties.xsd +18 -0
  73. data/lib/schema/shared-documentPropertiesCustom.xsd +59 -0
  74. data/lib/schema/shared-documentPropertiesExtended.xsd +56 -0
  75. data/lib/schema/shared-documentPropertiesVariantTypes.xsd +195 -0
  76. data/lib/schema/shared-math.xsd +582 -0
  77. data/lib/schema/shared-relationshipReference.xsd +25 -0
  78. data/lib/schema/sml.xsd +4430 -0
  79. data/lib/schema/vml-main.xsd +569 -0
  80. data/lib/schema/vml-officeDrawing.xsd +509 -0
  81. data/lib/schema/vml-presentationDrawing.xsd +12 -0
  82. data/lib/schema/vml-spreadsheetDrawing.xsd +108 -0
  83. data/lib/schema/vml-wordprocessingDrawing.xsd +96 -0
  84. data/lib/schema/wml.xsd +3644 -0
  85. data/lib/schema/xml.xsd +117 -0
  86. data/test/content_type/tc_content_type.rb +81 -0
  87. data/test/content_type/tc_content_type.rb~ +81 -0
  88. data/test/content_type/tc_default.rb +40 -0
  89. data/test/content_type/tc_default.rb~ +40 -0
  90. data/test/content_type/tc_override.rb +40 -0
  91. data/test/content_type/tc_override.rb~ +40 -0
  92. data/test/doc_props/tc_app.rb +19 -0
  93. data/test/doc_props/tc_app.rb~ +19 -0
  94. data/test/doc_props/tc_core.rb +34 -0
  95. data/test/drawing/tc_axis.rb +39 -0
  96. data/test/drawing/tc_axis.rb~ +0 -0
  97. data/test/drawing/tc_bar_3D_chart.rb +66 -0
  98. data/test/drawing/tc_bar_3D_chart.rb~ +4 -0
  99. data/test/drawing/tc_bar_series.rb +34 -0
  100. data/test/drawing/tc_bar_series.rb~ +31 -0
  101. data/test/drawing/tc_cat_axis.rb +32 -0
  102. data/test/drawing/tc_cat_axis.rb~ +39 -0
  103. data/test/drawing/tc_chart.rb +59 -0
  104. data/test/drawing/tc_chart.rb~ +58 -0
  105. data/test/drawing/tc_drawing.rb +71 -0
  106. data/test/drawing/tc_graphic_frame.rb +26 -0
  107. data/test/drawing/tc_graphic_frame.rb~ +21 -0
  108. data/test/drawing/tc_marker.rb +45 -0
  109. data/test/drawing/tc_marker.rb~ +26 -0
  110. data/test/drawing/tc_pie_3D_chart.rb +33 -0
  111. data/test/drawing/tc_pie_3D_chart.rb~ +58 -0
  112. data/test/drawing/tc_pie_series.rb +35 -0
  113. data/test/drawing/tc_pie_series.rb~ +26 -0
  114. data/test/drawing/tc_scaling.rb +37 -0
  115. data/test/drawing/tc_scaling.rb~ +45 -0
  116. data/test/drawing/tc_series.rb +24 -0
  117. data/test/drawing/tc_series.rb~ +31 -0
  118. data/test/drawing/tc_title.rb +34 -0
  119. data/test/drawing/tc_title.rb~ +37 -0
  120. data/test/drawing/tc_two_cell_anchor.rb +37 -0
  121. data/test/drawing/tc_two_cell_anchor.rb~ +35 -0
  122. data/test/drawing/tc_val_axis.rb +20 -0
  123. data/test/drawing/tc_val_axis.rb~ +32 -0
  124. data/test/drawing/tc_view_3D.rb +46 -0
  125. data/test/drawing/tc_view_3D.rb~ +37 -0
  126. data/test/rels/tc_relationship.rb +16 -0
  127. data/test/rels/tc_relationship.rb~ +39 -0
  128. data/test/rels/tc_relationships.rb +32 -0
  129. data/test/rels/tc_relationships.rb~ +37 -0
  130. data/test/stylesheet/tc_border.rb +38 -0
  131. data/test/stylesheet/tc_border.rb~ +31 -0
  132. data/test/stylesheet/tc_border_pr.rb +33 -0
  133. data/test/stylesheet/tc_border_pr.rb~ +31 -0
  134. data/test/stylesheet/tc_cell_alignment.rb +77 -0
  135. data/test/stylesheet/tc_cell_alignment.rb~ +38 -0
  136. data/test/stylesheet/tc_cell_protection.rb +30 -0
  137. data/test/stylesheet/tc_cell_protection.rb~ +77 -0
  138. data/test/stylesheet/tc_cell_style.rb +58 -0
  139. data/test/stylesheet/tc_cell_style.rb~ +30 -0
  140. data/test/stylesheet/tc_color.rb +38 -0
  141. data/test/stylesheet/tc_color.rb~ +38 -0
  142. data/test/stylesheet/tc_fill.rb +19 -0
  143. data/test/stylesheet/tc_fill.rb~ +19 -0
  144. data/test/stylesheet/tc_font.rb +114 -0
  145. data/test/stylesheet/tc_font.rb~ +19 -0
  146. data/test/stylesheet/tc_gradient_fill.rb +65 -0
  147. data/test/stylesheet/tc_gradient_fill.rb~ +114 -0
  148. data/test/stylesheet/tc_gradient_stop.rb +32 -0
  149. data/test/stylesheet/tc_gradient_stop.rb~ +65 -0
  150. data/test/stylesheet/tc_num_fmt.rb +31 -0
  151. data/test/stylesheet/tc_num_fmt.rb~ +32 -0
  152. data/test/stylesheet/tc_pattern_fill.rb +38 -0
  153. data/test/stylesheet/tc_pattern_fill.rb~ +31 -0
  154. data/test/stylesheet/tc_styles.rb +64 -0
  155. data/test/stylesheet/tc_table_style.rb +37 -0
  156. data/test/stylesheet/tc_table_style.rb~ +38 -0
  157. data/test/stylesheet/tc_table_style_element.rb +37 -0
  158. data/test/stylesheet/tc_table_style_element.rb~ +37 -0
  159. data/test/stylesheet/tc_table_styles.rb +30 -0
  160. data/test/stylesheet/tc_table_styles.rb~ +37 -0
  161. data/test/stylesheet/tc_xf.rb +121 -0
  162. data/test/stylesheet/tc_xf.rb~ +30 -0
  163. data/test/tc_app.rb~ +19 -0
  164. data/test/tc_border_pr.rb~ +21 -0
  165. data/test/tc_package.rb +70 -0
  166. data/test/tc_package.rb~ +64 -0
  167. data/test/tc_pie_3D_chart.rb~ +66 -0
  168. data/test/tc_relationships.rb~ +37 -0
  169. data/test/tc_series.rb~ +31 -0
  170. data/test/tc_styles.rb~ +64 -0
  171. data/test/tc_validators.rb~ +77 -0
  172. data/test/tc_worksheet.rb~ +85 -0
  173. data/test/util/tc_simple_typed_list.rb +66 -0
  174. data/test/util/tc_validators.rb +76 -0
  175. data/test/workbook/tc_workbook.rb +53 -0
  176. data/test/workbook/worksheet/tc_cell.rb +78 -0
  177. data/test/workbook/worksheet/tc_row.rb +30 -0
  178. data/test/workbook/worksheet/tc_worksheet.rb +85 -0
  179. metadata +378 -0
@@ -0,0 +1,150 @@
1
+ module Axlsx
2
+ # A SimpleTypedList is a type restrictive collection that allows some of the methods from Array and supports basic xml serialization.
3
+ # @private
4
+ class SimpleTypedList
5
+ # The class constants of allowed types
6
+ # @return [Array]
7
+ attr_reader :allowed_types
8
+
9
+ # The index below which items cannot be removed
10
+ # @return [Integer]
11
+ attr_reader :locked_at
12
+
13
+ # The tag name to use when serializing this object
14
+ # by default the parent node for all items in the list is the classname of the first allowed type with the first letter in lowercase.
15
+ # @return [String]
16
+ attr_reader :serialize_as
17
+
18
+ # Creats a new typed list
19
+ # @param [Array, Class] type An array of Class objects or a single Class object
20
+ # @param [String] serialize The tag name to use in serialization
21
+ # @raise [ArgumentError] if all members of type are not Class objects
22
+ def initialize type, serialize_as=nil
23
+ if type.is_a? Array
24
+ type.each { |item| raise ArgumentError, "All members of type must be Class objects" unless item.is_a? Class }
25
+ @allowed_types = type
26
+ else
27
+ raise ArgumentError, "Type must be a Class object or array of Class objects" unless type.is_a? Class
28
+ @allowed_types = [type]
29
+ end
30
+ @list = []
31
+ @locked_at = nil
32
+ @serialize_as = serialize_as
33
+ end
34
+
35
+ # Lock this list at the current size
36
+ # @return [self]
37
+ def lock
38
+ @locked_at = @list.size
39
+ self
40
+ end
41
+
42
+ # Unlock the list
43
+ # @return [self]
44
+ def unlock
45
+ @locked_at = nil
46
+ self
47
+ end
48
+
49
+ # Concat operator
50
+ # @param [Any] v the data to be added
51
+ # @raise [ArgumentError] if the value being added is not one fo the allowed types
52
+ # @return [Integer] returns the index of the item added.
53
+ def <<(v)
54
+ DataTypeValidator.validate "SimpleTypedList.<<", @allowed_types, v
55
+ @list << v
56
+ @list.size - 1
57
+ end
58
+
59
+ # alternate of << method
60
+ # @see <<
61
+ def push(v)
62
+ self.<< v
63
+ end
64
+
65
+ # delete the item from the list
66
+ # @param [Any] v The item to be deleted.
67
+ # @raise [ArgumentError] if the item's index is protected by locking
68
+ # @return [Any] The item deleted
69
+ def delete(v)
70
+ return unless @list.include? v
71
+ raise ArgumentError, "Item is protected and cannot be deleted" if protected? @list.index(v)
72
+ @list.delete v
73
+ end
74
+
75
+ # delete the item from the list at the index position provided
76
+ # @raise [ArgumentError] if the index is protected by locking
77
+ # @return [Any] The item deleted
78
+ def delete_at(index)
79
+ @list[index]
80
+ raise ArgumentError, "Item is protected and cannot be deleted" if protected? index
81
+ @list.delete_at index
82
+ end
83
+
84
+ # positional assignment. Adds the item at the index specified
85
+ # @param [Integer] index
86
+ # @param [Any] v
87
+ # @raise [ArgumentError] if the index is protected by locking
88
+ # @raise [ArgumentError] if the item is not one of the allowed types
89
+ def []=(index, v)
90
+ DataTypeValidator.validate "SimpleTypedList.<<", @allowed_types, v
91
+ raise ArgumentError, "Item is protected and cannot be changed" if protected? index
92
+ @list[index] = v
93
+ v
94
+ end
95
+
96
+ # determines if the index is protected
97
+ # @param [Integer] index
98
+ def protected? index
99
+ return false unless @locked_at.is_a? Fixnum
100
+ index < @locked_at
101
+ end
102
+
103
+ # method_mission override to pass allowed methods to the list.
104
+ # @note
105
+ # the following methods are not allowed
106
+ # :replace
107
+ # :insert
108
+ # :collect!
109
+ # :map!
110
+ # :pop
111
+ # :delete_if
112
+ # :reverse!
113
+ # :shift
114
+ # :shuffle!
115
+ # :slice!
116
+ # :sort!
117
+ # :uniq!
118
+ # :unshift
119
+ # :zip
120
+ # :flatten!
121
+ # :fill
122
+ # :drop
123
+ # :drop_while
124
+ # :delete_if
125
+ # :clear
126
+ # :concat
127
+ def method_missing(meth, *args, &block)
128
+ raise ArgumentError, "#{meth} not supported" if [:replace, :insert, :collect!, :map!, :pop, :delete_if, :reverse!, :shift, :shuffle!, :slice!, :sort!, :uniq!, :unshift, :zip, :flatten!, :fill, :drop, :drop_while, :delete_if, :clear, :concat].include? meth.to_sym
129
+ if @list.respond_to? meth
130
+ @list.send(meth, *args, &block)
131
+ else
132
+ super
133
+ end
134
+ end
135
+
136
+ # Serializes the list
137
+ # If the serialize_as property is set, it is used as the parent node name.
138
+ # If the serialize_as property is nil, the first item in the list of allowed_types will be used, having the first letter of the class changed to lower case.
139
+ # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
140
+ # @return [String]
141
+ def to_xml(xml)
142
+ classname = @allowed_types[0].name.split('::').last
143
+ el_name = serialize_as || (classname[0,1].downcase + classname[1..-1]).pluralize
144
+ xml.send(el_name, :count=>@list.size) {
145
+ @list.each { |item| item.to_xml(xml) }
146
+ }
147
+ end
148
+ end
149
+
150
+ end
@@ -0,0 +1,132 @@
1
+ module Axlsx
2
+ # Validate a value against a specific list of allowed values.
3
+ class RestrictionValidator
4
+ # Perform validation
5
+ # @param [String] name The name of what is being validatied. This is included in the error message
6
+ # @param [Array] choices The list of choices to validate against
7
+ # @param [Any] v The value to be validated
8
+ # @raise [ArgumentError] Raised if the value provided is not in the list of choices.
9
+ # @return [Boolean] true if validation succeeds.
10
+ def self.validate(name, choices, v)
11
+ raise ArgumentError, (ERR_RESTRICTION % [v.to_s, name, choices.inspect]) unless choices.include?(v)
12
+ true
13
+ end
14
+ end
15
+
16
+ # Validates the value against the regular expression provided.
17
+ # @param [String] name The name of what is being validated. This is included in the output when the value is invalid
18
+ # @param [Regexp] regex The regular expression to evaluate
19
+ # @param [Any] v The value to validate.
20
+ class RegexValidator
21
+ def self.validate(name, regex, v)
22
+ raise ArgumentError, (ERR_REGEX % [v.inspect, regex.to_s]) unless (v.respond_to?(:=~) && v =~ regex)
23
+ end
24
+ end
25
+ # Validate that the class of the value provided is either an instance or the class of the allowed types and that any specified additional validation returns true.
26
+ class DataTypeValidator
27
+ # Perform validation
28
+ # @param [String] name The name of what is being validated. This is included in the error message
29
+ # @param [Array, Class] types A single class or array of classes that the value is validated against.
30
+ # @param [Block] other Any block that must evaluate to true for the value to be valid
31
+ # @raise [ArugumentError] Raised if the class of the value provided is not in the specified array of types or the block passed returns false
32
+ # @return [Boolean] true if validation succeeds.
33
+ # @see validate_boolean
34
+ def self.validate(name, types, v, other= lambda{|v| true })
35
+ types = [types] unless types.is_a? Array
36
+ valid_type = false
37
+ if v.class == Class
38
+ types.each { |t| valid_type = true if v.ancestors.include?(t) }
39
+ else
40
+ types.each { |t| valid_type = true if v.is_a?(t) }
41
+ end
42
+ raise ArgumentError, (ERR_TYPE % [v.inspect, name, types.inspect]) unless (other.call(v) && valid_type)
43
+ end
44
+ true
45
+ end
46
+
47
+ # Requires that the value is a Fixnum or Integer and is greater or equal to 0
48
+ # @param [Any] v The value validated
49
+ # @raise [ArgumentError] raised if the value is not a Fixnum or Integer value greater or equal to 0
50
+ # @return [Boolean] true if the data is valid
51
+ def self.validate_unsigned_int(v)
52
+ DataTypeValidator.validate(:unsigned_int, [Fixnum, Integer], v, lambda { |v| v.respond_to?(:>=) && v >= 0 })
53
+ end
54
+
55
+ # Requires that the value is a Fixnum or Integer
56
+ # @param [Any] v The value validated
57
+ def self.validate_int(v)
58
+ DataTypeValidator.validate :unsigned_int, [Fixnum, Integer], v
59
+ end
60
+
61
+ # Requires that the value is a form that can be evaluated as a boolean in an xml document.
62
+ # The value must be an instance of Fixnum, String, Integer, Symbol, TrueClass or FalseClass and
63
+ # it must be one of 0, 1, "true", "false", :true, :false, true, false, "0", or "1"
64
+ # @param [Any] v The value validated
65
+ def self.validate_boolean(v)
66
+ DataTypeValidator.validate(:boolean, [Fixnum, String, Integer, Symbol, TrueClass, FalseClass], v, lambda { |v| [0, 1, "true", "false", :true, :false, true, false, "0", "1"].include?(v) })
67
+ end
68
+
69
+ # Requires that the value is a String
70
+ # @param [Any] v The value validated
71
+ def self.validate_string(v)
72
+ DataTypeValidator.validate :string, String, v
73
+ end
74
+
75
+ # Requires that the value is a Float
76
+ # @param [Any] v The value validated
77
+ def self.validate_float(v)
78
+ DataTypeValidator.validate :float, Float, v
79
+ end
80
+
81
+ # Requires that the value is valid pattern type.
82
+ # valid pattern types must be one of :none, :solid, :mediumGray, :darkGray, :lightGray, :darkHorizontal, :darkVertical, :darkDown,
83
+ # :darkUp, :darkGrid, :darkTrellis, :lightHorizontal, :lightVertical, :lightDown, :lightUp, :lightGrid, :lightTrellis, :gray125, or :gray0625.
84
+ # @param [Any] v The value validated
85
+ def self.validate_pattern_type(v)
86
+ RestrictionValidator.validate :pattern_type, [:none, :solid, :mediumGray, :darkGray, :lightGray, :darkHorizontal, :darkVertical, :darkDown, :darkUp, :darkGrid,
87
+ :darkTrellis, :lightHorizontal, :lightVertical, :lightDown, :lightUp, :lightGrid, :lightTrellis, :gray125, :gray0625], v
88
+ end
89
+
90
+ # Requires that the value is a gradient_type.
91
+ # valid types are :linear and :path
92
+ # @param [Any] v The value validated
93
+ def self.validate_gradient_type(v)
94
+ RestrictionValidator.validate :gradient_type, [:linear, :path], v
95
+ end
96
+
97
+ # Requires that the value is a valid horizontal_alignment
98
+ # :general, :left, :center, :right, :fill, :justify, :centerContinuous, :distributed are allowed
99
+ # @param [Any] v The value validated
100
+ def self.validate_horizontal_alignment(v)
101
+ RestrictionValidator.validate :horizontal_alignment, [:general, :left, :center, :right, :fill, :justify, :centerContinuous, :distributed], v
102
+ end
103
+
104
+ # Requires that the value is a valid vertical_alignment
105
+ # :top, :center, :bottom, :justify, :distributed are allowed
106
+ # @param [Any] v The value validated
107
+ def self.validate_vertical_alignment(v)
108
+ RestrictionValidator.validate :vertical_alignment, [:top, :center, :bottom, :justify, :distributed], v
109
+ end
110
+
111
+ # Requires that the value is a valid content_type
112
+ # TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, DRAWING_CT are allowed
113
+ # @param [Any] v The value validated
114
+ def self.validate_content_type(v)
115
+ RestrictionValidator.validate :content_type, [TABLE_CT, WORKBOOK_CT, APP_CT, RELS_CT, STYLES_CT, XML_CT, WORKSHEET_CT, SHARED_STRINGS_CT, CORE_CT, CHART_CT, DRAWING_CT], v
116
+ end
117
+
118
+ # Requires that the value is a valid relationship_type
119
+ # XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R are allowed
120
+ # @param [Any] v The value validated
121
+ def self.validate_relationship_type(v)
122
+ RestrictionValidator.validate :relationship_type, [XML_NS_R, TABLE_R, WORKBOOK_R, WORKSHEET_R, APP_R, RELS_R, CORE_R, STYLES_R, CHART_R, DRAWING_R], v
123
+ end
124
+
125
+ # Requires that the value is a valid table element type
126
+ # :wholeTable, :headerRow, :totalRow, :firstColumn, :lastColumn, :firstRowStripe, :secondRowStripe, :firstColumnStripe, :secondColumnStripe, :firstHeaderCell, :lastHeaderCell, :firstTotalCell, :lastTotalCell, :firstSubtotalColumn, :secondSubtotalColumn, :thirdSubtotalColumn, :firstSubtotalRow, :secondSubtotalRow, :thirdSubtotalRow, :blankRow, :firstColumnSubheading, :secondColumnSubheading, :thirdColumnSubheading, :firstRowSubheading, :secondRowSubheading, :thirdRowSubheading, :pageFieldLabels, :pageFieldValues are allowed
127
+ # @param [Any] v The value validated
128
+ def self.validate_table_element_type(v)
129
+ RestrictionValidator.validate :table_element_type, [:wholeTable, :headerRow, :totalRow, :firstColumn, :lastColumn, :firstRowStripe, :secondRowStripe, :firstColumnStripe, :secondColumnStripe, :firstHeaderCell, :lastHeaderCell, :firstTotalCell, :lastTotalCell, :firstSubtotalColumn, :secondSubtotalColumn, :thirdSubtotalColumn, :firstSubtotalRow, :secondSubtotalRow, :thirdSubtotalRow, :blankRow, :firstColumnSubheading, :secondColumnSubheading, :thirdColumnSubheading, :firstRowSubheading, :secondRowSubheading, :thirdRowSubheading, :pageFieldLabels, :pageFieldValues], v
130
+ end
131
+
132
+ end
@@ -0,0 +1,130 @@
1
+ # -*- coding: utf-8 -*-
2
+ module Axlsx
3
+
4
+ require 'axlsx/workbook/worksheet/cell.rb'
5
+ require 'axlsx/workbook/worksheet/row.rb'
6
+ require 'axlsx/workbook/worksheet/worksheet.rb'
7
+
8
+ # The Workbook class is an xlsx workbook that manages worksheets, charts, drawings and styles.
9
+ # The following parts of the Office Open XML spreadsheet specification are not implimented in this version.
10
+ #
11
+ # bookViews
12
+ # calcPr
13
+ # customWorkbookViews
14
+ # definedNames
15
+ # externalReferences
16
+ # extLst
17
+ # fileRecoveryPr
18
+ # fileSharing
19
+ # fileVersion
20
+ # functionGroups
21
+ # oleSize
22
+ # pivotCaches
23
+ # smartTagPr
24
+ # smartTagTypes
25
+ # webPublishing
26
+ # webPublishObjects
27
+ # workbookProtection
28
+ # workbookPr*
29
+ #
30
+ # *workbookPr is only supported to the extend of date1904
31
+ class Workbook
32
+
33
+ # A collection of worksheets associated with this workbook.
34
+ # @note The recommended way to manage worksheets is add_worksheet
35
+ # @see Workbook#add_worksheet
36
+ # @see Worksheet
37
+ # @return [SimpleTypedList]
38
+ attr_reader :worksheets
39
+
40
+ # A colllection of charts associated with this workbook
41
+ # @note The recommended way to manage charts is Worksheet#add_chart
42
+ # @see Worksheet#add_chart
43
+ # @see Chart
44
+ # @return [SimpleTypedList]
45
+ attr_reader :charts
46
+
47
+ # A colllection of drawings associated with this workbook
48
+ # @note The recommended way to manage drawings is Worksheet#add_chart
49
+ # @see Worksheet#add_chart
50
+ # @see Drawing
51
+ # @return [SimpleTypedList]
52
+ attr_reader :drawings
53
+
54
+ # The styles associated with this workbook
55
+ # @note The recommended way to manage styles is Styles#add_style
56
+ # @see Style#add_style
57
+ # @see Style
58
+ # @return [Styles]
59
+ attr_reader :styles
60
+
61
+ # The workbook relationships. This is managed automatically by the workbook
62
+ # @return [Relationships]
63
+ attr_reader :relationships
64
+
65
+ # Instance level access to the class variable 1904
66
+ # @return [Boolean]
67
+ attr_accessor :date1904
68
+
69
+
70
+ # Indicates if the epoc date for serialization should be 1904. If false, 1900 is used.
71
+ @@date1904 = false
72
+
73
+ # Creates a new Workbook
74
+ # @option options [Boolean] date1904
75
+ def initialize(options={})
76
+ @styles = Styles.new
77
+ @worksheets = SimpleTypedList.new Worksheet
78
+ @drawings = SimpleTypedList.new Drawing
79
+ @charts = SimpleTypedList.new Chart
80
+ self.date1904= options[:date1904] unless options[:date1904].nil?
81
+ end
82
+
83
+ def date1904=(v) Axlsx::validate_boolean v; @@date1904 = v; end
84
+ def date1904() @@date1904; end
85
+
86
+ # Sets the date1904 attribute to the provided boolean
87
+ # @return [Boolean]
88
+ def self.date1904=(v) Axlsx::validate_boolean v; @@date1904 = v; end
89
+
90
+ # retrieves the date1904 attribute
91
+ # @return [Boolean]
92
+ def self.date1904() @@date1904; end
93
+
94
+ # Adds a worksheet to this workbook
95
+ # @return [Worksheet]
96
+ # @option options [String] name The name of the worksheet.
97
+ # @see Worksheet#initialize
98
+ def add_worksheet(options={})
99
+ worksheet = Worksheet.new(self, options)
100
+ yield worksheet if block_given?
101
+ worksheet
102
+ end
103
+
104
+ def relationships
105
+ r = Relationships.new
106
+ @worksheets.each do |sheet|
107
+ r << Relationship.new(WORKSHEET_R, WORKSHEET_PN % (r.size+1))
108
+ end
109
+ r << Relationship.new(STYLES_R, STYLES_PN)
110
+ r
111
+ end
112
+
113
+ # Serializes the workbook document
114
+ # @return [String]
115
+ def to_xml()
116
+ add_worksheet unless worksheets.size > 0
117
+ builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
118
+ xml.workbook(:xmlns => XML_NS, :'xmlns:r' => XML_NS_R) {
119
+ xml.workbookPr(:date1904=>@@date1904)
120
+ xml.sheets {
121
+ @worksheets.each_with_index do |sheet, index|
122
+ xml.sheet(:name=>sheet.name, :sheetId=>index+1, :"r:id"=>sheet.rId)
123
+ end
124
+ }
125
+ }
126
+ end
127
+ builder.to_xml(:indent=>0)
128
+ end
129
+ end
130
+ end
@@ -0,0 +1,184 @@
1
+ module Axlsx
2
+ # A cell in a worksheet.
3
+ # Cell stores inforamation requried to serialize a single worksheet cell to xml. You must provde the Row that the cell belongs to and the cells value. The data type will automatically be determed if you do not specify the :type option. The default style will be applied if you do not supply the :style option. Changing the cell's type will recast the value to the type specified. Altering the cell's value via the property accessor will also automatically cast the provided value to the cell's type.
4
+ # @example Manually creating and manipulating Cell objects
5
+ # ws = Workbook.new.add_worksheet
6
+ # # This is the simple, and recommended way to create cells. Data types will automatically be determined for you.
7
+ # ws.add_row :values => [1,"fish",Time.now]
8
+ #
9
+ # # but you can also do this
10
+ # r = ws.add_row
11
+ # r.add_cell 1
12
+ #
13
+ # # or even this
14
+ # r = ws.add_row
15
+ # c = Cell.new row, 1, :value=>integer
16
+ #
17
+ # # cells can also be accessed via Row#cells. The example here changes the cells type, which will automatically updated the value from 1 to 1.0
18
+ # r.cells.last.type = :float
19
+ #
20
+ # @note The recommended way to generate cells is via Worksheet#add_row
21
+ #
22
+ # @see Worksheet#add_row
23
+ class Cell
24
+
25
+ # The index of the cellXfs item to be applied to this cell.
26
+ # @return [Integer]
27
+ # @see Axlsx::Styles
28
+ attr_accessor :style
29
+
30
+ # The row this cell belongs to.
31
+ # @return [Row]
32
+ attr_reader :row
33
+
34
+ # The cell's data type. Currently only four types are supported, :time, :float, :integer and :string.
35
+ # Changing the type for a cell will recast the value into that type. If no type option is specified in the constructor, the type is
36
+ # automatically determed.
37
+ # @see Cell#cell_type_from_value
38
+ # @return [Symbol] The type of data this cell's value is cast to.
39
+ # @raise [ArgumentExeption] Cell.type must be one of [:time, :float, :integer, :string]
40
+ # @note
41
+ # If the value provided cannot be cast into the type specified, type is changed to :string and the following logic is applied.
42
+ # :string to :integer or :float, type coversions always return 0 or 0.0
43
+ # :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string.
44
+ # No support is currently implemented for parsing time strings.
45
+ #
46
+ attr_accessor :type
47
+
48
+ # The value of this cell.
49
+ # @return casted value based on cell's type attribute.
50
+ attr_accessor :value
51
+
52
+ # @param [Row] row The row this cell belongs to.
53
+ # @param [Any] value The value associated with this cell.
54
+ # @option options [Symbol] type The intended data type for this cell. If not specified the data type will be determined internally based on the vlue provided.
55
+ # @option options [Integer] style The index of the cellXfs item to be applied to this cell. If not specified, the default style (0) will be applied.
56
+ def initialize(row, value="", options={})
57
+ self.row=row
58
+ #reference for validation
59
+ @styles = row.worksheet.workbook.styles
60
+ @type= options[:type] || cell_type_from_value(value)
61
+ self.style = options[:style] || 0
62
+ @value = cast_value(value)
63
+ @row.cells << self
64
+ end
65
+
66
+ # @return [Integer] The index of the cell in the containing row.
67
+ def index
68
+ @row.cells.index(self)
69
+ end
70
+
71
+ # @return [String] The alpha(column)numeric(row) reference for this sell.
72
+ # @example Relative Cell Reference
73
+ # ws.rows.first.cells.first.r #=> "A1"
74
+ def r
75
+ "#{col_ref}#{@row.index+1}"
76
+ end
77
+
78
+ # @return [String] The absolute alpha(column)numeric(row) reference for this sell.
79
+ # @example Absolute Cell Reference
80
+ # ws.rows.first.cells.first.r #=> "$A$1"
81
+ def r_abs
82
+ "$#{r.split('').join('$')}"
83
+ end
84
+
85
+ # @return [Integer] The cellXfs item index applied to this cell.
86
+ # @raise [ArgumentError] Invalid cellXfs id if the value provided is not within cellXfs items range.
87
+ def style=(v)
88
+ Axlsx::validate_unsigned_int(v)
89
+ count = @styles.cellXfs.size
90
+ raise ArgumentError, "Invalid cellXfs id" unless v < count
91
+ @style = v
92
+ end
93
+
94
+ def type=(v)
95
+ RestrictionValidator.validate "Cell.type", [:time, :float, :integer, :string], v
96
+ @type=v
97
+ self.value = @value
98
+ end
99
+
100
+ def value=(v)
101
+ #TODO: consider doing value based type determination first?
102
+ @value = cast_value(v)
103
+ end
104
+
105
+ # Serializes the cell
106
+ # @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
107
+ # @return [String] xml text for the cell
108
+ # @note
109
+ # Shared Strings are not used in this library. All values are set directly in the each sheet.
110
+ def to_xml(xml)
111
+ if @type == :string
112
+ #NOTE not sure why, but xml.t @v renders the text as html entities of unicode data
113
+ xml.c(:r => r, :t=>:inlineStr, :s=>style) { xml.is { xml << "<t>#{value}</t>" } }
114
+ else
115
+ xml.c(:r => r, :s => style) { xml.v value }
116
+ end
117
+ end
118
+
119
+ private
120
+
121
+ # assigns the owning row for this cell.
122
+ def row=(v) DataTypeValidator.validate "Cell.row", Row, v; @row=v end
123
+
124
+ # converts the column index into alphabetical values.
125
+ # @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
126
+ # @return [String]
127
+ def col_ref
128
+ chars = []
129
+ index = self.index
130
+ while index >= 26 do
131
+ chars << ((index % 26) + 65).chr
132
+ index /= 26
133
+ end
134
+ chars << ((chars.empty? ? index : index-1) + 65).chr
135
+ chars.reverse.join
136
+ end
137
+
138
+ # Determines the cell type based on the cell value.
139
+ # @note This is only used when a cell is created but no :type option is specified, the following rules apply:
140
+ # 1. If the value is an instance of Time, the type is set to :time
141
+ # 2. :float and :integer types are determined by regular expression matching.
142
+ # 3. Anything that does not meet either of the above is determined to be :string.
143
+ # @return [Symbol] The determined type
144
+ def cell_type_from_value(v)
145
+ if v.is_a? Time
146
+ :time
147
+ elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
148
+ :integer
149
+ elsif v.to_s.match(/\A[+-]?\d+\.\d+?\Z/) #float
150
+ :float
151
+ else
152
+ :string
153
+ end
154
+ end
155
+
156
+ # Cast the value into this cells data type.
157
+ # @note
158
+ # About Time - Time in OOXML is *different* from what you might expect. The history as to why is interesting, but you can safely assume that if you are generating docs on a mac, you will want to specify Workbook.1904 as true when using time typed values.
159
+ # @see Axlsx#date1904
160
+ def cast_value(v)
161
+ if @type == :time && v.is_a?(Time)
162
+ #todo consider a time parsing method to convert strings to time
163
+ epoc = Workbook.date1904 ? Time.local(1904,1,1,0,0,0,0,v.zone) : Time.local(1900,1,1,0,0,0,0,v.zone)
164
+ ((v - epoc) /60.0/60.0/24.0).to_f
165
+ elsif @type == :float
166
+ v.to_f
167
+ elsif @type == :integer
168
+ v.to_i
169
+ else
170
+ @type = :string
171
+ v.to_s
172
+ # curious as to why this would be the cells responsibility
173
+ # convert your values before passing them in wankers! CGI.unescapeHTML(v.to_s).to_xs
174
+ # to revert, load this once when the gem is loaded.
175
+ # unless String.method_defined? :to_xs
176
+ # require 'fast_xs' #dep
177
+ # class String
178
+ # alias_method :to_xs, :fast_xs
179
+ # end
180
+ # end
181
+ end
182
+ end
183
+ end
184
+ end