xlsxrb 0.1.13 → 0.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +57 -0
- data/README.md +2 -0
- data/lib/xlsxrb/colors.rb +118 -0
- data/lib/xlsxrb/elements/cell.rb +205 -16
- data/lib/xlsxrb/elements/column.rb +6 -4
- data/lib/xlsxrb/elements/coordinate_access.rb +32 -0
- data/lib/xlsxrb/elements/image.rb +128 -0
- data/lib/xlsxrb/elements/row.rb +206 -9
- data/lib/xlsxrb/elements/styles.rb +157 -0
- data/lib/xlsxrb/elements/types.rb +95 -1
- data/lib/xlsxrb/elements/workbook.rb +85 -4
- data/lib/xlsxrb/elements/worksheet.rb +424 -29
- data/lib/xlsxrb/elements.rb +2 -0
- data/lib/xlsxrb/number_formatter.rb +429 -0
- data/lib/xlsxrb/ooxml/cfb.rb +1 -1
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +7 -5
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +11 -4
- data/lib/xlsxrb/ooxml/reader.rb +12 -14
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +7 -1
- data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
- data/lib/xlsxrb/ooxml/utils.rb +34 -18
- data/lib/xlsxrb/ooxml/workbook_parser.rb +53 -15
- data/lib/xlsxrb/ooxml/workbook_writer.rb +65 -14
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +319 -79
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +206 -61
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +4 -2
- data/lib/xlsxrb/ooxml/writer.rb +14 -0
- data/lib/xlsxrb/ooxml/zip_reader.rb +109 -25
- data/lib/xlsxrb/stream_row.rb +243 -16
- data/lib/xlsxrb/stream_sheet.rb +414 -15
- data/lib/xlsxrb/stream_writer.rb +213 -17
- data/lib/xlsxrb/style_builder.rb +308 -22
- data/lib/xlsxrb/utils.rb +158 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +73 -3
- data/lib/xlsxrb/worksheet_builder.rb +227 -16
- data/lib/xlsxrb.rb +578 -79
- data/sig/generated/xlsxrb/colors.rbs +40 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +113 -8
- data/sig/generated/xlsxrb/elements/column.rbs +3 -2
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +18 -0
- data/sig/generated/xlsxrb/elements/image.rbs +82 -0
- data/sig/generated/xlsxrb/elements/row.rbs +83 -4
- data/sig/generated/xlsxrb/elements/styles.rbs +79 -0
- data/sig/generated/xlsxrb/elements/types.rbs +43 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +51 -2
- data/sig/generated/xlsxrb/elements/worksheet.rbs +231 -18
- data/sig/generated/xlsxrb/number_formatter.rbs +132 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +6 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/utils.rbs +17 -8
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +9 -3
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +28 -6
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +10 -0
- data/sig/generated/xlsxrb/stream_row.rbs +100 -6
- data/sig/generated/xlsxrb/stream_sheet.rbs +247 -13
- data/sig/generated/xlsxrb/stream_writer.rbs +120 -14
- data/sig/generated/xlsxrb/style_builder.rbs +55 -18
- data/sig/generated/xlsxrb/utils.rbs +119 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +107 -11
- data/sig/generated/xlsxrb.rbs +186 -27
- metadata +11 -1
|
@@ -26,14 +26,20 @@ module Xlsxrb
|
|
|
26
26
|
|
|
27
27
|
INTEGER_STRINGS = (0..65_535).map(&:to_s).freeze
|
|
28
28
|
|
|
29
|
-
def initialize(io)
|
|
29
|
+
def initialize(io, date1904: false)
|
|
30
30
|
@io = io
|
|
31
|
+
@date1904 = date1904 ? true : false
|
|
31
32
|
@builder = XmlBuilder.new(@io)
|
|
32
33
|
@row_buffer = String.new(capacity: 65_536)
|
|
33
34
|
@started = false
|
|
34
35
|
@finished = false
|
|
35
36
|
end
|
|
36
37
|
|
|
38
|
+
def set_column_style(col_index, style_id)
|
|
39
|
+
@column_styles ||= {}
|
|
40
|
+
@column_styles[col_index] = style_id
|
|
41
|
+
end
|
|
42
|
+
|
|
37
43
|
# Write the worksheet header. Call once before writing rows.
|
|
38
44
|
# Options for pre-sheetData elements:
|
|
39
45
|
# sheet_properties: Hash of sheet-level properties (:tab_color, etc.)
|
|
@@ -48,6 +54,25 @@ module Xlsxrb
|
|
|
48
54
|
@builder.declaration
|
|
49
55
|
@builder.open_tag("worksheet", { xmlns: SSML_NS, "xmlns:r": DOC_REL_NS })
|
|
50
56
|
|
|
57
|
+
@column_styles ||= {}
|
|
58
|
+
if columns && !columns.empty?
|
|
59
|
+
columns.each do |col|
|
|
60
|
+
if col.is_a?(Elements::Column)
|
|
61
|
+
s = col.style_index
|
|
62
|
+
min = col.index
|
|
63
|
+
max = col.index
|
|
64
|
+
else
|
|
65
|
+
s = col[:style_index] || col[:style]
|
|
66
|
+
min = col[:index] || col[:min] || 0
|
|
67
|
+
max = col[:index] || col[:max] || col[:min] || 0
|
|
68
|
+
end
|
|
69
|
+
next unless s
|
|
70
|
+
|
|
71
|
+
(min..max).each { |i| @column_styles[i] = s }
|
|
72
|
+
end
|
|
73
|
+
end
|
|
74
|
+
@column_styles = nil if @column_styles.empty?
|
|
75
|
+
|
|
51
76
|
write_sheet_properties(sheet_properties) if sheet_properties && !sheet_properties.empty?
|
|
52
77
|
write_sheet_views(freeze_pane: freeze_pane, split_pane: split_pane, selection: selection, sheet_view: sheet_view) if freeze_pane || split_pane || selection || (sheet_view && !sheet_view.empty?)
|
|
53
78
|
write_columns(columns) unless columns.empty?
|
|
@@ -63,12 +88,14 @@ module Xlsxrb
|
|
|
63
88
|
row_num_str = row_num.to_s
|
|
64
89
|
buf = @row_buffer ||= String.new(capacity: 65_536)
|
|
65
90
|
buf << '<row r="' << row_num_str << '"'
|
|
91
|
+
buf << ' s="' << attrs[:style_index].to_s << '" customFormat="1"' if attrs[:style_index]
|
|
66
92
|
if attrs[:height]
|
|
67
93
|
buf << ' ht="' << attrs[:height].to_s << '" customHeight="1"'
|
|
68
94
|
elsif attrs[:custom_height]
|
|
69
95
|
buf << ' customHeight="1"'
|
|
70
96
|
end
|
|
71
97
|
buf << ' hidden="1"' if attrs[:hidden]
|
|
98
|
+
buf << ' collapsed="1"' if attrs[:collapsed]
|
|
72
99
|
buf << ' outlineLevel="' << attrs[:outline_level].to_s << '"' if attrs[:outline_level]
|
|
73
100
|
buf << ">"
|
|
74
101
|
|
|
@@ -77,25 +104,31 @@ module Xlsxrb
|
|
|
77
104
|
value = cell.value
|
|
78
105
|
style_id = cell.style_index
|
|
79
106
|
col_ref = cell.ref || "#{column_letter(cell.column_index)}#{row_num_str}"
|
|
107
|
+
col_idx = cell.column_index
|
|
80
108
|
formula = cell.formula
|
|
81
109
|
formula_ca = false
|
|
82
110
|
cell_type_val = nil
|
|
83
111
|
elsif cell.is_a?(Hash)
|
|
84
112
|
value = cell[:value]
|
|
85
113
|
style_id = cell[:style_index]
|
|
86
|
-
|
|
114
|
+
col_idx = cell[:column_index]
|
|
115
|
+
col_ref = cell[:ref] || (col_idx ? "#{column_letter(col_idx)}#{row_num_str}" : nil)
|
|
87
116
|
formula = cell[:formula]
|
|
88
117
|
formula_ca = cell[:formula_ca]
|
|
89
118
|
cell_type_val = cell[:type]
|
|
90
119
|
else
|
|
91
120
|
value = cell
|
|
92
121
|
style_id = nil
|
|
122
|
+
col_idx = nil
|
|
93
123
|
col_ref = nil
|
|
94
124
|
formula = nil
|
|
95
125
|
formula_ca = false
|
|
96
126
|
cell_type_val = nil
|
|
97
127
|
end
|
|
98
128
|
|
|
129
|
+
col_style = @column_styles && col_idx ? @column_styles[col_idx] : nil
|
|
130
|
+
style_id ||= attrs[:style_index] || col_style
|
|
131
|
+
|
|
99
132
|
# Fast path for common unstyled cells
|
|
100
133
|
if !formula && !style_id && !cell_type_val
|
|
101
134
|
case value
|
|
@@ -117,7 +150,7 @@ module Xlsxrb
|
|
|
117
150
|
buf << '<c r="' << col_ref << '"/>'
|
|
118
151
|
next
|
|
119
152
|
when Date
|
|
120
|
-
serial = Xlsxrb::Ooxml::Utils.date_to_serial(value)
|
|
153
|
+
serial = Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: @date1904)
|
|
121
154
|
buf << '<c r="' << col_ref << '"><v>' << serial.to_s << "</v></c>"
|
|
122
155
|
next
|
|
123
156
|
end
|
|
@@ -137,13 +170,25 @@ module Xlsxrb
|
|
|
137
170
|
|
|
138
171
|
xml_val = value
|
|
139
172
|
type = cell_type_val
|
|
140
|
-
|
|
173
|
+
formula_type = nil
|
|
174
|
+
formula_ref = nil
|
|
175
|
+
formula_si = nil
|
|
141
176
|
|
|
142
177
|
if formula
|
|
143
178
|
if formula.is_a?(Xlsxrb::Elements::Formula)
|
|
144
179
|
formula_expr = formula.expression
|
|
145
180
|
formula_ca = formula.calculate_always
|
|
146
|
-
|
|
181
|
+
formula_type = formula.type
|
|
182
|
+
formula_ref = formula.ref
|
|
183
|
+
formula_si = formula.shared_index
|
|
184
|
+
xml_val = formula.cached_value.nil? ? (value || nil) : formula.cached_value
|
|
185
|
+
elsif formula.is_a?(Hash)
|
|
186
|
+
formula_expr = formula[:formula] || formula[:expression]
|
|
187
|
+
formula_ca = formula[:calculate_always]
|
|
188
|
+
formula_type = formula[:type]
|
|
189
|
+
formula_ref = formula[:ref]
|
|
190
|
+
formula_si = formula[:si] || formula[:shared_index]
|
|
191
|
+
xml_val = formula[:value] || formula[:cached_value] || value || nil
|
|
147
192
|
else
|
|
148
193
|
formula_expr = formula
|
|
149
194
|
xml_val = value || nil
|
|
@@ -175,9 +220,9 @@ module Xlsxrb
|
|
|
175
220
|
xml_val = "0"
|
|
176
221
|
type = "b"
|
|
177
222
|
when Date
|
|
178
|
-
xml_val = Xlsxrb::Ooxml::Utils.date_to_serial(value)
|
|
223
|
+
xml_val = Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: @date1904)
|
|
179
224
|
when Time
|
|
180
|
-
xml_val = Xlsxrb::Ooxml::Utils.datetime_to_serial(value)
|
|
225
|
+
xml_val = Xlsxrb::Ooxml::Utils.datetime_to_serial(value, date1904: @date1904)
|
|
181
226
|
when BigDecimal
|
|
182
227
|
xml_val = value.to_s("F")
|
|
183
228
|
when Xlsxrb::Elements::CellError
|
|
@@ -229,16 +274,24 @@ module Xlsxrb
|
|
|
229
274
|
buf << "><is><t>" << escape_xml(xml_val.to_s) << "</t></is></c>"
|
|
230
275
|
end
|
|
231
276
|
elsif formula_expr
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
277
|
+
f_attrs = +""
|
|
278
|
+
if formula_type
|
|
279
|
+
case formula_type.to_sym
|
|
280
|
+
when :array
|
|
281
|
+
f_attrs << ' t="array"'
|
|
282
|
+
f_attrs << %( ref="#{formula_ref}") if formula_ref
|
|
283
|
+
when :shared
|
|
284
|
+
f_attrs << ' t="shared"'
|
|
285
|
+
f_attrs << %( si="#{formula_si}") if formula_si
|
|
286
|
+
f_attrs << %( ref="#{formula_ref}") if formula_ref
|
|
287
|
+
end
|
|
288
|
+
end
|
|
289
|
+
f_attrs << ' ca="1"' if formula_ca
|
|
290
|
+
buf << "><f#{f_attrs}>" << escape_xml(formula_expr) << "</f>"
|
|
238
291
|
if xml_val
|
|
239
292
|
buf << "<v>" << xml_val.to_s << "</v></c>"
|
|
240
293
|
else
|
|
241
|
-
buf << "</c>"
|
|
294
|
+
buf << "<v>0</v></c>"
|
|
242
295
|
end
|
|
243
296
|
else
|
|
244
297
|
buf << "><v>" << xml_val.to_s << "</v></c>"
|
|
@@ -262,7 +315,7 @@ module Xlsxrb
|
|
|
262
315
|
row_num_str = row_num < 65_536 ? INTEGER_STRINGS[row_num] : row_num.to_s
|
|
263
316
|
buf = @row_buffer ||= String.new(capacity: 65_536)
|
|
264
317
|
|
|
265
|
-
if styles.nil? && attrs.nil?
|
|
318
|
+
if styles.nil? && attrs.nil? && @column_styles.nil?
|
|
266
319
|
buf << "<row r=\"#{row_num_str}\">"
|
|
267
320
|
col_index = 0
|
|
268
321
|
max_len = values.length
|
|
@@ -292,7 +345,7 @@ module Xlsxrb
|
|
|
292
345
|
next
|
|
293
346
|
end
|
|
294
347
|
formula_expr = value[1..]
|
|
295
|
-
buf << "<c r=\"#{col_ref}#{row_num_str}\"><f>#{escape_xml(formula_expr)}</f></c>"
|
|
348
|
+
buf << "<c r=\"#{col_ref}#{row_num_str}\"><f>#{escape_xml(formula_expr)}</f><v>0</v></c>"
|
|
296
349
|
when true
|
|
297
350
|
buf << "<c r=\"#{col_ref}#{row_num_str}\" t=\"b\"><v>1</v></c>"
|
|
298
351
|
when false
|
|
@@ -300,35 +353,54 @@ module Xlsxrb
|
|
|
300
353
|
when Date
|
|
301
354
|
date_style_id = style_map ? style_map["__xlsxrb_date"] : nil
|
|
302
355
|
buf << if date_style_id
|
|
303
|
-
"<c r=\"#{col_ref}#{row_num_str}\" s=\"#{date_style_id}\"><v>#{Xlsxrb::Ooxml::Utils.date_to_serial(value)}</v></c>"
|
|
356
|
+
"<c r=\"#{col_ref}#{row_num_str}\" s=\"#{date_style_id}\"><v>#{Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: @date1904)}</v></c>"
|
|
304
357
|
else
|
|
305
|
-
"<c r=\"#{col_ref}#{row_num_str}\"><v>#{Xlsxrb::Ooxml::Utils.date_to_serial(value)}</v></c>"
|
|
358
|
+
"<c r=\"#{col_ref}#{row_num_str}\"><v>#{Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: @date1904)}</v></c>"
|
|
306
359
|
end
|
|
307
360
|
when Time
|
|
308
361
|
time_style_id = style_map ? style_map["__xlsxrb_time"] : nil
|
|
309
362
|
buf << if time_style_id
|
|
310
|
-
"<c r=\"#{col_ref}#{row_num_str}\" s=\"#{time_style_id}\"><v>#{Xlsxrb::Ooxml::Utils.datetime_to_serial(value)}</v></c>"
|
|
363
|
+
"<c r=\"#{col_ref}#{row_num_str}\" s=\"#{time_style_id}\"><v>#{Xlsxrb::Ooxml::Utils.datetime_to_serial(value, date1904: @date1904)}</v></c>"
|
|
311
364
|
else
|
|
312
|
-
"<c r=\"#{col_ref}#{row_num_str}\"><v>#{Xlsxrb::Ooxml::Utils.datetime_to_serial(value)}</v></c>"
|
|
365
|
+
"<c r=\"#{col_ref}#{row_num_str}\"><v>#{Xlsxrb::Ooxml::Utils.datetime_to_serial(value, date1904: @date1904)}</v></c>"
|
|
313
366
|
end
|
|
314
367
|
when Xlsxrb::Elements::Formula
|
|
315
368
|
formula_expr = value.expression
|
|
316
369
|
formula_expr = formula_expr[1..] if formula_expr.start_with?("=")
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
370
|
+
f_attrs = +""
|
|
371
|
+
if value.type
|
|
372
|
+
case value.type.to_sym
|
|
373
|
+
when :array
|
|
374
|
+
f_attrs << ' t="array"'
|
|
375
|
+
f_attrs << %( ref="#{value.ref}") if value.ref
|
|
376
|
+
when :shared
|
|
377
|
+
f_attrs << ' t="shared"'
|
|
378
|
+
f_attrs << %( si="#{value.shared_index}") if value.shared_index
|
|
379
|
+
f_attrs << %( ref="#{value.ref}") if value.ref
|
|
380
|
+
end
|
|
381
|
+
end
|
|
382
|
+
f_attrs << ' ca="1"' if value.calculate_always
|
|
383
|
+
v_val = value.cached_value.nil? ? 0 : value.cached_value
|
|
384
|
+
buf << "<c r=\"#{col_ref}#{row_num_str}\"><f#{f_attrs}>#{escape_xml(formula_expr)}</f><v>#{v_val}</v></c>"
|
|
322
385
|
when Hash
|
|
323
386
|
if value.key?(:formula)
|
|
324
|
-
formula_expr = value[:formula]
|
|
387
|
+
formula_expr = value[:formula] || value[:expression]
|
|
325
388
|
formula_expr = formula_expr[1..] if formula_expr.start_with?("=")
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
389
|
+
f_attrs = +""
|
|
390
|
+
if value[:type]
|
|
391
|
+
case value[:type].to_sym
|
|
392
|
+
when :array
|
|
393
|
+
f_attrs << ' t="array"'
|
|
394
|
+
f_attrs << %( ref="#{value[:ref]}") if value[:ref]
|
|
395
|
+
when :shared
|
|
396
|
+
f_attrs << ' t="shared"'
|
|
397
|
+
f_attrs << %( si="#{value[:si] || value[:shared_index]}") if value[:si] || value[:shared_index]
|
|
398
|
+
f_attrs << %( ref="#{value[:ref]}") if value[:ref]
|
|
399
|
+
end
|
|
400
|
+
end
|
|
401
|
+
f_attrs << ' ca="1"' if value[:calculate_always]
|
|
402
|
+
xml_val = value[:value] || value[:cached_value] || 0
|
|
403
|
+
buf << "<c r=\"#{col_ref}#{row_num_str}\"><f#{f_attrs}>#{escape_xml(formula_expr)}</f><v>#{xml_val}</v></c>"
|
|
332
404
|
end
|
|
333
405
|
when Xlsxrb::Elements::CellError
|
|
334
406
|
buf << "<c r=\"#{col_ref}#{row_num_str}\" t=\"e\"><v>#{value.code}</v></c>"
|
|
@@ -360,6 +432,7 @@ module Xlsxrb
|
|
|
360
432
|
if attrs
|
|
361
433
|
buf << ' ht="' << attrs[:height].to_s << '" customHeight="1"' if attrs[:height]
|
|
362
434
|
buf << ' hidden="1"' if attrs[:hidden]
|
|
435
|
+
buf << ' collapsed="1"' if attrs[:collapsed]
|
|
363
436
|
buf << ' outlineLevel="' << attrs[:outline_level].to_s << '"' if attrs[:outline_level]
|
|
364
437
|
end
|
|
365
438
|
buf << ">"
|
|
@@ -370,17 +443,34 @@ module Xlsxrb
|
|
|
370
443
|
max_len = [max_len, styles_len].max
|
|
371
444
|
end
|
|
372
445
|
|
|
446
|
+
row_style = attrs ? attrs[:style_index] : nil
|
|
447
|
+
row_style_id = row_style && style_map ? (style_map[row_style] || style_map[row_style.to_s] || row_style) : row_style
|
|
448
|
+
|
|
373
449
|
col_index = 0
|
|
374
450
|
while col_index < max_len
|
|
375
451
|
value = col_index < values.length ? values[col_index] : nil
|
|
376
452
|
style_id = single_style_id
|
|
377
|
-
if is_styles_collection
|
|
453
|
+
if is_styles_collection
|
|
378
454
|
style_name = if styles.is_a?(Array)
|
|
379
455
|
col_index < styles.length ? styles[col_index] : nil
|
|
380
456
|
else
|
|
381
457
|
styles[col_index]
|
|
382
458
|
end
|
|
383
|
-
style_id = style_map
|
|
459
|
+
style_id = if style_map && style_name
|
|
460
|
+
style_map[style_name] || style_map[style_name.to_s] || style_name
|
|
461
|
+
else
|
|
462
|
+
style_name
|
|
463
|
+
end
|
|
464
|
+
end
|
|
465
|
+
|
|
466
|
+
if style_id.nil?
|
|
467
|
+
col_style = @column_styles ? @column_styles[col_index] : nil
|
|
468
|
+
col_style_id = if col_style && style_map
|
|
469
|
+
style_map[col_style] || style_map[col_style.to_s] || col_style
|
|
470
|
+
else
|
|
471
|
+
col_style
|
|
472
|
+
end
|
|
473
|
+
style_id = row_style_id || col_style_id
|
|
384
474
|
end
|
|
385
475
|
|
|
386
476
|
col_ref = COLUMN_LETTERS[col_index] || column_letter(col_index)
|
|
@@ -425,11 +515,11 @@ module Xlsxrb
|
|
|
425
515
|
col_index += 1
|
|
426
516
|
next
|
|
427
517
|
when Date
|
|
428
|
-
buf << '<c r="' << col_ref << row_num_str << '"><v>' << Xlsxrb::Ooxml::Utils.date_to_serial(value).to_s << "</v></c>"
|
|
518
|
+
buf << '<c r="' << col_ref << row_num_str << '"><v>' << Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: @date1904).to_s << "</v></c>"
|
|
429
519
|
col_index += 1
|
|
430
520
|
next
|
|
431
521
|
when Time
|
|
432
|
-
buf << '<c r="' << col_ref << row_num_str << '"><v>' << Xlsxrb::Ooxml::Utils.datetime_to_serial(value).to_s << "</v></c>"
|
|
522
|
+
buf << '<c r="' << col_ref << row_num_str << '"><v>' << Xlsxrb::Ooxml::Utils.datetime_to_serial(value, date1904: @date1904).to_s << "</v></c>"
|
|
433
523
|
col_index += 1
|
|
434
524
|
next
|
|
435
525
|
end
|
|
@@ -438,6 +528,9 @@ module Xlsxrb
|
|
|
438
528
|
# General path: styled, formula, rich text, or complex cell
|
|
439
529
|
formula_expr = nil
|
|
440
530
|
formula_ca = false
|
|
531
|
+
formula_type = nil
|
|
532
|
+
formula_ref = nil
|
|
533
|
+
formula_si = nil
|
|
441
534
|
xml_val = value
|
|
442
535
|
type = nil
|
|
443
536
|
|
|
@@ -445,6 +538,9 @@ module Xlsxrb
|
|
|
445
538
|
when Xlsxrb::Elements::Formula
|
|
446
539
|
formula_expr = value.expression
|
|
447
540
|
formula_ca = value.calculate_always
|
|
541
|
+
formula_type = value.type
|
|
542
|
+
formula_ref = value.ref
|
|
543
|
+
formula_si = value.shared_index
|
|
448
544
|
xml_val = value.cached_value
|
|
449
545
|
case value.cached_value
|
|
450
546
|
when String
|
|
@@ -458,9 +554,12 @@ module Xlsxrb
|
|
|
458
554
|
end
|
|
459
555
|
when Hash
|
|
460
556
|
if value.key?(:formula)
|
|
461
|
-
formula_expr = value[:formula]
|
|
557
|
+
formula_expr = value[:formula] || value[:expression]
|
|
462
558
|
formula_ca = value[:calculate_always] || false
|
|
463
|
-
|
|
559
|
+
formula_type = value[:type]
|
|
560
|
+
formula_ref = value[:ref]
|
|
561
|
+
formula_si = value[:si] || value[:shared_index]
|
|
562
|
+
xml_val = value[:value] || value[:cached_value]
|
|
464
563
|
case xml_val
|
|
465
564
|
when String
|
|
466
565
|
type = "str"
|
|
@@ -476,7 +575,7 @@ module Xlsxrb
|
|
|
476
575
|
if value.start_with?("=") && value.length > 1
|
|
477
576
|
formula_expr = value
|
|
478
577
|
xml_val = nil
|
|
479
|
-
|
|
578
|
+
elsif sst_index
|
|
480
579
|
idx = sst_index[value]
|
|
481
580
|
unless idx
|
|
482
581
|
sst << value
|
|
@@ -485,16 +584,24 @@ module Xlsxrb
|
|
|
485
584
|
end
|
|
486
585
|
xml_val = idx
|
|
487
586
|
type = "s"
|
|
587
|
+
else
|
|
588
|
+
xml_val = value
|
|
589
|
+
type = "inlineStr"
|
|
488
590
|
end
|
|
489
591
|
when Xlsxrb::Elements::RichText
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
592
|
+
if sst_index
|
|
593
|
+
idx = sst_index[value]
|
|
594
|
+
unless idx
|
|
595
|
+
sst << value
|
|
596
|
+
idx = sst.size - 1
|
|
597
|
+
sst_index[value] = idx
|
|
598
|
+
end
|
|
599
|
+
xml_val = idx
|
|
600
|
+
type = "s"
|
|
601
|
+
else
|
|
602
|
+
xml_val = value
|
|
603
|
+
type = "inlineStr"
|
|
495
604
|
end
|
|
496
|
-
xml_val = idx
|
|
497
|
-
type = "s"
|
|
498
605
|
when true
|
|
499
606
|
xml_val = "1"
|
|
500
607
|
type = "b"
|
|
@@ -502,9 +609,9 @@ module Xlsxrb
|
|
|
502
609
|
xml_val = "0"
|
|
503
610
|
type = "b"
|
|
504
611
|
when Date
|
|
505
|
-
xml_val = Xlsxrb::Ooxml::Utils.date_to_serial(value)
|
|
612
|
+
xml_val = Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: @date1904)
|
|
506
613
|
when Time
|
|
507
|
-
xml_val = Xlsxrb::Ooxml::Utils.datetime_to_serial(value)
|
|
614
|
+
xml_val = Xlsxrb::Ooxml::Utils.datetime_to_serial(value, date1904: @date1904)
|
|
508
615
|
when BigDecimal
|
|
509
616
|
xml_val = value.to_s("F")
|
|
510
617
|
when Xlsxrb::Elements::CellError
|
|
@@ -518,17 +625,27 @@ module Xlsxrb
|
|
|
518
625
|
buf << ' s="' << style_id.to_s << '"' if style_id
|
|
519
626
|
buf << ' t="' << type << '"' if type
|
|
520
627
|
if formula_expr
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
628
|
+
f_attrs = +""
|
|
629
|
+
if formula_type
|
|
630
|
+
case formula_type.to_sym
|
|
631
|
+
when :array
|
|
632
|
+
f_attrs << ' t="array"'
|
|
633
|
+
f_attrs << %( ref="#{formula_ref}") if formula_ref
|
|
634
|
+
when :shared
|
|
635
|
+
f_attrs << ' t="shared"'
|
|
636
|
+
f_attrs << %( si="#{formula_si}") if formula_si
|
|
637
|
+
f_attrs << %( ref="#{formula_ref}") if formula_ref
|
|
638
|
+
end
|
|
639
|
+
end
|
|
640
|
+
f_attrs << ' ca="1"' if formula_ca
|
|
641
|
+
buf << "<f#{f_attrs}>" << escape_xml(formula_expr) << "</f>"
|
|
527
642
|
if xml_val
|
|
528
643
|
buf << "<v>" << xml_val.to_s << "</v></c>"
|
|
529
644
|
else
|
|
530
|
-
buf << "</c>"
|
|
645
|
+
buf << "<v>0</v></c>"
|
|
531
646
|
end
|
|
647
|
+
elsif type == "inlineStr"
|
|
648
|
+
buf << "><is><t>" << escape_xml(xml_val.to_s) << "</t></is></c>"
|
|
532
649
|
else
|
|
533
650
|
buf << "><v>" << xml_val.to_s << "</v></c>"
|
|
534
651
|
end
|
|
@@ -945,7 +1062,8 @@ module Xlsxrb
|
|
|
945
1062
|
def write_hyperlinks(links)
|
|
946
1063
|
@builder.open_tag("hyperlinks")
|
|
947
1064
|
links.each_with_index do |link, idx|
|
|
948
|
-
|
|
1065
|
+
cell_ref = link[:cell] || link[:ref]
|
|
1066
|
+
h_attrs = { ref: cell_ref }
|
|
949
1067
|
h_attrs[:"r:id"] = "rId#{link[:_rid] || (idx + 1)}" if link[:url]
|
|
950
1068
|
h_attrs[:location] = link[:location] if link[:location]
|
|
951
1069
|
h_attrs[:display] = link[:display] if link[:display]
|
|
@@ -1106,6 +1224,8 @@ module Xlsxrb
|
|
|
1106
1224
|
attrs[:hidden] = "1" if col[:hidden]
|
|
1107
1225
|
attrs[:customWidth] = "1" if col[:custom_width] || col[:width]
|
|
1108
1226
|
attrs[:outlineLevel] = col[:outline_level].to_s if col[:outline_level]
|
|
1227
|
+
style_id = col[:style_index] || col[:style]
|
|
1228
|
+
attrs[:style] = style_id.to_s if style_id
|
|
1109
1229
|
@builder.empty_tag("col", attrs)
|
|
1110
1230
|
end
|
|
1111
1231
|
@builder.close_tag("cols")
|
|
@@ -1120,7 +1240,10 @@ module Xlsxrb
|
|
|
1120
1240
|
# For formula cells with cached values, don't infer type from value
|
|
1121
1241
|
type = formula ? cell[:type] : (cell[:type] || cell_type(value))
|
|
1122
1242
|
attrs[:t] = type if type
|
|
1123
|
-
|
|
1243
|
+
col_idx = cell[:column_index]
|
|
1244
|
+
col_style = @column_styles && col_idx ? @column_styles[col_idx] : nil
|
|
1245
|
+
style_id = cell[:style_index] || col_style
|
|
1246
|
+
attrs[:s] = style_id.to_s if style_id
|
|
1124
1247
|
|
|
1125
1248
|
if value.nil? && formula.nil?
|
|
1126
1249
|
@builder.empty_tag("c", attrs)
|
|
@@ -1130,14 +1253,36 @@ module Xlsxrb
|
|
|
1130
1253
|
@builder.open_tag("c", attrs)
|
|
1131
1254
|
if formula
|
|
1132
1255
|
f_attrs = {}
|
|
1133
|
-
|
|
1256
|
+
formula_text = formula
|
|
1257
|
+
if formula.is_a?(Xlsxrb::Elements::Formula)
|
|
1258
|
+
formula_text = formula.expression
|
|
1259
|
+
formula_text = formula_text[1..] if formula_text.start_with?("=")
|
|
1260
|
+
f_attrs[:t] = formula.type.to_s if formula.type
|
|
1261
|
+
f_attrs[:ref] = formula.ref if formula.ref
|
|
1262
|
+
f_attrs[:si] = formula.shared_index.to_s if formula.shared_index
|
|
1263
|
+
f_attrs[:ca] = "1" if formula.calculate_always
|
|
1264
|
+
else
|
|
1265
|
+
formula_text = formula_text[1..] if formula_text.is_a?(String) && formula_text.start_with?("=")
|
|
1266
|
+
f_type = cell[:formula_type] || cell[:type]
|
|
1267
|
+
if f_type && %i[array shared].include?(f_type.to_sym)
|
|
1268
|
+
f_attrs[:t] = f_type.to_s
|
|
1269
|
+
f_attrs[:ref] = cell[:formula_ref] || cell[:ref] if cell[:formula_ref] || (f_type.to_s == "array" && cell[:ref])
|
|
1270
|
+
f_attrs[:si] = cell[:formula_si].to_s if cell[:formula_si]
|
|
1271
|
+
end
|
|
1272
|
+
f_attrs[:ca] = "1" if cell[:formula_ca]
|
|
1273
|
+
end
|
|
1134
1274
|
if f_attrs.empty?
|
|
1135
|
-
@builder.tag("f") { |b| b.text(
|
|
1275
|
+
@builder.tag("f") { |b| b.text(formula_text) }
|
|
1136
1276
|
else
|
|
1137
|
-
@builder.tag("f", f_attrs) { |b| b.text(
|
|
1277
|
+
@builder.tag("f", f_attrs) { |b| b.text(formula_text) }
|
|
1138
1278
|
end
|
|
1139
1279
|
end
|
|
1140
|
-
|
|
1280
|
+
v_val = if value.nil?
|
|
1281
|
+
formula ? "0" : nil
|
|
1282
|
+
else
|
|
1283
|
+
xml_cell_value(value, type)
|
|
1284
|
+
end
|
|
1285
|
+
@builder.tag("v") { |b| b.text(v_val) } unless v_val.nil?
|
|
1141
1286
|
@builder.close_tag("c")
|
|
1142
1287
|
end
|
|
1143
1288
|
|
|
@@ -393,11 +393,13 @@ module Xlsxrb
|
|
|
393
393
|
when true, false
|
|
394
394
|
%(<c r="#{cell_ref}" t="b"#{s_attr}#{ph_attr}><v>#{value ? 1 : 0}</v></c>)
|
|
395
395
|
when Time
|
|
396
|
-
|
|
396
|
+
date1904 = @workbook_properties&.[](:date1904) ? true : false
|
|
397
|
+
serial = Xlsxrb::Ooxml::Utils.datetime_to_serial(value, date1904: date1904)
|
|
397
398
|
dt_attr = s_attr.empty? && (dt_style = resolve_style_index(datetime_num_fmt_id)) ? %( s="#{dt_style}") : s_attr
|
|
398
399
|
%(<c r="#{cell_ref}"#{dt_attr}#{ph_attr}><v>#{serial}</v></c>)
|
|
399
400
|
when Date
|
|
400
|
-
|
|
401
|
+
date1904 = @workbook_properties&.[](:date1904) ? true : false
|
|
402
|
+
serial = Xlsxrb::Ooxml::Utils.date_to_serial(value, date1904: date1904)
|
|
401
403
|
ds_attr = s_attr.empty? && (date_style = resolve_style_index(date_num_fmt_id)) ? %( s="#{date_style}") : s_attr
|
|
402
404
|
%(<c r="#{cell_ref}"#{ds_attr}#{ph_attr}><v>#{serial}</v></c>)
|
|
403
405
|
when Numeric
|
data/lib/xlsxrb/ooxml/writer.rb
CHANGED
|
@@ -330,6 +330,19 @@ module Xlsxrb
|
|
|
330
330
|
validate_cell_address!(cell_address)
|
|
331
331
|
sheet_name = sheet || @sheet_order.first
|
|
332
332
|
raise ArgumentError, "unknown sheet: #{sheet_name}" unless @hyperlinks.key?(sheet_name)
|
|
333
|
+
|
|
334
|
+
if url.is_a?(Elements::Hyperlink)
|
|
335
|
+
link = {}
|
|
336
|
+
link[:url] = url.url if url.url
|
|
337
|
+
link[:display] = url.display || display if url.display || display
|
|
338
|
+
link[:tooltip] = url.tooltip || tooltip if url.tooltip || tooltip
|
|
339
|
+
link[:location] = url.location || location if url.location || location
|
|
340
|
+
raise ArgumentError, "url or location required" if link[:url].nil? && link[:location].nil?
|
|
341
|
+
|
|
342
|
+
@hyperlinks[sheet_name][cell_address] = link
|
|
343
|
+
return
|
|
344
|
+
end
|
|
345
|
+
|
|
333
346
|
raise ArgumentError, "url or location required" if url.nil? && location.nil?
|
|
334
347
|
|
|
335
348
|
link = {}
|
|
@@ -997,6 +1010,7 @@ module Xlsxrb
|
|
|
997
1010
|
def set_workbook_property(name, value)
|
|
998
1011
|
@workbook_properties[name] = value
|
|
999
1012
|
end
|
|
1013
|
+
alias workbook_property set_workbook_property
|
|
1000
1014
|
|
|
1001
1015
|
# Returns workbook properties hash.
|
|
1002
1016
|
# : () -> untyped
|