axlsx 1.0.12 → 1.0.14
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.
- data/README.md +165 -134
- data/examples/example.rb +133 -153
- data/lib/axlsx/#cfb.xlsx# +0 -0
- data/lib/axlsx/content_type/content_type.rb +23 -0
- data/lib/axlsx/content_type/default.rb +37 -0
- data/lib/axlsx/content_type/override.rb +37 -0
- data/lib/axlsx/doc_props/app.rb +178 -0
- data/lib/axlsx/doc_props/core.rb +34 -0
- data/lib/axlsx/drawing/axis.rb +93 -0
- data/lib/axlsx/drawing/bar_3D_chart.rb +136 -0
- data/lib/axlsx/drawing/bar_series.rb +64 -0
- data/lib/axlsx/drawing/cat_axis.rb +63 -0
- data/lib/axlsx/drawing/cat_axis_data.rb +35 -0
- data/lib/axlsx/drawing/chart.rb +193 -0
- data/lib/axlsx/drawing/drawing.rb +137 -0
- data/lib/axlsx/drawing/graphic_frame.rb +52 -0
- data/lib/axlsx/drawing/line_3D_chart.rb +114 -0
- data/lib/axlsx/drawing/line_series.rb +46 -0
- data/lib/axlsx/drawing/marker.rb +61 -0
- data/lib/axlsx/drawing/one_cell_anchor.rb +89 -0
- data/lib/axlsx/drawing/pic.rb +153 -0
- data/lib/axlsx/drawing/picture_locking.rb +72 -0
- data/lib/axlsx/drawing/picture_locking.rb~ +36 -0
- data/lib/axlsx/drawing/pie_3D_chart.rb +41 -0
- data/lib/axlsx/drawing/pie_series.rb +56 -0
- data/lib/axlsx/drawing/scaling.rb +59 -0
- data/lib/axlsx/drawing/ser_axis.rb +45 -0
- data/lib/axlsx/drawing/series.rb +71 -0
- data/lib/axlsx/drawing/series_title.rb +22 -0
- data/lib/axlsx/drawing/title.rb +65 -0
- data/lib/axlsx/drawing/two_cell_anchor.rb +76 -0
- data/lib/axlsx/drawing/val_axis.rb +34 -0
- data/lib/axlsx/drawing/val_axis_data.rb +26 -0
- data/lib/axlsx/drawing/view_3D.rb +85 -0
- data/lib/axlsx/package.rb +223 -0
- data/lib/axlsx/rels/relationship.rb +44 -0
- data/lib/axlsx/rels/relationships.rb +25 -0
- data/lib/axlsx/stylesheet/border.rb +57 -0
- data/lib/axlsx/stylesheet/border_pr.rb +68 -0
- data/lib/axlsx/stylesheet/cell_alignment.rb +105 -0
- data/lib/axlsx/stylesheet/cell_protection.rb +36 -0
- data/lib/axlsx/stylesheet/cell_style.rb +65 -0
- data/lib/axlsx/stylesheet/color.rb +69 -0
- data/lib/axlsx/stylesheet/fill.rb +32 -0
- data/lib/axlsx/stylesheet/font.rb +139 -0
- data/lib/axlsx/stylesheet/gradient_fill.rb +76 -0
- data/lib/axlsx/stylesheet/gradient_stop.rb +33 -0
- data/lib/axlsx/stylesheet/num_fmt.rb +63 -0
- data/lib/axlsx/stylesheet/pattern_fill.rb +66 -0
- data/lib/axlsx/stylesheet/styles.rb +298 -0
- data/lib/axlsx/stylesheet/table_style.rb +47 -0
- data/lib/axlsx/stylesheet/table_style_element.rb +71 -0
- data/lib/axlsx/stylesheet/table_styles.rb +39 -0
- data/lib/axlsx/stylesheet/xf.rb +138 -0
- data/lib/axlsx/util/constants.rb +216 -0
- data/lib/axlsx/util/ms_off_crypto.rb +88 -0
- data/lib/axlsx/util/ms_off_crypto.rb~ +3 -0
- data/lib/axlsx/util/ms_offcrypto.rb~ +0 -0
- data/lib/axlsx/util/parser.rb +43 -0
- data/lib/axlsx/util/parser.rb~ +6 -0
- data/lib/axlsx/util/simple_typed_list.rb +160 -0
- data/lib/axlsx/util/validators.rb +132 -0
- data/lib/axlsx/version.rb +4 -0
- data/lib/axlsx/workbook/workbook.rb +161 -0
- data/lib/axlsx/workbook/worksheet/cell.rb +350 -0
- data/lib/axlsx/workbook/worksheet/row.rb +107 -0
- data/lib/axlsx/workbook/worksheet/worksheet.rb +335 -0
- data/lib/axlsx.rb +59 -0
- data/test/drawing/tc_axis.rb +1 -1
- data/test/drawing/tc_cat_axis.rb +1 -1
- data/test/drawing/tc_line_series.tc~ +34 -0
- data/test/drawing/tc_picture_locking.rb~ +77 -0
- data/test/tc_package.rb +10 -0
- data/test/workbook/worksheet/tc_cell.rb +15 -0
- data/test/workbook/worksheet/tc_worksheet.rb +22 -1
- metadata +117 -5
- data/examples/follow_20111202.xlsx +0 -0
|
@@ -0,0 +1,161 @@
|
|
|
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 images associated with this workbook
|
|
48
|
+
# @note The recommended way to manage images is Worksheet#add_image
|
|
49
|
+
# @see Worksheet#add_image
|
|
50
|
+
# @see Pic
|
|
51
|
+
# @return [SimpleTypedList]
|
|
52
|
+
attr_reader :images
|
|
53
|
+
|
|
54
|
+
# A colllection of drawings associated with this workbook
|
|
55
|
+
# @note The recommended way to manage drawings is Worksheet#add_chart
|
|
56
|
+
# @see Worksheet#add_chart
|
|
57
|
+
# @see Drawing
|
|
58
|
+
# @return [SimpleTypedList]
|
|
59
|
+
attr_reader :drawings
|
|
60
|
+
|
|
61
|
+
# The styles associated with this workbook
|
|
62
|
+
# @note The recommended way to manage styles is Styles#add_style
|
|
63
|
+
# @see Style#add_style
|
|
64
|
+
# @see Style
|
|
65
|
+
# @return [Styles]
|
|
66
|
+
def styles
|
|
67
|
+
yield @styles if block_given?
|
|
68
|
+
@styles
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
# Indicates if the epoc date for serialization should be 1904. If false, 1900 is used.
|
|
73
|
+
@@date1904 = false
|
|
74
|
+
|
|
75
|
+
# lets come back to this later when we are ready for parsing.
|
|
76
|
+
#def self.parse entry
|
|
77
|
+
# io = entry.get_input_stream
|
|
78
|
+
# w = self.new
|
|
79
|
+
# w.parser_xml = Nokogiri::XML(io.read)
|
|
80
|
+
# w.parse_string :date1904, "//xmlns:workbookPr/@date1904"
|
|
81
|
+
# w
|
|
82
|
+
#end
|
|
83
|
+
|
|
84
|
+
# Creates a new Workbook
|
|
85
|
+
# @option options [Boolean] date1904
|
|
86
|
+
def initialize(options={})
|
|
87
|
+
@styles = Styles.new
|
|
88
|
+
@worksheets = SimpleTypedList.new Worksheet
|
|
89
|
+
@drawings = SimpleTypedList.new Drawing
|
|
90
|
+
@charts = SimpleTypedList.new Chart
|
|
91
|
+
@images = SimpleTypedList.new Pic
|
|
92
|
+
self.date1904= options[:date1904] unless options[:date1904].nil?
|
|
93
|
+
yield self if block_given?
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Instance level access to the class variable 1904
|
|
97
|
+
# @return [Boolean]
|
|
98
|
+
def date1904() @@date1904; end
|
|
99
|
+
|
|
100
|
+
# see @date1904
|
|
101
|
+
def date1904=(v) Axlsx::validate_boolean v; @@date1904 = v; end
|
|
102
|
+
|
|
103
|
+
# Sets the date1904 attribute to the provided boolean
|
|
104
|
+
# @return [Boolean]
|
|
105
|
+
def self.date1904=(v) Axlsx::validate_boolean v; @@date1904 = v; end
|
|
106
|
+
|
|
107
|
+
# retrieves the date1904 attribute
|
|
108
|
+
# @return [Boolean]
|
|
109
|
+
def self.date1904() @@date1904; end
|
|
110
|
+
|
|
111
|
+
# Adds a worksheet to this workbook
|
|
112
|
+
# @return [Worksheet]
|
|
113
|
+
# @option options [String] name The name of the worksheet.
|
|
114
|
+
# @see Worksheet#initialize
|
|
115
|
+
def add_worksheet(options={})
|
|
116
|
+
worksheet = Worksheet.new(self, options)
|
|
117
|
+
yield worksheet if block_given?
|
|
118
|
+
worksheet
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# The workbook relationships. This is managed automatically by the workbook
|
|
122
|
+
# @return [Relationships]
|
|
123
|
+
def relationships
|
|
124
|
+
r = Relationships.new
|
|
125
|
+
@worksheets.each do |sheet|
|
|
126
|
+
r << Relationship.new(WORKSHEET_R, WORKSHEET_PN % (r.size+1))
|
|
127
|
+
end
|
|
128
|
+
r << Relationship.new(STYLES_R, STYLES_PN)
|
|
129
|
+
r
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
# returns a range of cells in a worksheet
|
|
133
|
+
# @param [String] cell_def The excel style reference defining the worksheet and cells. The range must specify the sheet to
|
|
134
|
+
# retrieve the cells from. e.g. range('Sheet1!A1:B2') will return an array of four cells [A1, A2, B1, B2] while range('Sheet1!A1') will return a single Cell.
|
|
135
|
+
# @return [Cell, Array]
|
|
136
|
+
def [](cell_def)
|
|
137
|
+
sheet_name = cell_def.split('!')[0] if cell_def.match('!')
|
|
138
|
+
worksheet = self.worksheets.select { |s| s.name == sheet_name }.first
|
|
139
|
+
raise ArgumentError, 'Unknown Sheet' unless sheet_name && worksheet.is_a?(Worksheet)
|
|
140
|
+
worksheet[cell_def.gsub(/.+!/,"")]
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
# Serializes the workbook document
|
|
144
|
+
# @return [String]
|
|
145
|
+
def to_xml()
|
|
146
|
+
add_worksheet unless worksheets.size > 0
|
|
147
|
+
builder = Nokogiri::XML::Builder.new(:encoding => ENCODING) do |xml|
|
|
148
|
+
xml.workbook(:xmlns => XML_NS, :'xmlns:r' => XML_NS_R) {
|
|
149
|
+
xml.workbookPr(:date1904=>@@date1904)
|
|
150
|
+
#<x:workbookProtection workbookPassword="xsd:hexBinary data" lockStructure="1" lockWindows="1" />
|
|
151
|
+
xml.sheets {
|
|
152
|
+
@worksheets.each_with_index do |sheet, index|
|
|
153
|
+
xml.sheet(:name=>sheet.name, :sheetId=>index+1, :"r:id"=>sheet.rId)
|
|
154
|
+
end
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
end
|
|
158
|
+
builder.to_xml(:indent=>0)
|
|
159
|
+
end
|
|
160
|
+
end
|
|
161
|
+
end
|
|
@@ -0,0 +1,350 @@
|
|
|
1
|
+
# -*- coding: utf-8 -*-
|
|
2
|
+
module Axlsx
|
|
3
|
+
# A cell in a worksheet.
|
|
4
|
+
# 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.
|
|
5
|
+
# @example Manually creating and manipulating Cell objects
|
|
6
|
+
# ws = Workbook.new.add_worksheet
|
|
7
|
+
# # This is the simple, and recommended way to create cells. Data types will automatically be determined for you.
|
|
8
|
+
# ws.add_row :values => [1,"fish",Time.now]
|
|
9
|
+
#
|
|
10
|
+
# # but you can also do this
|
|
11
|
+
# r = ws.add_row
|
|
12
|
+
# r.add_cell 1
|
|
13
|
+
#
|
|
14
|
+
# # or even this
|
|
15
|
+
# r = ws.add_row
|
|
16
|
+
# c = Cell.new row, 1, :value=>integer
|
|
17
|
+
#
|
|
18
|
+
# # 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
|
|
19
|
+
# r.cells.last.type = :float
|
|
20
|
+
#
|
|
21
|
+
# @note The recommended way to generate cells is via Worksheet#add_row
|
|
22
|
+
#
|
|
23
|
+
# @see Worksheet#add_row
|
|
24
|
+
class Cell
|
|
25
|
+
|
|
26
|
+
# The index of the cellXfs item to be applied to this cell.
|
|
27
|
+
# @return [Integer]
|
|
28
|
+
# @see Axlsx::Styles
|
|
29
|
+
attr_reader :style
|
|
30
|
+
|
|
31
|
+
# The row this cell belongs to.
|
|
32
|
+
# @return [Row]
|
|
33
|
+
attr_reader :row
|
|
34
|
+
|
|
35
|
+
# The cell's data type. Currently only four types are supported, :time, :float, :integer and :string.
|
|
36
|
+
# 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
|
|
37
|
+
# automatically determed.
|
|
38
|
+
# @see Cell#cell_type_from_value
|
|
39
|
+
# @return [Symbol] The type of data this cell's value is cast to.
|
|
40
|
+
# @raise [ArgumentExeption] Cell.type must be one of [:time, :float, :integer, :string]
|
|
41
|
+
# @note
|
|
42
|
+
# If the value provided cannot be cast into the type specified, type is changed to :string and the following logic is applied.
|
|
43
|
+
# :string to :integer or :float, type coversions always return 0 or 0.0
|
|
44
|
+
# :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string.
|
|
45
|
+
# No support is currently implemented for parsing time strings.
|
|
46
|
+
attr_reader :type
|
|
47
|
+
# @see type
|
|
48
|
+
def type=(v)
|
|
49
|
+
RestrictionValidator.validate "Cell.type", [:time, :float, :integer, :string], v
|
|
50
|
+
@type=v
|
|
51
|
+
self.value = @value
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
# The value of this cell.
|
|
56
|
+
# @return [String, Integer, Float, Time] casted value based on cell's type attribute.
|
|
57
|
+
attr_reader :value
|
|
58
|
+
# @see value
|
|
59
|
+
def value=(v)
|
|
60
|
+
#TODO: consider doing value based type determination first?
|
|
61
|
+
@value = cast_value(v)
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# The inline font_name property for the cell
|
|
65
|
+
# @return [String]
|
|
66
|
+
attr_reader :font_name
|
|
67
|
+
# @see font_name
|
|
68
|
+
def font_name=(v) Axlsx::validate_string(v); @font_name = v; end
|
|
69
|
+
|
|
70
|
+
# The inline charset property for the cell
|
|
71
|
+
# @return [String]
|
|
72
|
+
attr_reader :charset
|
|
73
|
+
# @see charset
|
|
74
|
+
def charset=(v) Axlsx::validate_unsigned_int(v); @charset = v; end
|
|
75
|
+
|
|
76
|
+
# The inline family property for the cell
|
|
77
|
+
# @return [String]
|
|
78
|
+
attr_reader :family
|
|
79
|
+
# @see family
|
|
80
|
+
def family=(v) Axlsx::validate_string(v); @family = v; end
|
|
81
|
+
|
|
82
|
+
# The inline bold property for the cell
|
|
83
|
+
# @return [Boolean]
|
|
84
|
+
attr_reader :b
|
|
85
|
+
# @see b
|
|
86
|
+
def b=(v) Axlsx::validate_boolean(v); @b = v; end
|
|
87
|
+
|
|
88
|
+
# The inline italic property for the cell
|
|
89
|
+
# @return [Boolean]
|
|
90
|
+
attr_reader :i
|
|
91
|
+
# @see i
|
|
92
|
+
def i=(v) Axlsx::validate_boolean(v); @i = v; end
|
|
93
|
+
|
|
94
|
+
# The inline strike property for the cell
|
|
95
|
+
# @return [Boolean]
|
|
96
|
+
attr_reader :strike
|
|
97
|
+
# @see strike
|
|
98
|
+
def strike=(v) Axlsx::validate_boolean(v); @strike = v; end
|
|
99
|
+
|
|
100
|
+
# The inline outline property for the cell
|
|
101
|
+
# @return [Boolean]
|
|
102
|
+
attr_reader :outline
|
|
103
|
+
# @see outline
|
|
104
|
+
def outline=(v) Axlsx::validate_boolean(v); @outline = v; end
|
|
105
|
+
|
|
106
|
+
# The inline shadow property for the cell
|
|
107
|
+
# @return [Boolean]
|
|
108
|
+
attr_reader :shadow
|
|
109
|
+
# @see shadow
|
|
110
|
+
def shadow=(v) Axlsx::validate_boolean(v); @shadow = v; end
|
|
111
|
+
|
|
112
|
+
# The inline condense property for the cell
|
|
113
|
+
# @return [Boolean]
|
|
114
|
+
attr_reader :condense
|
|
115
|
+
# @see condense
|
|
116
|
+
def condense=(v) Axlsx::validate_boolean(v); @condense = v; end
|
|
117
|
+
|
|
118
|
+
# The inline extend property for the cell
|
|
119
|
+
# @return [Boolean]
|
|
120
|
+
attr_reader :extend
|
|
121
|
+
# @see extend
|
|
122
|
+
def extend=(v) Axlsx::validate_boolean(v); @extend = v; end
|
|
123
|
+
|
|
124
|
+
# The inline underline property for the cell
|
|
125
|
+
# @return [Boolean]
|
|
126
|
+
attr_reader :u
|
|
127
|
+
# @see u
|
|
128
|
+
def u=(v) Axlsx::validate_boolean(v); @u = v; end
|
|
129
|
+
|
|
130
|
+
# The inline color property for the cell
|
|
131
|
+
# @return [Color]
|
|
132
|
+
attr_reader :color
|
|
133
|
+
# @param [String] The 8 character representation for an rgb color #FFFFFFFF"
|
|
134
|
+
def color=(v)
|
|
135
|
+
@color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
# The inline sz property for the cell
|
|
139
|
+
# @return [Boolean]
|
|
140
|
+
attr_reader :sz
|
|
141
|
+
# @see sz
|
|
142
|
+
def sz=(v) Axlsx::validate_unsigned_int(v); @sz = v; end
|
|
143
|
+
|
|
144
|
+
# The inline vertical alignment property for the cell
|
|
145
|
+
# this must be one of [:baseline, :subscript, :superscript]
|
|
146
|
+
# @return [Symbol]
|
|
147
|
+
attr_reader :vertAlign
|
|
148
|
+
# @see vertAlign
|
|
149
|
+
def vertAlign=(v) RestrictionValidator.validate "Cell.vertAlign", [:baseline, :subscript, :superscript], v; @vertAlign = v; end
|
|
150
|
+
|
|
151
|
+
# The inline scheme property for the cell
|
|
152
|
+
# this must be one of [:none, major, minor]
|
|
153
|
+
# @return [Symbol]
|
|
154
|
+
attr_reader :scheme
|
|
155
|
+
# @see scheme
|
|
156
|
+
def scheme=(v) RestrictionValidator.validate "Cell.schema", [:none, :major, :minor], v; @scheme = v; end
|
|
157
|
+
|
|
158
|
+
# @param [Row] row The row this cell belongs to.
|
|
159
|
+
# @param [Any] value The value associated with this cell.
|
|
160
|
+
# @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.
|
|
161
|
+
# @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.
|
|
162
|
+
# @option options [String] font_name
|
|
163
|
+
# @option options [Integer] charset
|
|
164
|
+
# @option options [String] family
|
|
165
|
+
# @option options [Boolean] b
|
|
166
|
+
# @option options [Boolean] i
|
|
167
|
+
# @option options [Boolean] strike
|
|
168
|
+
# @option options [Boolean] outline
|
|
169
|
+
# @option options [Boolean] shadow
|
|
170
|
+
# @option options [Boolean] condense
|
|
171
|
+
# @option options [Boolean] extend
|
|
172
|
+
# @option options [Boolean] u
|
|
173
|
+
# @option options [Symbol] vertAlign must be one of :baseline, :subscript, :superscript
|
|
174
|
+
# @option options [Integer] sz
|
|
175
|
+
# @option options [String] color an 8 letter rgb specification
|
|
176
|
+
# @option options [Symbol] scheme must be one of :none, major, :minor
|
|
177
|
+
def initialize(row, value="", options={})
|
|
178
|
+
self.row=row
|
|
179
|
+
@styles = row.worksheet.workbook.styles
|
|
180
|
+
@style = 0
|
|
181
|
+
@type = cell_type_from_value(value)
|
|
182
|
+
@row.cells << self
|
|
183
|
+
options.each do |o|
|
|
184
|
+
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
185
|
+
end
|
|
186
|
+
@value = cast_value(value)
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
# @return [Integer] The index of the cell in the containing row.
|
|
190
|
+
def index
|
|
191
|
+
@row.cells.index(self)
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @return [String] The alpha(column)numeric(row) reference for this sell.
|
|
195
|
+
# @example Relative Cell Reference
|
|
196
|
+
# ws.rows.first.cells.first.r #=> "A1"
|
|
197
|
+
def r
|
|
198
|
+
"#{col_ref}#{@row.index+1}"
|
|
199
|
+
end
|
|
200
|
+
|
|
201
|
+
# @return [String] The absolute alpha(column)numeric(row) reference for this sell.
|
|
202
|
+
# @example Absolute Cell Reference
|
|
203
|
+
# ws.rows.first.cells.first.r #=> "$A$1"
|
|
204
|
+
def r_abs
|
|
205
|
+
"$#{r.split('').join('$')}"
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
# @return [Integer] The cellXfs item index applied to this cell.
|
|
209
|
+
# @raise [ArgumentError] Invalid cellXfs id if the value provided is not within cellXfs items range.
|
|
210
|
+
def style=(v)
|
|
211
|
+
Axlsx::validate_unsigned_int(v)
|
|
212
|
+
count = @styles.cellXfs.size
|
|
213
|
+
raise ArgumentError, "Invalid cellXfs id" unless v < count
|
|
214
|
+
@style = v
|
|
215
|
+
end
|
|
216
|
+
|
|
217
|
+
# @return [Array] of x/y coordinates in the cheet for this cell.
|
|
218
|
+
def pos
|
|
219
|
+
[index, row.index]
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# Merges all the cells in a range created between this cell and the cell or string name for a cell provided
|
|
223
|
+
# @see worksheet.merge_cells
|
|
224
|
+
# @param [Cell, String] target The last cell, or str ref for the cell in the merge range
|
|
225
|
+
def merge(target)
|
|
226
|
+
range_end = if target.is_a?(String)
|
|
227
|
+
target
|
|
228
|
+
elsif(target.is_a?(Cell))
|
|
229
|
+
target.r
|
|
230
|
+
end
|
|
231
|
+
self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil?
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
# Serializes the cell
|
|
235
|
+
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
|
236
|
+
# @return [String] xml text for the cell
|
|
237
|
+
# @note
|
|
238
|
+
# Shared Strings are not used in this library. All values are set directly in the each sheet.
|
|
239
|
+
def to_xml(xml)
|
|
240
|
+
|
|
241
|
+
# however nokogiri does a nice 'force_encoding' which we shall remove!
|
|
242
|
+
if @type == :string
|
|
243
|
+
#parse formula
|
|
244
|
+
if @value.start_with?('=')
|
|
245
|
+
xml.c(:r => r, :t=>:str, :s=>style) {
|
|
246
|
+
xml.f @value.to_s.gsub('=', '')
|
|
247
|
+
}
|
|
248
|
+
else
|
|
249
|
+
#parse standard string
|
|
250
|
+
#xml.c(:r => r, :t=>:inlineStr, :s=>style) {
|
|
251
|
+
# xml.is { xml.t @value.to_s }
|
|
252
|
+
#}
|
|
253
|
+
#parse styled string
|
|
254
|
+
xml.c(:r => r, :s=>style, :t => :inlineStr) {
|
|
255
|
+
xml.is {
|
|
256
|
+
xml.r {
|
|
257
|
+
xml.rPr {
|
|
258
|
+
xml.rFont(:val=>@font_name) if @font_name
|
|
259
|
+
xml.charset(:val=>@charset) if @charset
|
|
260
|
+
xml.family(:val=>@family) if @family
|
|
261
|
+
xml.b(:val=>@b) if @b
|
|
262
|
+
xml.i(:val=>@i) if @i
|
|
263
|
+
xml.strike(:val=>@strike) if @strike
|
|
264
|
+
xml.outline(:val=>@outline) if @outline
|
|
265
|
+
xml.shadow(:val=>@shadow) if @shadow
|
|
266
|
+
xml.condense(:val=>@condense) if @condense
|
|
267
|
+
xml.extend(:val=>@extend) if @extend
|
|
268
|
+
@color.to_xml(xml) if @color
|
|
269
|
+
xml.sz(:val=>@sz) if @sz
|
|
270
|
+
xml.u(:val=>@u) if @u
|
|
271
|
+
# :baseline, :subscript, :superscript
|
|
272
|
+
xml.vertAlign(:val=>@vertAlign) if @verAlign
|
|
273
|
+
# :none, major, :minor
|
|
274
|
+
xml.scheme(:val=>@scheme) if @scheme
|
|
275
|
+
}
|
|
276
|
+
xml.t @value.to_s
|
|
277
|
+
}
|
|
278
|
+
}
|
|
279
|
+
}
|
|
280
|
+
end
|
|
281
|
+
elsif @type == :time
|
|
282
|
+
# Using hardcoded offsets here as some operating systems will not except a 'negative' offset from the ruby epoc.
|
|
283
|
+
# (1970)
|
|
284
|
+
epoc1900 = -2209021200 #Time.local(1900, 1, 1)
|
|
285
|
+
epoc1904 = -2082877200 #Time.local(1904, 1, 1)
|
|
286
|
+
epoc = Workbook.date1904 ? epoc1904 : epoc1900
|
|
287
|
+
v = ((@value.localtime.to_f - epoc) /60.0/60.0/24.0).to_f
|
|
288
|
+
xml.c(:r => r, :s => style) { xml.v v }
|
|
289
|
+
else
|
|
290
|
+
xml.c(:r => r, :s => style) { xml.v value }
|
|
291
|
+
end
|
|
292
|
+
end
|
|
293
|
+
|
|
294
|
+
|
|
295
|
+
private
|
|
296
|
+
|
|
297
|
+
# assigns the owning row for this cell.
|
|
298
|
+
def row=(v) DataTypeValidator.validate "Cell.row", Row, v; @row=v end
|
|
299
|
+
|
|
300
|
+
# converts the column index into alphabetical values.
|
|
301
|
+
# @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
|
|
302
|
+
# @return [String]
|
|
303
|
+
def col_ref
|
|
304
|
+
chars = []
|
|
305
|
+
index = self.index
|
|
306
|
+
while index >= 26 do
|
|
307
|
+
chars << ((index % 26) + 65).chr
|
|
308
|
+
index /= 26
|
|
309
|
+
end
|
|
310
|
+
chars << ((chars.empty? ? index : index-1) + 65).chr
|
|
311
|
+
chars.reverse.join
|
|
312
|
+
end
|
|
313
|
+
|
|
314
|
+
# Determines the cell type based on the cell value.
|
|
315
|
+
# @note This is only used when a cell is created but no :type option is specified, the following rules apply:
|
|
316
|
+
# 1. If the value is an instance of Time, the type is set to :time
|
|
317
|
+
# 2. :float and :integer types are determined by regular expression matching.
|
|
318
|
+
# 3. Anything that does not meet either of the above is determined to be :string.
|
|
319
|
+
# @return [Symbol] The determined type
|
|
320
|
+
def cell_type_from_value(v)
|
|
321
|
+
if v.is_a? Time
|
|
322
|
+
:time
|
|
323
|
+
elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
|
|
324
|
+
:integer
|
|
325
|
+
elsif v.to_s.match(/\A[+-]?\d+\.\d+?\Z/) #float
|
|
326
|
+
:float
|
|
327
|
+
else
|
|
328
|
+
:string
|
|
329
|
+
end
|
|
330
|
+
end
|
|
331
|
+
|
|
332
|
+
# Cast the value into this cells data type.
|
|
333
|
+
# @note
|
|
334
|
+
# 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.
|
|
335
|
+
# @see Axlsx#date1904
|
|
336
|
+
def cast_value(v)
|
|
337
|
+
if (@type == :time && v.is_a?(Time)) || (@type == :time && v.respond_to?(:to_time))
|
|
338
|
+
self.style = STYLE_DATE if self.style == 0
|
|
339
|
+
v.respond_to?(:to_time) ? v.to_time : v
|
|
340
|
+
elsif @type == :float
|
|
341
|
+
v.to_f
|
|
342
|
+
elsif @type == :integer
|
|
343
|
+
v.to_i
|
|
344
|
+
else
|
|
345
|
+
@type = :string
|
|
346
|
+
v.to_s
|
|
347
|
+
end
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
end
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
module Axlsx
|
|
2
|
+
# A Row is a single row in a worksheet.
|
|
3
|
+
# @note The recommended way to manage rows and cells is to use Worksheet#add_row
|
|
4
|
+
# @see Worksheet#add_row
|
|
5
|
+
class Row
|
|
6
|
+
|
|
7
|
+
# The worksheet this row belongs to
|
|
8
|
+
# @return [Worksheet]
|
|
9
|
+
attr_reader :worksheet
|
|
10
|
+
|
|
11
|
+
# The cells this row holds
|
|
12
|
+
# @return [SimpleTypedList]
|
|
13
|
+
attr_reader :cells
|
|
14
|
+
|
|
15
|
+
# Creates a new row. New Cell objects are created based on the values, types and style options.
|
|
16
|
+
# A new cell is created for each item in the values array. style and types options are applied as follows:
|
|
17
|
+
# If the types option is defined and is a symbol it is applied to all the cells created.
|
|
18
|
+
# If the types option is an array, cell types are applied by index for each cell
|
|
19
|
+
# If the types option is not set, the cell will automatically determine its type.
|
|
20
|
+
# If the style option is defined and is an Integer, it is applied to all cells created.
|
|
21
|
+
# If the style option is an array, style is applied by index for each cell.
|
|
22
|
+
# If the style option is not defined, the default style (0) is applied to each cell.
|
|
23
|
+
# @param [Worksheet] worksheet
|
|
24
|
+
# @option options [Array] values
|
|
25
|
+
# @option options [Array, Symbol] types
|
|
26
|
+
# @option options [Array, Integer] style
|
|
27
|
+
# @see Row#array_to_cells
|
|
28
|
+
# @see Cell
|
|
29
|
+
def initialize(worksheet, values=[], options={})
|
|
30
|
+
self.worksheet = worksheet
|
|
31
|
+
@cells = SimpleTypedList.new Cell
|
|
32
|
+
@worksheet.rows << self
|
|
33
|
+
array_to_cells(values, options)
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
# The index of this row in the worksheet
|
|
37
|
+
# @return [Integer]
|
|
38
|
+
def index
|
|
39
|
+
worksheet.rows.index(self)
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# Serializes the row
|
|
43
|
+
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
|
44
|
+
# @return [String]
|
|
45
|
+
def to_xml(xml)
|
|
46
|
+
xml.row(:r => index+1) { @cells.each { |cell| cell.to_xml(xml) } }
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
# Adds a singel sell to the row based on the data provided and updates the worksheet's autofit data.
|
|
50
|
+
# @return [Cell]
|
|
51
|
+
def add_cell(value="", options={})
|
|
52
|
+
c = Cell.new(self, value, options)
|
|
53
|
+
update_auto_fit_data
|
|
54
|
+
c
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# sets the style for every cell in this row
|
|
58
|
+
def style=(style)
|
|
59
|
+
cells.each_with_index do | cell, index |
|
|
60
|
+
s = style.is_a?(Array) ? style[index] : style
|
|
61
|
+
cell.style = s
|
|
62
|
+
end
|
|
63
|
+
end
|
|
64
|
+
|
|
65
|
+
# returns the cells in this row as an array
|
|
66
|
+
# This lets us transpose the rows into columns
|
|
67
|
+
# @return [Array]
|
|
68
|
+
def to_ary
|
|
69
|
+
@cells.to_ary
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
private
|
|
73
|
+
|
|
74
|
+
# assigns the owning worksheet for this row
|
|
75
|
+
def worksheet=(v) DataTypeValidator.validate "Row.worksheet", Worksheet, v; @worksheet=v; end
|
|
76
|
+
|
|
77
|
+
# Tell the worksheet to update autofit data for the columns based on this row's cells.
|
|
78
|
+
# @return [SimpleTypedList]
|
|
79
|
+
def update_auto_fit_data
|
|
80
|
+
worksheet.send(:update_auto_fit_data, self.cells)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# Converts values, types, and style options into cells and associates them with this row.
|
|
85
|
+
# A new cell is created for each item in the values array.
|
|
86
|
+
# If value option is defined and is a symbol it is applied to all the cells created.
|
|
87
|
+
# If the value option is an array, cell types are applied by index for each cell
|
|
88
|
+
# If the style option is defined and is an Integer, it is applied to all cells created.
|
|
89
|
+
# If the style option is an array, style is applied by index for each cell.
|
|
90
|
+
# @option options [Array] values
|
|
91
|
+
# @option options [Array, Symbol] types
|
|
92
|
+
# @option options [Array, Integer] style
|
|
93
|
+
def array_to_cells(values, options={})
|
|
94
|
+
values = values
|
|
95
|
+
DataTypeValidator.validate 'Row.array_to_cells', Array, values
|
|
96
|
+
types, style = options.delete(:types), options.delete(:style)
|
|
97
|
+
values.each_with_index do |value, index|
|
|
98
|
+
cell_style = style.is_a?(Array) ? style[index] : style
|
|
99
|
+
options[:style] = cell_style if cell_style
|
|
100
|
+
cell_type = types.is_a?(Array)? types[index] : types
|
|
101
|
+
options[:type] = cell_type if cell_type
|
|
102
|
+
Cell.new(self, value, options)
|
|
103
|
+
end
|
|
104
|
+
end
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
end
|