axlsx 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/Rakefile +13 -0
- data/lib/axlsx.rb +38 -0
- data/lib/axlsx/content_type/content_type.rb +23 -0
- data/lib/axlsx/content_type/default.rb +32 -0
- data/lib/axlsx/content_type/override.rb +30 -0
- data/lib/axlsx/doc_props/app.rb +148 -0
- data/lib/axlsx/doc_props/core.rb +34 -0
- data/lib/axlsx/drawing/axis.rb +78 -0
- data/lib/axlsx/drawing/bar_3D_chart.rb +138 -0
- data/lib/axlsx/drawing/bar_series.rb +91 -0
- data/lib/axlsx/drawing/cat_axis.rb +58 -0
- data/lib/axlsx/drawing/chart.rb +120 -0
- data/lib/axlsx/drawing/drawing.rb +121 -0
- data/lib/axlsx/drawing/graphic_frame.rb +55 -0
- data/lib/axlsx/drawing/marker.rb +57 -0
- data/lib/axlsx/drawing/pie_3D_chart.rb +59 -0
- data/lib/axlsx/drawing/pie_series.rb +88 -0
- data/lib/axlsx/drawing/scaling.rb +53 -0
- data/lib/axlsx/drawing/series.rb +70 -0
- data/lib/axlsx/drawing/title.rb +69 -0
- data/lib/axlsx/drawing/two_cell_anchor.rb +88 -0
- data/lib/axlsx/drawing/val_axis.rb +34 -0
- data/lib/axlsx/drawing/view_3D.rb +72 -0
- data/lib/axlsx/package.rb +181 -0
- data/lib/axlsx/rels/relationship.rb +43 -0
- data/lib/axlsx/rels/relationships.rb +25 -0
- data/lib/axlsx/stylesheet/border.rb +52 -0
- data/lib/axlsx/stylesheet/border_pr.rb +65 -0
- data/lib/axlsx/stylesheet/cell_alignment.rb +96 -0
- data/lib/axlsx/stylesheet/cell_protection.rb +33 -0
- data/lib/axlsx/stylesheet/cell_style.rb +60 -0
- data/lib/axlsx/stylesheet/color.rb +57 -0
- data/lib/axlsx/stylesheet/fill.rb +31 -0
- data/lib/axlsx/stylesheet/font.rb +128 -0
- data/lib/axlsx/stylesheet/gradient_fill.rb +70 -0
- data/lib/axlsx/stylesheet/gradient_stop.rb +31 -0
- data/lib/axlsx/stylesheet/num_fmt.rb +61 -0
- data/lib/axlsx/stylesheet/pattern_fill.rb +64 -0
- data/lib/axlsx/stylesheet/styles.rb +296 -0
- data/lib/axlsx/stylesheet/table_style.rb +44 -0
- data/lib/axlsx/stylesheet/table_style_element.rb +66 -0
- data/lib/axlsx/stylesheet/table_styles.rb +39 -0
- data/lib/axlsx/stylesheet/xf.rb +117 -0
- data/lib/axlsx/util/constants.rb +189 -0
- data/lib/axlsx/util/simple_typed_list.rb +150 -0
- data/lib/axlsx/util/validators.rb +132 -0
- data/lib/axlsx/workbook/workbook.rb +130 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +184 -0
- data/lib/axlsx/workbook/worksheet/row.rb +92 -0
- data/lib/axlsx/workbook/worksheet/worksheet.rb +194 -0
- data/lib/schema/dc.xsd +118 -0
- data/lib/schema/dcmitype.xsd +50 -0
- data/lib/schema/dcterms.xsd +331 -0
- data/lib/schema/dml-chart.xsd +1499 -0
- data/lib/schema/dml-chartDrawing.xsd +146 -0
- data/lib/schema/dml-compatibility.xsd +14 -0
- data/lib/schema/dml-diagram.xsd +1091 -0
- data/lib/schema/dml-lockedCanvas.xsd +11 -0
- data/lib/schema/dml-main.xsd +3048 -0
- data/lib/schema/dml-picture.xsd +23 -0
- data/lib/schema/dml-spreadsheetDrawing.xsd +185 -0
- data/lib/schema/dml-wordprocessingDrawing.xsd +185 -0
- data/lib/schema/opc-contentTypes.xsd +42 -0
- data/lib/schema/opc-coreProperties.xsd +50 -0
- data/lib/schema/opc-digSig.xsd +49 -0
- data/lib/schema/opc-relationships.xsd +33 -0
- data/lib/schema/pml.xsd +1676 -0
- data/lib/schema/shared-additionalCharacteristics.xsd +28 -0
- data/lib/schema/shared-bibliography.xsd +144 -0
- data/lib/schema/shared-commonSimpleTypes.xsd +166 -0
- data/lib/schema/shared-customXmlDataProperties.xsd +25 -0
- data/lib/schema/shared-customXmlSchemaProperties.xsd +18 -0
- data/lib/schema/shared-documentPropertiesCustom.xsd +59 -0
- data/lib/schema/shared-documentPropertiesExtended.xsd +56 -0
- data/lib/schema/shared-documentPropertiesVariantTypes.xsd +195 -0
- data/lib/schema/shared-math.xsd +582 -0
- data/lib/schema/shared-relationshipReference.xsd +25 -0
- data/lib/schema/sml.xsd +4430 -0
- data/lib/schema/vml-main.xsd +569 -0
- data/lib/schema/vml-officeDrawing.xsd +509 -0
- data/lib/schema/vml-presentationDrawing.xsd +12 -0
- data/lib/schema/vml-spreadsheetDrawing.xsd +108 -0
- data/lib/schema/vml-wordprocessingDrawing.xsd +96 -0
- data/lib/schema/wml.xsd +3644 -0
- data/lib/schema/xml.xsd +117 -0
- data/test/content_type/tc_content_type.rb +81 -0
- data/test/content_type/tc_content_type.rb~ +81 -0
- data/test/content_type/tc_default.rb +40 -0
- data/test/content_type/tc_default.rb~ +40 -0
- data/test/content_type/tc_override.rb +40 -0
- data/test/content_type/tc_override.rb~ +40 -0
- data/test/doc_props/tc_app.rb +19 -0
- data/test/doc_props/tc_app.rb~ +19 -0
- data/test/doc_props/tc_core.rb +34 -0
- data/test/drawing/tc_axis.rb +39 -0
- data/test/drawing/tc_axis.rb~ +0 -0
- data/test/drawing/tc_bar_3D_chart.rb +66 -0
- data/test/drawing/tc_bar_3D_chart.rb~ +4 -0
- data/test/drawing/tc_bar_series.rb +34 -0
- data/test/drawing/tc_bar_series.rb~ +31 -0
- data/test/drawing/tc_cat_axis.rb +32 -0
- data/test/drawing/tc_cat_axis.rb~ +39 -0
- data/test/drawing/tc_chart.rb +59 -0
- data/test/drawing/tc_chart.rb~ +58 -0
- data/test/drawing/tc_drawing.rb +71 -0
- data/test/drawing/tc_graphic_frame.rb +26 -0
- data/test/drawing/tc_graphic_frame.rb~ +21 -0
- data/test/drawing/tc_marker.rb +45 -0
- data/test/drawing/tc_marker.rb~ +26 -0
- data/test/drawing/tc_pie_3D_chart.rb +33 -0
- data/test/drawing/tc_pie_3D_chart.rb~ +58 -0
- data/test/drawing/tc_pie_series.rb +35 -0
- data/test/drawing/tc_pie_series.rb~ +26 -0
- data/test/drawing/tc_scaling.rb +37 -0
- data/test/drawing/tc_scaling.rb~ +45 -0
- data/test/drawing/tc_series.rb +24 -0
- data/test/drawing/tc_series.rb~ +31 -0
- data/test/drawing/tc_title.rb +34 -0
- data/test/drawing/tc_title.rb~ +37 -0
- data/test/drawing/tc_two_cell_anchor.rb +37 -0
- data/test/drawing/tc_two_cell_anchor.rb~ +35 -0
- data/test/drawing/tc_val_axis.rb +20 -0
- data/test/drawing/tc_val_axis.rb~ +32 -0
- data/test/drawing/tc_view_3D.rb +46 -0
- data/test/drawing/tc_view_3D.rb~ +37 -0
- data/test/rels/tc_relationship.rb +16 -0
- data/test/rels/tc_relationship.rb~ +39 -0
- data/test/rels/tc_relationships.rb +32 -0
- data/test/rels/tc_relationships.rb~ +37 -0
- data/test/stylesheet/tc_border.rb +38 -0
- data/test/stylesheet/tc_border.rb~ +31 -0
- data/test/stylesheet/tc_border_pr.rb +33 -0
- data/test/stylesheet/tc_border_pr.rb~ +31 -0
- data/test/stylesheet/tc_cell_alignment.rb +77 -0
- data/test/stylesheet/tc_cell_alignment.rb~ +38 -0
- data/test/stylesheet/tc_cell_protection.rb +30 -0
- data/test/stylesheet/tc_cell_protection.rb~ +77 -0
- data/test/stylesheet/tc_cell_style.rb +58 -0
- data/test/stylesheet/tc_cell_style.rb~ +30 -0
- data/test/stylesheet/tc_color.rb +38 -0
- data/test/stylesheet/tc_color.rb~ +38 -0
- data/test/stylesheet/tc_fill.rb +19 -0
- data/test/stylesheet/tc_fill.rb~ +19 -0
- data/test/stylesheet/tc_font.rb +114 -0
- data/test/stylesheet/tc_font.rb~ +19 -0
- data/test/stylesheet/tc_gradient_fill.rb +65 -0
- data/test/stylesheet/tc_gradient_fill.rb~ +114 -0
- data/test/stylesheet/tc_gradient_stop.rb +32 -0
- data/test/stylesheet/tc_gradient_stop.rb~ +65 -0
- data/test/stylesheet/tc_num_fmt.rb +31 -0
- data/test/stylesheet/tc_num_fmt.rb~ +32 -0
- data/test/stylesheet/tc_pattern_fill.rb +38 -0
- data/test/stylesheet/tc_pattern_fill.rb~ +31 -0
- data/test/stylesheet/tc_styles.rb +64 -0
- data/test/stylesheet/tc_table_style.rb +37 -0
- data/test/stylesheet/tc_table_style.rb~ +38 -0
- data/test/stylesheet/tc_table_style_element.rb +37 -0
- data/test/stylesheet/tc_table_style_element.rb~ +37 -0
- data/test/stylesheet/tc_table_styles.rb +30 -0
- data/test/stylesheet/tc_table_styles.rb~ +37 -0
- data/test/stylesheet/tc_xf.rb +121 -0
- data/test/stylesheet/tc_xf.rb~ +30 -0
- data/test/tc_app.rb~ +19 -0
- data/test/tc_border_pr.rb~ +21 -0
- data/test/tc_package.rb +70 -0
- data/test/tc_package.rb~ +64 -0
- data/test/tc_pie_3D_chart.rb~ +66 -0
- data/test/tc_relationships.rb~ +37 -0
- data/test/tc_series.rb~ +31 -0
- data/test/tc_styles.rb~ +64 -0
- data/test/tc_validators.rb~ +77 -0
- data/test/tc_worksheet.rb~ +85 -0
- data/test/util/tc_simple_typed_list.rb +66 -0
- data/test/util/tc_validators.rb +76 -0
- data/test/workbook/tc_workbook.rb +53 -0
- data/test/workbook/worksheet/tc_cell.rb +78 -0
- data/test/workbook/worksheet/tc_row.rb +30 -0
- data/test/workbook/worksheet/tc_worksheet.rb +85 -0
- 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
|