axlsx 1.0.16 → 1.0.18
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/.yardopts +1 -0
- data/CHANGELOG.md +7 -0
- data/README.md +105 -46
- data/examples/example.rb +172 -142
- data/lib/axlsx/content_type/content_type.rb +4 -3
- data/lib/axlsx/content_type/default.rb +1 -0
- data/lib/axlsx/content_type/override.rb +1 -0
- data/lib/axlsx/doc_props/app.rb +1 -1
- data/lib/axlsx/doc_props/core.rb +1 -0
- data/lib/axlsx/drawing/axis.rb +1 -0
- data/lib/axlsx/drawing/bar_3D_chart.rb +1 -0
- data/lib/axlsx/drawing/bar_series.rb +1 -0
- data/lib/axlsx/drawing/cat_axis.rb +1 -0
- data/lib/axlsx/drawing/cat_axis_data.rb +1 -0
- data/lib/axlsx/drawing/chart.rb +4 -4
- data/lib/axlsx/drawing/drawing.rb +1 -0
- data/lib/axlsx/drawing/graphic_frame.rb +1 -0
- data/lib/axlsx/drawing/hyperlink.rb +1 -1
- data/lib/axlsx/drawing/line_3D_chart.rb +1 -0
- data/lib/axlsx/drawing/line_series.rb +1 -0
- data/lib/axlsx/drawing/marker.rb +1 -0
- data/lib/axlsx/drawing/one_cell_anchor.rb +1 -0
- data/lib/axlsx/drawing/pic.rb +2 -1
- data/lib/axlsx/drawing/picture_locking.rb +1 -0
- data/lib/axlsx/drawing/pie_3D_chart.rb +1 -0
- data/lib/axlsx/drawing/pie_series.rb +1 -0
- data/lib/axlsx/drawing/scaling.rb +1 -0
- data/lib/axlsx/drawing/ser_axis.rb +1 -0
- data/lib/axlsx/drawing/series.rb +1 -0
- data/lib/axlsx/drawing/series_title.rb +1 -0
- data/lib/axlsx/drawing/title.rb +1 -0
- data/lib/axlsx/drawing/two_cell_anchor.rb +1 -0
- data/lib/axlsx/drawing/val_axis.rb +1 -0
- data/lib/axlsx/drawing/val_axis_data.rb +1 -0
- data/lib/axlsx/drawing/view_3D.rb +1 -0
- data/lib/axlsx/package.rb +86 -38
- data/lib/axlsx/rels/relationship.rb +4 -3
- data/lib/axlsx/rels/relationships.rb +1 -0
- data/lib/axlsx/stylesheet/border.rb +1 -0
- data/lib/axlsx/stylesheet/border_pr.rb +1 -0
- data/lib/axlsx/stylesheet/cell_alignment.rb +1 -0
- data/lib/axlsx/stylesheet/cell_protection.rb +1 -0
- data/lib/axlsx/stylesheet/cell_style.rb +1 -0
- data/lib/axlsx/stylesheet/color.rb +1 -0
- data/lib/axlsx/stylesheet/fill.rb +1 -0
- data/lib/axlsx/stylesheet/font.rb +8 -0
- data/lib/axlsx/stylesheet/gradient_fill.rb +1 -1
- data/lib/axlsx/stylesheet/gradient_stop.rb +1 -1
- data/lib/axlsx/stylesheet/num_fmt.rb +1 -0
- data/lib/axlsx/stylesheet/pattern_fill.rb +1 -0
- data/lib/axlsx/stylesheet/styles.rb +12 -9
- data/lib/axlsx/stylesheet/table_style.rb +1 -0
- data/lib/axlsx/stylesheet/table_style_element.rb +1 -0
- data/lib/axlsx/stylesheet/table_styles.rb +1 -0
- data/lib/axlsx/stylesheet/xf.rb +1 -0
- data/lib/axlsx/util/cbf.rb +1 -0
- data/lib/axlsx/util/constants.rb +23 -14
- data/lib/axlsx/util/ms_off_crypto.rb +1 -1
- data/lib/axlsx/util/parser.rb +1 -0
- data/lib/axlsx/util/simple_typed_list.rb +2 -1
- data/lib/axlsx/util/storage.rb +1 -0
- data/lib/axlsx/util/validators.rb +11 -2
- data/lib/axlsx/version.rb +2 -1
- data/lib/axlsx/workbook/shared_strings_table.rb +71 -0
- data/lib/axlsx/workbook/shared_strings_table.rb~ +69 -0
- data/lib/axlsx/workbook/workbook.rb +47 -25
- data/lib/axlsx/workbook/worksheet/cell.rb +131 -78
- data/lib/axlsx/workbook/worksheet/date_time_converter.rb +29 -0
- data/lib/axlsx/workbook/worksheet/page_margins.rb +94 -0
- data/lib/axlsx/workbook/worksheet/row.rb +44 -12
- data/lib/axlsx/workbook/worksheet/shared_strings_table.rb~ +0 -0
- data/lib/axlsx/workbook/worksheet/worksheet.rb +158 -44
- data/lib/axlsx.rb +16 -10
- data/test/content_type/tc_content_type.rb +2 -0
- data/test/content_type/tc_default.rb +2 -0
- data/test/content_type/tc_override.rb +1 -0
- data/test/drawing/tc_chart.rb +2 -2
- data/test/stylesheet/tc_cell_alignment.rb +8 -3
- data/test/stylesheet/tc_font.rb +8 -0
- data/test/stylesheet/tc_styles.rb +6 -2
- data/test/tc_package.rb +31 -0
- data/test/workbook/tc_shared_strings_table.rb +39 -0
- data/test/workbook/tc_shared_strings_table.rb~ +8 -0
- data/test/workbook/tc_workbook.rb +8 -0
- data/test/workbook/worksheet/tc_cell.rb +52 -9
- data/test/workbook/worksheet/tc_date_time_converter.rb +127 -0
- data/test/workbook/worksheet/tc_date_time_converter.rb~ +69 -0
- data/test/workbook/worksheet/tc_page_margins.rb +100 -0
- data/test/workbook/worksheet/tc_row.rb +36 -0
- data/test/workbook/worksheet/tc_worksheet.rb +97 -3
- metadata +33 -40
|
@@ -1,53 +1,61 @@
|
|
|
1
|
-
#
|
|
1
|
+
# encoding: UTF-8
|
|
2
2
|
module Axlsx
|
|
3
|
-
# A cell in a worksheet.
|
|
3
|
+
# A cell in a worksheet.
|
|
4
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
5
|
# @example Manually creating and manipulating Cell objects
|
|
6
|
-
# ws = Workbook.new.add_worksheet
|
|
6
|
+
# ws = Workbook.new.add_worksheet
|
|
7
7
|
# # This is the simple, and recommended way to create cells. Data types will automatically be determined for you.
|
|
8
8
|
# ws.add_row :values => [1,"fish",Time.now]
|
|
9
9
|
#
|
|
10
10
|
# # but you can also do this
|
|
11
11
|
# r = ws.add_row
|
|
12
12
|
# r.add_cell 1
|
|
13
|
-
#
|
|
13
|
+
#
|
|
14
14
|
# # or even this
|
|
15
15
|
# r = ws.add_row
|
|
16
16
|
# c = Cell.new row, 1, :value=>integer
|
|
17
17
|
#
|
|
18
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
19
|
# r.cells.last.type = :float
|
|
20
|
-
#
|
|
20
|
+
#
|
|
21
21
|
# @note The recommended way to generate cells is via Worksheet#add_row
|
|
22
|
-
#
|
|
22
|
+
#
|
|
23
23
|
# @see Worksheet#add_row
|
|
24
24
|
class Cell
|
|
25
25
|
|
|
26
|
+
|
|
27
|
+
# An array of available inline styes.
|
|
28
|
+
INLINE_STYLES = ['value', 'type', 'font_name', 'charset',
|
|
29
|
+
'family', 'b', 'i', 'strike','outline',
|
|
30
|
+
'shadow', 'condense', 'extend', 'u',
|
|
31
|
+
'vertAlign', 'sz', 'color', 'scheme']
|
|
32
|
+
|
|
33
|
+
|
|
26
34
|
# The index of the cellXfs item to be applied to this cell.
|
|
27
|
-
# @return [Integer]
|
|
35
|
+
# @return [Integer]
|
|
28
36
|
# @see Axlsx::Styles
|
|
29
37
|
attr_reader :style
|
|
30
38
|
|
|
31
39
|
# The row this cell belongs to.
|
|
32
40
|
# @return [Row]
|
|
33
41
|
attr_reader :row
|
|
34
|
-
|
|
35
|
-
# The cell's data type. Currently only
|
|
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
|
|
42
|
+
|
|
43
|
+
# The cell's data type. Currently only six types are supported, :date, :time, :float, :integer, :string and :boolean.
|
|
44
|
+
# 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
45
|
# automatically determed.
|
|
38
46
|
# @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
|
|
47
|
+
# @return [Symbol] The type of data this cell's value is cast to.
|
|
48
|
+
# @raise [ArgumentExeption] Cell.type must be one of [:date, time, :float, :integer, :string, :boolean]
|
|
49
|
+
# @note
|
|
42
50
|
# 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
|
|
51
|
+
# :string to :integer or :float, type conversions always return 0 or 0.0
|
|
44
52
|
# :string, :integer, or :float to :time conversions always return the original value as a string and set the cells type to :string.
|
|
45
53
|
# No support is currently implemented for parsing time strings.
|
|
46
54
|
attr_reader :type
|
|
47
55
|
# @see type
|
|
48
|
-
def type=(v)
|
|
49
|
-
RestrictionValidator.validate "Cell.type", [:time, :float, :integer, :string], v
|
|
50
|
-
@type=v
|
|
56
|
+
def type=(v)
|
|
57
|
+
RestrictionValidator.validate "Cell.type", [:date, :time, :float, :integer, :string, :boolean], v
|
|
58
|
+
@type=v
|
|
51
59
|
self.value = @value unless @value.nil?
|
|
52
60
|
end
|
|
53
61
|
|
|
@@ -60,7 +68,7 @@ module Axlsx
|
|
|
60
68
|
#TODO: consider doing value based type determination first?
|
|
61
69
|
@value = cast_value(v)
|
|
62
70
|
end
|
|
63
|
-
|
|
71
|
+
|
|
64
72
|
# The inline font_name property for the cell
|
|
65
73
|
# @return [String]
|
|
66
74
|
attr_reader :font_name
|
|
@@ -131,7 +139,7 @@ module Axlsx
|
|
|
131
139
|
# @return [Color]
|
|
132
140
|
attr_reader :color
|
|
133
141
|
# @param [String] The 8 character representation for an rgb color #FFFFFFFF"
|
|
134
|
-
def color=(v)
|
|
142
|
+
def color=(v)
|
|
135
143
|
@color = v.is_a?(Color) ? v : Color.new(:rgb=>v)
|
|
136
144
|
end
|
|
137
145
|
|
|
@@ -156,7 +164,7 @@ module Axlsx
|
|
|
156
164
|
def scheme=(v) RestrictionValidator.validate "Cell.schema", [:none, :major, :minor], v; @scheme = v; end
|
|
157
165
|
|
|
158
166
|
# @param [Row] row The row this cell belongs to.
|
|
159
|
-
# @param [Any] value The value associated with this cell.
|
|
167
|
+
# @param [Any] value The value associated with this cell.
|
|
160
168
|
# @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
169
|
# @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
170
|
# @option options [String] font_name
|
|
@@ -175,9 +183,11 @@ module Axlsx
|
|
|
175
183
|
# @option options [String] color an 8 letter rgb specification
|
|
176
184
|
# @option options [Symbol] scheme must be one of :none, major, :minor
|
|
177
185
|
def initialize(row, value="", options={})
|
|
178
|
-
self.row=row
|
|
186
|
+
self.row=row
|
|
187
|
+
@font_name = @charset = @family = @b = @i = @strike = @outline = @shadow = nil
|
|
188
|
+
@condense = @u = @vertAlign = @sz = @color = @scheme = @extend = @ssti = nil
|
|
179
189
|
@styles = row.worksheet.workbook.styles
|
|
180
|
-
@row.cells << self
|
|
190
|
+
@row.cells << self
|
|
181
191
|
options.each do |o|
|
|
182
192
|
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
183
193
|
end
|
|
@@ -186,6 +196,24 @@ module Axlsx
|
|
|
186
196
|
@value = cast_value(value)
|
|
187
197
|
end
|
|
188
198
|
|
|
199
|
+
# The Shared Strings Table index for this cell
|
|
200
|
+
# @return [Integer]
|
|
201
|
+
attr_reader :ssti
|
|
202
|
+
|
|
203
|
+
# equality comparison to test value, type and inline style attributes
|
|
204
|
+
# this is how we work out if the cell needs to be added or already exists in the shared strings table
|
|
205
|
+
def shareable(v)
|
|
206
|
+
|
|
207
|
+
#using reject becase 1.8.7 select returns an array...
|
|
208
|
+
v_hash = v.instance_values.reject { |key, val| !INLINE_STYLES.include?(key) }
|
|
209
|
+
self_hash = self.instance_values.reject { |key, val| !INLINE_STYLES.include?(key) }
|
|
210
|
+
# required as color is an object, and the comparison will fail even though both use the same color.
|
|
211
|
+
v_hash['color'] = v_hash['color'].instance_values if v_hash['color']
|
|
212
|
+
self_hash['color'] = self_hash['color'].instance_values if self_hash['color']
|
|
213
|
+
|
|
214
|
+
v_hash == self_hash
|
|
215
|
+
end
|
|
216
|
+
|
|
189
217
|
# @return [Integer] The index of the cell in the containing row.
|
|
190
218
|
def index
|
|
191
219
|
@row.cells.index(self)
|
|
@@ -193,14 +221,14 @@ module Axlsx
|
|
|
193
221
|
|
|
194
222
|
# @return [String] The alpha(column)numeric(row) reference for this sell.
|
|
195
223
|
# @example Relative Cell Reference
|
|
196
|
-
# ws.rows.first.cells.first.r #=> "A1"
|
|
224
|
+
# ws.rows.first.cells.first.r #=> "A1"
|
|
197
225
|
def r
|
|
198
|
-
"#{col_ref}#{@row.index+1}"
|
|
226
|
+
"#{col_ref}#{@row.index+1}"
|
|
199
227
|
end
|
|
200
228
|
|
|
201
229
|
# @return [String] The absolute alpha(column)numeric(row) reference for this sell.
|
|
202
230
|
# @example Absolute Cell Reference
|
|
203
|
-
# ws.rows.first.cells.first.r #=> "$A$1"
|
|
231
|
+
# ws.rows.first.cells.first.r #=> "$A$1"
|
|
204
232
|
def r_abs
|
|
205
233
|
"$#{r.split('').join('$')}"
|
|
206
234
|
end
|
|
@@ -229,74 +257,88 @@ module Axlsx
|
|
|
229
257
|
target.r
|
|
230
258
|
end
|
|
231
259
|
self.row.worksheet.merge_cells "#{self.r}:#{range_end}" unless range_end.nil?
|
|
232
|
-
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# builds an xml text run based on this cells attributes. This is extracted from to_xml so that shared strings can use it.
|
|
263
|
+
# @param [Nokogiri::XML::Builder] xml The document builder instance this output will be added to.
|
|
264
|
+
# @return [String] the xml for this cell's text run
|
|
265
|
+
def run_xml(xml)
|
|
266
|
+
if (self.instance_values.keys & INLINE_STYLES).size > 0
|
|
267
|
+
xml.r {
|
|
268
|
+
xml.rPr {
|
|
269
|
+
xml.rFont(:val=>@font_name) if @font_name
|
|
270
|
+
xml.charset(:val=>@charset) if @charset
|
|
271
|
+
xml.family(:val=>@family) if @family
|
|
272
|
+
xml.b(:val=>@b) if @b
|
|
273
|
+
xml.i(:val=>@i) if @i
|
|
274
|
+
xml.strike(:val=>@strike) if @strike
|
|
275
|
+
xml.outline(:val=>@outline) if @outline
|
|
276
|
+
xml.shadow(:val=>@shadow) if @shadow
|
|
277
|
+
xml.condense(:val=>@condense) if @condense
|
|
278
|
+
xml.extend(:val=>@extend) if @extend
|
|
279
|
+
@color.to_xml(xml) if @color
|
|
280
|
+
xml.sz(:val=>@sz) if @sz
|
|
281
|
+
xml.u(:val=>@u) if @u
|
|
282
|
+
# :baseline, :subscript, :superscript
|
|
283
|
+
xml.vertAlign(:val=>@vertAlign) if @vertAlign
|
|
284
|
+
# :none, major, :minor
|
|
285
|
+
xml.scheme(:val=>@scheme) if @scheme
|
|
286
|
+
}
|
|
287
|
+
xml.t @value.to_s
|
|
288
|
+
}
|
|
289
|
+
else
|
|
290
|
+
xml.t @value.to_s
|
|
291
|
+
end
|
|
292
|
+
end
|
|
233
293
|
|
|
234
294
|
# Serializes the cell
|
|
235
295
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
|
236
296
|
# @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
297
|
def to_xml(xml)
|
|
240
|
-
|
|
241
|
-
# however nokogiri does a nice 'force_encoding' which we shall remove!
|
|
242
|
-
if @type == :string
|
|
298
|
+
if @type == :string
|
|
243
299
|
#parse formula
|
|
244
300
|
if @value.start_with?('=')
|
|
245
301
|
xml.c(:r => r, :t=>:str, :s=>style) {
|
|
246
302
|
xml.f @value.to_s.gsub('=', '')
|
|
247
303
|
}
|
|
248
304
|
else
|
|
249
|
-
#parse
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
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
|
|
305
|
+
#parse shared
|
|
306
|
+
if @ssti
|
|
307
|
+
xml.c(:r => r, :s=>style, :t => :s) { xml.v ssti }
|
|
308
|
+
else
|
|
309
|
+
#parse inline string
|
|
310
|
+
xml.c(:r => r, :s=>style, :t => :inlineStr) {
|
|
311
|
+
xml.is {
|
|
312
|
+
run_xml(xml)
|
|
277
313
|
}
|
|
278
314
|
}
|
|
279
|
-
|
|
315
|
+
end
|
|
280
316
|
end
|
|
317
|
+
elsif @type == :date
|
|
318
|
+
# TODO: See if this is subject to the same restriction as Time below
|
|
319
|
+
v = DateTimeConverter::date_to_serial @value
|
|
320
|
+
xml.c(:r => r, :s => style) { xml.v v }
|
|
281
321
|
elsif @type == :time
|
|
282
|
-
|
|
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
|
|
322
|
+
v = DateTimeConverter::time_to_serial @value
|
|
288
323
|
xml.c(:r => r, :s => style) { xml.v v }
|
|
324
|
+
elsif @type == :boolean
|
|
325
|
+
xml.c(:r => r, :s => style, :t => :b) { xml.v value }
|
|
289
326
|
else
|
|
290
327
|
xml.c(:r => r, :s => style) { xml.v value }
|
|
291
328
|
end
|
|
292
329
|
end
|
|
293
330
|
|
|
331
|
+
private
|
|
294
332
|
|
|
295
|
-
|
|
333
|
+
# @see ssti
|
|
334
|
+
def ssti=(v)
|
|
335
|
+
Axlsx::validate_unsigned_int(v)
|
|
336
|
+
@ssti = v
|
|
337
|
+
end
|
|
296
338
|
|
|
297
339
|
# assigns the owning row for this cell.
|
|
298
340
|
def row=(v) DataTypeValidator.validate "Cell.row", Row, v; @row=v end
|
|
299
|
-
|
|
341
|
+
|
|
300
342
|
# converts the column index into alphabetical values.
|
|
301
343
|
# @note This follows the standard spreadsheet convention of naming columns A to Z, followed by AA to AZ etc.
|
|
302
344
|
# @return [String]
|
|
@@ -311,15 +353,21 @@ module Axlsx
|
|
|
311
353
|
chars.reverse.join
|
|
312
354
|
end
|
|
313
355
|
|
|
314
|
-
# Determines the cell type based on the cell value.
|
|
356
|
+
# Determines the cell type based on the cell value.
|
|
315
357
|
# @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
|
|
317
|
-
# 2.
|
|
318
|
-
# 3.
|
|
358
|
+
# 1. If the value is an instance of Date, the type is set to :date
|
|
359
|
+
# 2. If the value is an instance of Time, the type is set to :time
|
|
360
|
+
# 3. If the value is an instance of TrueClass or FalseClass, the type is set to :boolean
|
|
361
|
+
# 4. :float and :integer types are determined by regular expression matching.
|
|
362
|
+
# 5. Anything that does not meet either of the above is determined to be :string.
|
|
319
363
|
# @return [Symbol] The determined type
|
|
320
|
-
def cell_type_from_value(v)
|
|
321
|
-
if v.is_a?
|
|
364
|
+
def cell_type_from_value(v)
|
|
365
|
+
if v.is_a?(Date)
|
|
366
|
+
:date
|
|
367
|
+
elsif v.is_a?(Time)
|
|
322
368
|
:time
|
|
369
|
+
elsif v.is_a?(TrueClass) || v.is_a?(FalseClass)
|
|
370
|
+
:boolean
|
|
323
371
|
elsif v.to_s.match(/\A[+-]?\d+?\Z/) #numeric
|
|
324
372
|
:integer
|
|
325
373
|
elsif v.to_s.match(/\A[+-]?\d+\.\d+?\Z/) #float
|
|
@@ -329,22 +377,27 @@ module Axlsx
|
|
|
329
377
|
end
|
|
330
378
|
end
|
|
331
379
|
|
|
332
|
-
# Cast the value into this cells data type.
|
|
333
|
-
# @note
|
|
380
|
+
# Cast the value into this cells data type.
|
|
381
|
+
# @note
|
|
334
382
|
# 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
383
|
# @see Axlsx#date1904
|
|
336
384
|
def cast_value(v)
|
|
337
|
-
if
|
|
385
|
+
if @type == :date
|
|
386
|
+
self.style = STYLE_DATE if self.style == 0
|
|
387
|
+
v
|
|
388
|
+
elsif (@type == :time && v.is_a?(Time)) || (@type == :time && v.respond_to?(:to_time))
|
|
338
389
|
self.style = STYLE_DATE if self.style == 0
|
|
339
390
|
v.respond_to?(:to_time) ? v.to_time : v
|
|
340
391
|
elsif @type == :float
|
|
341
392
|
v.to_f
|
|
342
393
|
elsif @type == :integer
|
|
343
394
|
v.to_i
|
|
395
|
+
elsif @type == :boolean
|
|
396
|
+
v ? 1 : 0
|
|
344
397
|
else
|
|
345
398
|
@type = :string
|
|
346
399
|
v.to_s
|
|
347
400
|
end
|
|
348
|
-
end
|
|
401
|
+
end
|
|
349
402
|
end
|
|
350
403
|
end
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
require "date"
|
|
3
|
+
|
|
4
|
+
module Axlsx
|
|
5
|
+
# The DateTimeConverter class converts both data and time types to their apprpriate excel serializations
|
|
6
|
+
class DateTimeConverter
|
|
7
|
+
|
|
8
|
+
# The date_to_serial method converts Date objects to the equivelant excel serialized forms
|
|
9
|
+
# @param [Date] date the date to be serialized
|
|
10
|
+
# @return [Numeric]
|
|
11
|
+
def self.date_to_serial(date)
|
|
12
|
+
epoch = Axlsx::Workbook::date1904 ? Date.new(1904) : Date.new(1899, 12, 30)
|
|
13
|
+
(date-epoch).to_f
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
# The time_to_serial methond converts a Time object its excel serialized form.
|
|
17
|
+
# @param [Time] time the time to be serialized
|
|
18
|
+
# @return [Numeric]
|
|
19
|
+
def self.time_to_serial(time)
|
|
20
|
+
# Using hardcoded offsets here as some operating systems will not except
|
|
21
|
+
# a 'negative' offset from the ruby epoch.
|
|
22
|
+
epoch1900 = -2209161600 # Time.utc(1899, 12, 30).to_i
|
|
23
|
+
epoch1904 = -2082844800 # Time.utc(1904, 1, 1).to_i
|
|
24
|
+
seconds_per_day = 86400 # 60*60*24
|
|
25
|
+
epoch = Axlsx::Workbook::date1904 ? epoch1904 : epoch1900
|
|
26
|
+
(time.to_f - epoch)/seconds_per_day
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
module Axlsx
|
|
2
|
+
# PageMargins specify the margins when printing a worksheet.
|
|
3
|
+
#
|
|
4
|
+
# For compatibility, PageMargins serialize to an empty string, unless at least one custom margin value
|
|
5
|
+
# has been specified. Otherwise, it serializes to a PageMargin element specifying all 6 margin values
|
|
6
|
+
# (using default values for margins that have not been specified explicitly).
|
|
7
|
+
#
|
|
8
|
+
# @note The recommended way to manage page margins is via Worksheet#page_margins
|
|
9
|
+
# @see Worksheet#page_margins
|
|
10
|
+
# @see Worksheet#initialize
|
|
11
|
+
class PageMargins
|
|
12
|
+
|
|
13
|
+
# Default left and right margin (in inches)
|
|
14
|
+
DEFAULT_LEFT_RIGHT = 0.75
|
|
15
|
+
|
|
16
|
+
# Default top and bottom margins (in inches)
|
|
17
|
+
DEFAULT_TOP_BOTTOM = 1.00
|
|
18
|
+
|
|
19
|
+
# Default header and footer margins (in inches)
|
|
20
|
+
DEFAULT_HEADER_FOOTER = 0.50
|
|
21
|
+
|
|
22
|
+
# Left margin (in inches)
|
|
23
|
+
# @return [Float]
|
|
24
|
+
attr_reader :left
|
|
25
|
+
|
|
26
|
+
# Right margin (in inches)
|
|
27
|
+
# @return [Float]
|
|
28
|
+
attr_reader :right
|
|
29
|
+
|
|
30
|
+
# Top margin (in inches)
|
|
31
|
+
# @return [Float]
|
|
32
|
+
attr_reader :top
|
|
33
|
+
|
|
34
|
+
# Bottom margin (in inches)
|
|
35
|
+
# @return [Float]
|
|
36
|
+
attr_reader :bottom
|
|
37
|
+
|
|
38
|
+
# Header margin (in inches)
|
|
39
|
+
# @return [Float]
|
|
40
|
+
attr_reader :header
|
|
41
|
+
|
|
42
|
+
# Footer margin (in inches)
|
|
43
|
+
# @return [Float]
|
|
44
|
+
attr_reader :footer
|
|
45
|
+
|
|
46
|
+
# Creates a new PageMargins object
|
|
47
|
+
# @option options [Numeric] left The left margin in inches
|
|
48
|
+
# @option options [Numeric] right The right margin in inches
|
|
49
|
+
# @option options [Numeric] bottom The bottom margin in inches
|
|
50
|
+
# @option options [Numeric] top The top margin in inches
|
|
51
|
+
# @option options [Numeric] header The header margin in inches
|
|
52
|
+
# @option options [Numeric] footer The footer margin in inches
|
|
53
|
+
def initialize(options={})
|
|
54
|
+
# Default values taken from MS Excel for Mac 2011
|
|
55
|
+
@left = @right = DEFAULT_LEFT_RIGHT
|
|
56
|
+
@top = @bottom = DEFAULT_TOP_BOTTOM
|
|
57
|
+
@header = @footer = DEFAULT_HEADER_FOOTER
|
|
58
|
+
|
|
59
|
+
options.each do |o|
|
|
60
|
+
self.send("#{o[0]}=", o[1]) if self.respond_to? "#{o[0]}="
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
# Set some or all margins at once.
|
|
65
|
+
# @param [Hash] margins the margins to set (possible keys are :left, :right, :top, :bottom, :header and :footer).
|
|
66
|
+
def set(margins)
|
|
67
|
+
margins.select do |k, v|
|
|
68
|
+
next unless [:left, :right, :top, :bottom, :header, :footer].include? k
|
|
69
|
+
send("#{k}=", v)
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
# @see left
|
|
74
|
+
def left=(v); Axlsx::validate_unsigned_numeric(v); @left = v end
|
|
75
|
+
# @see right
|
|
76
|
+
def right=(v); Axlsx::validate_unsigned_numeric(v); @right = v end
|
|
77
|
+
# @see top
|
|
78
|
+
def top=(v); Axlsx::validate_unsigned_numeric(v); @top = v end
|
|
79
|
+
# @see bottom
|
|
80
|
+
def bottom=(v); Axlsx::validate_unsigned_numeric(v); @bottom = v end
|
|
81
|
+
# @see header
|
|
82
|
+
def header=(v); Axlsx::validate_unsigned_numeric(v); @header = v end
|
|
83
|
+
# @see footer
|
|
84
|
+
def footer=(v); Axlsx::validate_unsigned_numeric(v); @footer = v end
|
|
85
|
+
|
|
86
|
+
# Serializes the page margins element
|
|
87
|
+
# @note For compatibility, this is a noop unless custom margins have been specified.
|
|
88
|
+
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
|
89
|
+
# @see #custom_margins_specified?
|
|
90
|
+
def to_xml(xml)
|
|
91
|
+
xml.pageMargins :left => left, :right => right, :top => top, :bottom => bottom, :header => header, :footer => footer
|
|
92
|
+
end
|
|
93
|
+
end
|
|
94
|
+
end
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
1
2
|
module Axlsx
|
|
2
3
|
# A Row is a single row in a worksheet.
|
|
3
4
|
# @note The recommended way to manage rows and cells is to use Worksheet#add_row
|
|
@@ -12,6 +13,22 @@ module Axlsx
|
|
|
12
13
|
# @return [SimpleTypedList]
|
|
13
14
|
attr_reader :cells
|
|
14
15
|
|
|
16
|
+
# The height of this row in points, if set explicitly.
|
|
17
|
+
# @return [Float]
|
|
18
|
+
attr_reader :height
|
|
19
|
+
|
|
20
|
+
# TODO 18.3.1.73
|
|
21
|
+
# collapsed
|
|
22
|
+
# customFormat
|
|
23
|
+
# hidden
|
|
24
|
+
# outlineLevel
|
|
25
|
+
# ph
|
|
26
|
+
# s (style)
|
|
27
|
+
# spans
|
|
28
|
+
# thickTop
|
|
29
|
+
# thickBottom
|
|
30
|
+
|
|
31
|
+
|
|
15
32
|
# Creates a new row. New Cell objects are created based on the values, types and style options.
|
|
16
33
|
# A new cell is created for each item in the values array. style and types options are applied as follows:
|
|
17
34
|
# If the types option is defined and is a symbol it is applied to all the cells created.
|
|
@@ -22,28 +39,33 @@ module Axlsx
|
|
|
22
39
|
# If the style option is not defined, the default style (0) is applied to each cell.
|
|
23
40
|
# @param [Worksheet] worksheet
|
|
24
41
|
# @option options [Array] values
|
|
25
|
-
# @option options [Array, Symbol] types
|
|
26
|
-
# @option options [Array, Integer] style
|
|
42
|
+
# @option options [Array, Symbol] types
|
|
43
|
+
# @option options [Array, Integer] style
|
|
44
|
+
# @option options [Float] height the row's height (in points)
|
|
27
45
|
# @see Row#array_to_cells
|
|
28
46
|
# @see Cell
|
|
29
47
|
def initialize(worksheet, values=[], options={})
|
|
48
|
+
@height = nil
|
|
30
49
|
self.worksheet = worksheet
|
|
31
50
|
@cells = SimpleTypedList.new Cell
|
|
32
51
|
@worksheet.rows << self
|
|
52
|
+
self.height = options.delete(:height) if options[:height]
|
|
33
53
|
array_to_cells(values, options)
|
|
34
54
|
end
|
|
35
55
|
|
|
36
56
|
# The index of this row in the worksheet
|
|
37
57
|
# @return [Integer]
|
|
38
|
-
def index
|
|
58
|
+
def index
|
|
39
59
|
worksheet.rows.index(self)
|
|
40
60
|
end
|
|
41
|
-
|
|
61
|
+
|
|
42
62
|
# Serializes the row
|
|
43
63
|
# @param [Nokogiri::XML::Builder] xml The document builder instance this objects xml will be added to.
|
|
44
64
|
# @return [String]
|
|
45
65
|
def to_xml(xml)
|
|
46
|
-
|
|
66
|
+
attrs = {:r => index+1}
|
|
67
|
+
attrs.merge!(:customHeight => 1, :ht => height) if custom_height?
|
|
68
|
+
xml.row(attrs) { |ixml| @cells.each { |cell| cell.to_xml(ixml) } }
|
|
47
69
|
end
|
|
48
70
|
|
|
49
71
|
# Adds a singel sell to the row based on the data provided and updates the worksheet's autofit data.
|
|
@@ -53,7 +75,7 @@ module Axlsx
|
|
|
53
75
|
update_auto_fit_data
|
|
54
76
|
c
|
|
55
77
|
end
|
|
56
|
-
|
|
78
|
+
|
|
57
79
|
# sets the style for every cell in this row
|
|
58
80
|
def style=(style)
|
|
59
81
|
cells.each_with_index do | cell, index |
|
|
@@ -63,17 +85,27 @@ module Axlsx
|
|
|
63
85
|
end
|
|
64
86
|
|
|
65
87
|
# returns the cells in this row as an array
|
|
66
|
-
# This lets us transpose the rows into columns
|
|
88
|
+
# This lets us transpose the rows into columns
|
|
67
89
|
# @return [Array]
|
|
68
90
|
def to_ary
|
|
69
91
|
@cells.to_ary
|
|
70
92
|
end
|
|
71
93
|
|
|
94
|
+
# @see height
|
|
95
|
+
def height=(v); Axlsx::validate_unsigned_numeric(v) unless v.nil?; @height = v end
|
|
96
|
+
|
|
97
|
+
# true if the row height has been manually set
|
|
98
|
+
# @return [Boolean]
|
|
99
|
+
# @see #height
|
|
100
|
+
def custom_height?
|
|
101
|
+
@height != nil
|
|
102
|
+
end
|
|
103
|
+
|
|
72
104
|
private
|
|
73
105
|
|
|
74
106
|
# assigns the owning worksheet for this row
|
|
75
107
|
def worksheet=(v) DataTypeValidator.validate "Row.worksheet", Worksheet, v; @worksheet=v; end
|
|
76
|
-
|
|
108
|
+
|
|
77
109
|
# Tell the worksheet to update autofit data for the columns based on this row's cells.
|
|
78
110
|
# @return [SimpleTypedList]
|
|
79
111
|
def update_auto_fit_data
|
|
@@ -88,13 +120,13 @@ module Axlsx
|
|
|
88
120
|
# If the style option is defined and is an Integer, it is applied to all cells created.
|
|
89
121
|
# If the style option is an array, style is applied by index for each cell.
|
|
90
122
|
# @option options [Array] values
|
|
91
|
-
# @option options [Array, Symbol] types
|
|
92
|
-
# @option options [Array, Integer] style
|
|
123
|
+
# @option options [Array, Symbol] types
|
|
124
|
+
# @option options [Array, Integer] style
|
|
93
125
|
def array_to_cells(values, options={})
|
|
94
126
|
values = values
|
|
95
127
|
DataTypeValidator.validate 'Row.array_to_cells', Array, values
|
|
96
128
|
types, style = options.delete(:types), options.delete(:style)
|
|
97
|
-
values.each_with_index do |value, index|
|
|
129
|
+
values.each_with_index do |value, index|
|
|
98
130
|
cell_style = style.is_a?(Array) ? style[index] : style
|
|
99
131
|
options[:style] = cell_style if cell_style
|
|
100
132
|
cell_type = types.is_a?(Array)? types[index] : types
|
|
@@ -103,5 +135,5 @@ module Axlsx
|
|
|
103
135
|
end
|
|
104
136
|
end
|
|
105
137
|
end
|
|
106
|
-
|
|
138
|
+
|
|
107
139
|
end
|
|
File without changes
|