xlsxrb 0.1.15 → 0.1.16
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 +61 -0
- data/README.md +22 -3
- data/benchmark/micro_ips.rb +70 -0
- data/lib/xlsxrb/elements/styles.rb +427 -15
- data/lib/xlsxrb/elements/workbook.rb +31 -4
- data/lib/xlsxrb/elements/worksheet.rb +22 -7
- data/lib/xlsxrb/ooxml/cfb.rb +10 -0
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +56 -38
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +7 -1
- data/lib/xlsxrb/ooxml/reader/listeners/style_listeners.rb +12 -7
- data/lib/xlsxrb/ooxml/reader.rb +165 -136
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +83 -28
- data/lib/xlsxrb/ooxml/styles_parser.rb +57 -14
- data/lib/xlsxrb/ooxml/utils.rb +59 -2
- data/lib/xlsxrb/ooxml/workbook_parser.rb +42 -3
- data/lib/xlsxrb/ooxml/workbook_writer.rb +215 -50
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +192 -123
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +238 -108
- data/lib/xlsxrb/ooxml/writer/drawing_xml.rb +16 -12
- data/lib/xlsxrb/ooxml/writer/styles_xml.rb +64 -15
- data/lib/xlsxrb/ooxml/writer.rb +31 -28
- data/lib/xlsxrb/ooxml/xml_builder.rb +12 -4
- data/lib/xlsxrb/ooxml/xml_parser.rb +45 -0
- data/lib/xlsxrb/ooxml/zip_reader.rb +48 -29
- data/lib/xlsxrb/stream_row.rb +4 -3
- data/lib/xlsxrb/stream_sheet.rb +26 -6
- data/lib/xlsxrb/stream_writer.rb +35 -14
- data/lib/xlsxrb/utils.rb +15 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +110 -10
- data/lib/xlsxrb/worksheet_builder.rb +15 -7
- data/lib/xlsxrb.rb +416 -108
- data/sig/generated/xlsxrb/elements/styles.rbs +271 -5
- data/sig/generated/xlsxrb/elements/workbook.rbs +26 -3
- data/sig/generated/xlsxrb/elements/worksheet.rbs +12 -2
- data/sig/generated/xlsxrb/ooxml/reader/listeners/style_listeners.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +12 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/utils.rbs +22 -0
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +7 -0
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +12 -0
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +18 -2
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/writer/styles_xml.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +4 -1
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +6 -6
- data/sig/generated/xlsxrb/stream_row.rbs +3 -2
- data/sig/generated/xlsxrb/stream_sheet.rbs +21 -5
- data/sig/generated/xlsxrb/stream_writer.rbs +18 -11
- data/sig/generated/xlsxrb/utils.rbs +13 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +3 -2
- data/sig/generated/xlsxrb.rbs +47 -10
- metadata +2 -1
|
@@ -24,12 +24,15 @@ module Xlsxrb
|
|
|
24
24
|
@runs = []
|
|
25
25
|
@current_font = {}
|
|
26
26
|
@has_runs = false
|
|
27
|
+
@inside_rph = false
|
|
27
28
|
end
|
|
28
29
|
|
|
29
30
|
def start_element(_uri, local_name, qname, attributes)
|
|
30
31
|
name = element_name(local_name, qname)
|
|
31
32
|
|
|
32
33
|
case name
|
|
34
|
+
when "rPh"
|
|
35
|
+
@inside_rph = true
|
|
33
36
|
when "si"
|
|
34
37
|
@inside_si = true
|
|
35
38
|
@text_buffer = +""
|
|
@@ -74,7 +77,7 @@ module Xlsxrb
|
|
|
74
77
|
when "scheme"
|
|
75
78
|
@current_font[:scheme] = attributes["val"] if @inside_rpr
|
|
76
79
|
when "t"
|
|
77
|
-
@inside_t = @inside_si
|
|
80
|
+
@inside_t = @inside_si && !@inside_rph
|
|
78
81
|
@text_buffer = +"" if @inside_r
|
|
79
82
|
end
|
|
80
83
|
end
|
|
@@ -87,12 +90,16 @@ module Xlsxrb
|
|
|
87
90
|
name = element_name(local_name, qname)
|
|
88
91
|
|
|
89
92
|
case name
|
|
93
|
+
when "rPh"
|
|
94
|
+
@inside_rph = false
|
|
90
95
|
when "t"
|
|
91
96
|
@inside_t = false
|
|
92
97
|
when "rPr"
|
|
93
98
|
@inside_rpr = false
|
|
94
99
|
when "r"
|
|
95
|
-
|
|
100
|
+
decoded_text = XmlBuilder.unescape(@text_buffer)
|
|
101
|
+
decoded_text = decoded_text.gsub("\r\n", "\n").tr("\r", "\n") if decoded_text.include?("\r")
|
|
102
|
+
run = { text: decoded_text }
|
|
96
103
|
run[:font] = @current_font.dup unless @current_font.empty?
|
|
97
104
|
@runs << run
|
|
98
105
|
@inside_r = false
|
|
@@ -100,7 +107,9 @@ module Xlsxrb
|
|
|
100
107
|
@strings << if @has_runs
|
|
101
108
|
Xlsxrb::Elements::RichText.new(runs: @runs)
|
|
102
109
|
else
|
|
103
|
-
@text_buffer
|
|
110
|
+
decoded_text = XmlBuilder.unescape(@text_buffer)
|
|
111
|
+
decoded_text = decoded_text.gsub("\r\n", "\n").tr("\r", "\n") if decoded_text.include?("\r")
|
|
112
|
+
decoded_text
|
|
104
113
|
end
|
|
105
114
|
@inside_si = false
|
|
106
115
|
@text_buffer = +""
|
|
@@ -145,18 +154,23 @@ module Xlsxrb
|
|
|
145
154
|
@is_has_runs = false
|
|
146
155
|
@is_current_font = {}
|
|
147
156
|
@is_run_text = +""
|
|
157
|
+
@inside_rph = false
|
|
158
|
+
@has_inline_text = false
|
|
148
159
|
end
|
|
149
160
|
|
|
150
161
|
def start_element(_uri, local_name, qname, attributes)
|
|
151
162
|
name = element_name(local_name, qname)
|
|
152
163
|
|
|
153
164
|
case name
|
|
165
|
+
when "rPh"
|
|
166
|
+
@inside_rph = true
|
|
154
167
|
when "row"
|
|
155
168
|
parse_row_attributes(attributes)
|
|
156
169
|
when "c"
|
|
157
170
|
@current_cell_ref = attributes["r"]
|
|
158
171
|
@current_cell_type = attributes["t"]
|
|
159
172
|
@current_cell_ph = %w[1 true].include?(attributes["ph"])
|
|
173
|
+
@has_inline_text = false
|
|
160
174
|
@value_buffer = +""
|
|
161
175
|
@inline_text_buffer = +""
|
|
162
176
|
@formula_buffer = +""
|
|
@@ -188,6 +202,7 @@ module Xlsxrb
|
|
|
188
202
|
@formula_r1 = attributes["r1"] if attributes["r1"]
|
|
189
203
|
@formula_r2 = attributes["r2"] if attributes["r2"]
|
|
190
204
|
when "is"
|
|
205
|
+
@has_inline_text = true
|
|
191
206
|
@inside_is = true if @current_cell_type == "inlineStr"
|
|
192
207
|
when "r"
|
|
193
208
|
if @inside_is
|
|
@@ -231,11 +246,15 @@ module Xlsxrb
|
|
|
231
246
|
when "scheme"
|
|
232
247
|
@is_current_font[:scheme] = attributes["val"] if @inside_is_rpr
|
|
233
248
|
when "t"
|
|
234
|
-
|
|
235
|
-
@
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
249
|
+
unless @inside_rph
|
|
250
|
+
if @inside_is_r
|
|
251
|
+
@is_run_text = +""
|
|
252
|
+
@inside_inline_text = true
|
|
253
|
+
@has_inline_text = true
|
|
254
|
+
elsif @inside_is || (@current_cell_type == "inlineStr" && !@current_cell_ref.nil?)
|
|
255
|
+
@inside_inline_text = true
|
|
256
|
+
@has_inline_text = true
|
|
257
|
+
end
|
|
239
258
|
end
|
|
240
259
|
end
|
|
241
260
|
end
|
|
@@ -256,6 +275,8 @@ module Xlsxrb
|
|
|
256
275
|
name = element_name(local_name, qname)
|
|
257
276
|
|
|
258
277
|
case name
|
|
278
|
+
when "rPh"
|
|
279
|
+
@inside_rph = false
|
|
259
280
|
when "v"
|
|
260
281
|
@inside_value = false
|
|
261
282
|
when "f"
|
|
@@ -309,7 +330,14 @@ module Xlsxrb
|
|
|
309
330
|
return if @current_cell_ref.nil?
|
|
310
331
|
|
|
311
332
|
unless @formula_buffer.empty? && @formula_type.nil?
|
|
312
|
-
cached = @value_buffer.empty?
|
|
333
|
+
cached = if @value_buffer.empty?
|
|
334
|
+
nil
|
|
335
|
+
elsif @current_cell_type == "b"
|
|
336
|
+
v = @value_buffer.strip
|
|
337
|
+
v == "1" || v.casecmp?("true")
|
|
338
|
+
else
|
|
339
|
+
@value_buffer.dup
|
|
340
|
+
end
|
|
313
341
|
f_type = { "shared" => :shared, "array" => :array, "dataTable" => :data_table }[@formula_type]
|
|
314
342
|
@cells[@current_cell_ref] = Xlsxrb::Elements::Formula.new(
|
|
315
343
|
expression: @formula_buffer.dup,
|
|
@@ -328,39 +356,29 @@ module Xlsxrb
|
|
|
328
356
|
return
|
|
329
357
|
end
|
|
330
358
|
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
Xlsxrb::Elements::RichText.new(runs: @is_runs.map(&:dup))
|
|
335
|
-
else
|
|
336
|
-
@inline_text_buffer.dup
|
|
337
|
-
end
|
|
338
|
-
when "s"
|
|
339
|
-
index = @value_buffer.to_i
|
|
340
|
-
@cells[@current_cell_ref] = @shared_strings[index] || ""
|
|
341
|
-
when "e"
|
|
342
|
-
code = @value_buffer.dup
|
|
343
|
-
@cells[@current_cell_ref] = if Xlsxrb::Elements::VALID_ERROR_CODES.include?(code)
|
|
344
|
-
Xlsxrb::Elements::CellError.new(code:)
|
|
345
|
-
else
|
|
346
|
-
code
|
|
347
|
-
end
|
|
348
|
-
when "b"
|
|
349
|
-
@cells[@current_cell_ref] = @value_buffer.strip == "1"
|
|
350
|
-
when nil, "", "n"
|
|
351
|
-
return if @value_buffer.empty?
|
|
352
|
-
|
|
353
|
-
raw = @value_buffer.dup
|
|
354
|
-
@cells[@current_cell_ref] = numeric_value(raw)
|
|
359
|
+
if @current_cell_type == "inlineStr" && @is_has_runs
|
|
360
|
+
@cells[@current_cell_ref] = Xlsxrb::Elements::RichText.new(runs: @is_runs.map(&:dup))
|
|
361
|
+
return
|
|
355
362
|
end
|
|
363
|
+
|
|
364
|
+
v = if @current_cell_type == "inlineStr"
|
|
365
|
+
@has_inline_text ? @inline_text_buffer : nil
|
|
366
|
+
else
|
|
367
|
+
@value_buffer.empty? ? nil : @value_buffer
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
val = Xlsxrb::Ooxml::WorksheetParser.resolve_cell_value(@current_cell_type, v, nil, @shared_strings)
|
|
371
|
+
return if val.nil? && (@current_cell_type.nil? || @current_cell_type == "" || @current_cell_type == "n" || @current_cell_type == "s" || @current_cell_type == "inlineStr")
|
|
372
|
+
|
|
373
|
+
@cells[@current_cell_ref] = if @current_cell_type == "e" && val && Xlsxrb::Elements::VALID_ERROR_CODES.include?(val)
|
|
374
|
+
Xlsxrb::Elements::CellError.new(code: val)
|
|
375
|
+
else
|
|
376
|
+
val
|
|
377
|
+
end
|
|
356
378
|
end
|
|
357
379
|
|
|
358
380
|
def numeric_value(raw)
|
|
359
|
-
|
|
360
|
-
raw.to_f
|
|
361
|
-
else
|
|
362
|
-
raw.to_i
|
|
363
|
-
end
|
|
381
|
+
Xlsxrb::Ooxml::WorksheetParser.numeric_cell_value(raw)
|
|
364
382
|
end
|
|
365
383
|
|
|
366
384
|
def element_name(local_name, qname)
|
|
@@ -962,11 +962,14 @@ module Xlsxrb
|
|
|
962
962
|
when "formula2"
|
|
963
963
|
@inside_formula2 = true
|
|
964
964
|
@text_buffer = +""
|
|
965
|
+
when "sqref"
|
|
966
|
+
@inside_sqref = true
|
|
967
|
+
@text_buffer = +""
|
|
965
968
|
end
|
|
966
969
|
end
|
|
967
970
|
|
|
968
971
|
def characters(text)
|
|
969
|
-
@text_buffer << text if @inside_formula1 || @inside_formula2
|
|
972
|
+
@text_buffer << text if @inside_formula1 || @inside_formula2 || @inside_sqref
|
|
970
973
|
end
|
|
971
974
|
|
|
972
975
|
def end_element(_uri, local_name, qname)
|
|
@@ -978,6 +981,9 @@ module Xlsxrb
|
|
|
978
981
|
when "formula2"
|
|
979
982
|
@current_dv[:formula2] = @text_buffer.dup if @current_dv
|
|
980
983
|
@inside_formula2 = false
|
|
984
|
+
when "sqref"
|
|
985
|
+
@current_dv[:sqref] = @text_buffer.strip if @current_dv && (@current_dv[:sqref].nil? || @current_dv[:sqref].empty?)
|
|
986
|
+
@inside_sqref = false
|
|
981
987
|
when "dataValidation"
|
|
982
988
|
@validations << @current_dv if @current_dv
|
|
983
989
|
@current_dv = nil
|
|
@@ -135,19 +135,19 @@ module Xlsxrb
|
|
|
135
135
|
when "font"
|
|
136
136
|
@current_font = {} if @inside_fonts || @inside_dxfs
|
|
137
137
|
when "b"
|
|
138
|
-
@current_font[:bold] =
|
|
138
|
+
@current_font[:bold] = truthy_val?(attributes) if @current_font
|
|
139
139
|
when "i"
|
|
140
|
-
@current_font[:italic] =
|
|
140
|
+
@current_font[:italic] = truthy_val?(attributes) if @current_font
|
|
141
141
|
when "strike"
|
|
142
|
-
@current_font[:strike] =
|
|
142
|
+
@current_font[:strike] = truthy_val?(attributes) if @current_font
|
|
143
143
|
when "shadow"
|
|
144
|
-
@current_font[:shadow] =
|
|
144
|
+
@current_font[:shadow] = truthy_val?(attributes) if @current_font
|
|
145
145
|
when "outline"
|
|
146
|
-
@current_font[:outline] =
|
|
146
|
+
@current_font[:outline] = truthy_val?(attributes) if @current_font
|
|
147
147
|
when "condense"
|
|
148
|
-
@current_font[:condense] =
|
|
148
|
+
@current_font[:condense] = truthy_val?(attributes) if @current_font
|
|
149
149
|
when "extend"
|
|
150
|
-
@current_font[:extend] =
|
|
150
|
+
@current_font[:extend] = truthy_val?(attributes) if @current_font
|
|
151
151
|
when "u"
|
|
152
152
|
if @current_font
|
|
153
153
|
val = attributes["val"]
|
|
@@ -303,6 +303,11 @@ module Xlsxrb
|
|
|
303
303
|
|
|
304
304
|
private
|
|
305
305
|
|
|
306
|
+
def truthy_val?(attributes)
|
|
307
|
+
val = attributes["val"]
|
|
308
|
+
val.nil? || (val != "0" && val.downcase != "false")
|
|
309
|
+
end
|
|
310
|
+
|
|
306
311
|
def parse_color(attributes)
|
|
307
312
|
if @inside_mru_colors
|
|
308
313
|
c = {}
|