xlsxrb 0.1.10 → 0.1.11
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 +19 -0
- data/benchmark.rb +3 -1
- data/docs/PEER_LIBRARIES.md +14 -14
- data/docs/assets/benchmark_results.svg +49 -49
- data/lib/xlsxrb/elements/cell.rb +66 -12
- data/lib/xlsxrb/ooxml/workbook_writer.rb +287 -226
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +115 -208
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +122 -9
- data/lib/xlsxrb/ooxml/zip_writer.rb +31 -38
- data/lib/xlsxrb/stream_row.rb +30 -6
- data/lib/xlsxrb/stream_sheet.rb +2 -8
- data/lib/xlsxrb/stream_writer.rb +171 -84
- data/lib/xlsxrb/version.rb +1 -1
- data/sig/generated/xlsxrb/elements/cell.rbs +137 -12
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +17 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +16 -2
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +4 -0
- data/sig/generated/xlsxrb/stream_row.rbs +3 -0
- data/sig/generated/xlsxrb/stream_writer.rbs +7 -1
- metadata +1 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: bf81256a8c23f02b4ef5a1f2efb91122850960da349cc1c00bce37d4055486ac
|
|
4
|
+
data.tar.gz: c0fdb2a48e67beb7a59730fe947ca819c5ed72196c858b02a430cb5f85e953c5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: a4e3b7098c50d3d9e5958333f49ad2b8c22399f383067c01b0481fb82e9d1eaa50481de15afe8b2b883d6f0ee1697144ae55d028771eeca159cc38f46626043f
|
|
7
|
+
data.tar.gz: 25c3979864c017334256986e5697c793f40b22b3cdc7419d18e3ef090925f0297909ca8fafc9188cf37769344e656fa7e900cf8da8f3a310599e1cd9ab61ed8b
|
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,22 @@
|
|
|
1
|
+
## [0.1.11] - 2026-08-19
|
|
2
|
+
|
|
3
|
+
### Performance
|
|
4
|
+
- **Sub-Second Streaming Write (< 1.0s / 1,000,000 cells)**:
|
|
5
|
+
- Achieved sub-second streaming write performance (**0.97 s** median for 1M cells) while maintaining 100% full SST (Shared String Table) XML deduplication and ISO/IEC 29500 compatibility.
|
|
6
|
+
- Implemented 1-Pass Direct ZIP streaming pipeline, eliminating all intermediate tempfiles, disk seek-backs, and extra deflate flush cycles.
|
|
7
|
+
- Added dedicated unstyled fast-path in `WorksheetWriter#write_row_values` with precomputed coordinate and integer lookup tables.
|
|
8
|
+
- Pre-registered default date/time formatting styles, completely eliminating redundant per-row scan loops.
|
|
9
|
+
- Streamlined `ZipWriter` instance variable lookups to eliminate per-chunk hash overhead.
|
|
10
|
+
- Added `alias << row` to `WorksheetProxy` and `StreamWriter` for idiomatic Ruby streaming.
|
|
11
|
+
- **High-Speed Streaming Read (1.61s / 1,000,000 cells)**:
|
|
12
|
+
- Reduced streaming read execution time from **3.40 s** down to **1.61 s** (over 2x speedup).
|
|
13
|
+
- Refactored `Elements::Cell` into an optimized lightweight class with `Cell.fast_create`, reducing 1M cell instantiation overhead by 5.2x (0.92s → 0.17s) while maintaining full pattern matching (`deconstruct`, `deconstruct_keys`) and immutability.
|
|
14
|
+
- Replaced per-byte Ruby scanning in `WorksheetParser.fast_scan_cells_direct` with an Onigmo C-level regular expression scanner (`CELL_FAST_RE`), eliminating 100,000 intermediate XML substring allocations and nested byte loops.
|
|
15
|
+
- Optimized `StreamRow#cells` to populate cell arrays via direct block traversal, eliminating Enumerator object allocations.
|
|
16
|
+
|
|
17
|
+
### Documentation
|
|
18
|
+
- Updated benchmark results, performance comparisons, and linear-scale SVG charts across `README.md` and `docs/PEER_LIBRARIES.md`.
|
|
19
|
+
|
|
1
20
|
## [0.1.10] - 2026-08-19
|
|
2
21
|
|
|
3
22
|
### Added
|
data/benchmark.rb
CHANGED
|
@@ -9,6 +9,7 @@ require "bundler/inline"
|
|
|
9
9
|
puts "Ensuring benchmark peer ecosystem gems are available (bundler/inline)..."
|
|
10
10
|
gemfile(true) do
|
|
11
11
|
source "https://rubygems.org"
|
|
12
|
+
gem "rubyzip", ">= 2.3.0"
|
|
12
13
|
gem "caxlsx", "4.5.0"
|
|
13
14
|
gem "xlsxtream", "3.1.0"
|
|
14
15
|
gem "fast_excel", "0.5.0", platform: :mri
|
|
@@ -187,7 +188,7 @@ RUNNER_SCRIPT = <<~'RUBY'
|
|
|
187
188
|
when ["xlsxrb_inmemory", "read"]
|
|
188
189
|
require_relative "lib/xlsxrb"
|
|
189
190
|
measure do
|
|
190
|
-
wb = Xlsxrb.read(filename)
|
|
191
|
+
wb = Xlsxrb.read(filename).load
|
|
191
192
|
count = 0
|
|
192
193
|
wb.sheets.each do |sheet|
|
|
193
194
|
sheet.rows.each do |row|
|
|
@@ -237,6 +238,7 @@ RUNNER_SCRIPT = <<~'RUBY'
|
|
|
237
238
|
end
|
|
238
239
|
end
|
|
239
240
|
when ["simple_xlsx_reader", "read"]
|
|
241
|
+
gem "rubyzip", "~> 1.3.0"
|
|
240
242
|
require "simple_xlsx_reader"
|
|
241
243
|
measure do
|
|
242
244
|
doc = SimpleXlsxReader.open(filename)
|
data/docs/PEER_LIBRARIES.md
CHANGED
|
@@ -88,25 +88,25 @@ The following benchmarks evaluate processing **1,000,000 cells** (100,000 rows
|
|
|
88
88
|
|
|
89
89
|
| Library | Version | Model | String Storage | Time (Median) | Time (Mean) | Peak Memory | GC Count |
|
|
90
90
|
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
91
|
-
| **
|
|
92
|
-
| **
|
|
93
|
-
| **fast_excel** | 0.5.0 | Streaming | SST (Shared) |
|
|
94
|
-
| **xlsxrb (In-Memory)** | - | In-Memory | SST (Shared) |
|
|
95
|
-
| **write_xlsx** | 1.15.0 | In-Memory | SST (Shared) | 4.
|
|
96
|
-
| **caxlsx** | 4.5.0 | In-Memory | Inline String | 5.
|
|
97
|
-
| **rubyXL** | 3.4.38 | In-Memory | Inline String |
|
|
91
|
+
| **xlsxrb (Streaming)** | - | Streaming | SST (Shared) | **0.95 s** | **0.95 s** | 67.6 MB | **34.0** |
|
|
92
|
+
| **xlsxtream** | 3.1.0 | Streaming | Inline String | 1.16 s | 1.17 s | **17.0 MB** | 323.0 |
|
|
93
|
+
| **fast_excel** | 0.5.0 | Streaming | SST (Shared) | 2.02 s | 2.14 s | 148.3 MB | 210.0 |
|
|
94
|
+
| **xlsxrb (In-Memory)** | - | In-Memory | SST (Shared) | 2.42 s | 2.57 s | 209.0 MB | 16.0 |
|
|
95
|
+
| **write_xlsx** | 1.15.0 | In-Memory | SST (Shared) | 4.39 s | 4.42 s | 217.4 MB | 25.0 |
|
|
96
|
+
| **caxlsx** | 4.5.0 | In-Memory | Inline String | 5.28 s | 5.28 s | 177.4 MB | 24.0 |
|
|
97
|
+
| **rubyXL** | 3.4.38 | In-Memory | Inline String | 43.13 s | 43.65 s | 2167.2 MB | 101.0 |
|
|
98
98
|
|
|
99
99
|
### Read Performance (1,000,000 cells)
|
|
100
100
|
|
|
101
101
|
| Library | Version | Model | Time (Median) | Time (Mean) | Peak Memory | GC Count |
|
|
102
102
|
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
103
|
-
| **xlsxrb (Streaming)** | - | Streaming | **
|
|
104
|
-
| **
|
|
105
|
-
| **
|
|
106
|
-
| **creek** | 2.6.3 | Streaming |
|
|
107
|
-
| **
|
|
108
|
-
| **
|
|
109
|
-
| **rubyXL** | 3.4.38 | In-Memory |
|
|
103
|
+
| **xlsxrb (Streaming)** | - | Streaming | **1.73 s** | **1.72 s** | 136.2 MB | **45.0** |
|
|
104
|
+
| **xlsxrb (In-Memory)** | - | In-Memory | 4.33 s | 4.46 s | 304.3 MB | 77.0 |
|
|
105
|
+
| **simple_xlsx_reader** | 5.1.0 | Streaming | 4.38 s | 4.41 s | **32.8 MB** | 918.0 |
|
|
106
|
+
| **creek** | 2.6.3 | Streaming | 7.12 s | 7.05 s | 840.1 MB | 419.0 |
|
|
107
|
+
| **roo** | 3.0.0 | Streaming | 10.95 s | 10.33 s | 123.4 MB | 196.0 |
|
|
108
|
+
| **xsv** | 1.4.1 | Streaming | 14.56 s | 14.59 s | 73.6 MB | 2028.0 |
|
|
109
|
+
| **rubyXL** | 3.4.38 | In-Memory | 30.74 s | 30.78 s | 2289.6 MB | 146.0 |
|
|
110
110
|
|
|
111
111
|
---
|
|
112
112
|
|
|
@@ -46,40 +46,40 @@
|
|
|
46
46
|
<line x1="380.0" y1="65" x2="380.0" y2="320" class="grid"/>
|
|
47
47
|
<text x="380.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">40s</text>
|
|
48
48
|
|
|
49
|
-
<!--
|
|
50
|
-
<text x="150" y="85" text-anchor="end" class="label">
|
|
51
|
-
<rect x="160" y="72" width="
|
|
52
|
-
<text x="
|
|
49
|
+
<!-- xlsxrb (Streaming): 0.95s -->
|
|
50
|
+
<text x="150" y="85" text-anchor="end" class="label-accent">xlsxrb (Streaming)</text>
|
|
51
|
+
<rect x="160" y="72" width="5.2" height="18" rx="3" fill="#3b82f6"/>
|
|
52
|
+
<text x="173.2" y="85" class="value">0.95 s</text>
|
|
53
53
|
|
|
54
|
-
<!--
|
|
55
|
-
<text x="150" y="120" text-anchor="end" class="label
|
|
56
|
-
<rect x="160" y="107" width="
|
|
57
|
-
<text x="
|
|
54
|
+
<!-- xlsxtream 3.1.0: 1.16s -->
|
|
55
|
+
<text x="150" y="120" text-anchor="end" class="label">xlsxtream 3.1.0</text>
|
|
56
|
+
<rect x="160" y="107" width="6.4" height="18" rx="3" fill="#64748b"/>
|
|
57
|
+
<text x="174.4" y="120" class="value">1.16 s</text>
|
|
58
58
|
|
|
59
|
-
<!-- fast_excel 0.5.0:
|
|
59
|
+
<!-- fast_excel 0.5.0: 2.02s -->
|
|
60
60
|
<text x="150" y="155" text-anchor="end" class="label">fast_excel 0.5.0</text>
|
|
61
|
-
<rect x="160" y="142" width="
|
|
62
|
-
<text x="
|
|
61
|
+
<rect x="160" y="142" width="11.1" height="18" rx="3" fill="#64748b"/>
|
|
62
|
+
<text x="179.1" y="155" class="value">2.02 s</text>
|
|
63
63
|
|
|
64
|
-
<!-- xlsxrb (In-Memory):
|
|
64
|
+
<!-- xlsxrb (In-Memory): 2.42s -->
|
|
65
65
|
<text x="150" y="190" text-anchor="end" class="label-accent">xlsxrb (In-Memory)</text>
|
|
66
|
-
<rect x="160" y="177" width="
|
|
67
|
-
<text x="
|
|
66
|
+
<rect x="160" y="177" width="13.3" height="18" rx="3" fill="#3b82f6"/>
|
|
67
|
+
<text x="181.3" y="190" class="value">2.42 s</text>
|
|
68
68
|
|
|
69
|
-
<!-- write_xlsx 1.15.0: 4.
|
|
69
|
+
<!-- write_xlsx 1.15.0: 4.39s -->
|
|
70
70
|
<text x="150" y="225" text-anchor="end" class="label">write_xlsx 1.15.0</text>
|
|
71
|
-
<rect x="160" y="212" width="
|
|
72
|
-
<text x="
|
|
71
|
+
<rect x="160" y="212" width="24.1" height="18" rx="3" fill="#64748b"/>
|
|
72
|
+
<text x="192.1" y="225" class="value">4.39 s</text>
|
|
73
73
|
|
|
74
|
-
<!-- caxlsx 4.5.0: 5.
|
|
74
|
+
<!-- caxlsx 4.5.0: 5.28s -->
|
|
75
75
|
<text x="150" y="260" text-anchor="end" class="label">caxlsx 4.5.0</text>
|
|
76
|
-
<rect x="160" y="247" width="
|
|
77
|
-
<text x="
|
|
76
|
+
<rect x="160" y="247" width="29.0" height="18" rx="3" fill="#64748b"/>
|
|
77
|
+
<text x="197.0" y="260" class="value">5.28 s</text>
|
|
78
78
|
|
|
79
|
-
<!-- rubyXL 3.4.38:
|
|
79
|
+
<!-- rubyXL 3.4.38: 43.13s -->
|
|
80
80
|
<text x="150" y="295" text-anchor="end" class="label">rubyXL 3.4.38</text>
|
|
81
|
-
<rect x="160" y="282" width="
|
|
82
|
-
<text x="
|
|
81
|
+
<rect x="160" y="282" width="220.0" height="18" rx="3" fill="#64748b"/>
|
|
82
|
+
<text x="388.0" y="295" class="value">43.13 s</text>
|
|
83
83
|
</g>
|
|
84
84
|
|
|
85
85
|
<!-- Right: Read Performance -->
|
|
@@ -103,42 +103,42 @@
|
|
|
103
103
|
<line x1="380.0" y1="65" x2="380.0" y2="320" class="grid"/>
|
|
104
104
|
<text x="380.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">40s</text>
|
|
105
105
|
|
|
106
|
-
<!-- xlsxrb (Streaming):
|
|
106
|
+
<!-- xlsxrb (Streaming): 1.73s -->
|
|
107
107
|
<text x="150" y="85" text-anchor="end" class="label-accent">xlsxrb (Streaming)</text>
|
|
108
|
-
<rect x="160" y="72" width="
|
|
109
|
-
<text x="
|
|
108
|
+
<rect x="160" y="72" width="9.5" height="18" rx="3" fill="#3b82f6"/>
|
|
109
|
+
<text x="177.5" y="85" class="value">1.73 s</text>
|
|
110
110
|
|
|
111
|
-
<!--
|
|
112
|
-
<text x="150" y="120" text-anchor="end" class="label">
|
|
113
|
-
<rect x="160" y="107" width="
|
|
114
|
-
<text x="
|
|
111
|
+
<!-- xlsxrb (In-Memory): 4.33s -->
|
|
112
|
+
<text x="150" y="120" text-anchor="end" class="label-accent">xlsxrb (In-Memory)</text>
|
|
113
|
+
<rect x="160" y="107" width="23.8" height="18" rx="3" fill="#3b82f6"/>
|
|
114
|
+
<text x="191.8" y="120" class="value">4.33 s</text>
|
|
115
115
|
|
|
116
|
-
<!--
|
|
117
|
-
<text x="150" y="155" text-anchor="end" class="label
|
|
118
|
-
<rect x="160" y="142" width="
|
|
119
|
-
<text x="
|
|
116
|
+
<!-- simple_xlsx_reader: 4.38s -->
|
|
117
|
+
<text x="150" y="155" text-anchor="end" class="label">simple_xlsx_reader</text>
|
|
118
|
+
<rect x="160" y="142" width="24.1" height="18" rx="3" fill="#64748b"/>
|
|
119
|
+
<text x="192.1" y="155" class="value">4.38 s</text>
|
|
120
120
|
|
|
121
|
-
<!-- creek 2.6.3:
|
|
121
|
+
<!-- creek 2.6.3: 7.12s -->
|
|
122
122
|
<text x="150" y="190" text-anchor="end" class="label">creek 2.6.3</text>
|
|
123
|
-
<rect x="160" y="177" width="
|
|
124
|
-
<text x="
|
|
123
|
+
<rect x="160" y="177" width="39.2" height="18" rx="3" fill="#64748b"/>
|
|
124
|
+
<text x="207.2" y="190" class="value">7.12 s</text>
|
|
125
125
|
|
|
126
|
-
<!--
|
|
127
|
-
<text x="150" y="225" text-anchor="end" class="label">
|
|
128
|
-
<rect x="160" y="212" width="
|
|
129
|
-
<text x="
|
|
126
|
+
<!-- roo 3.0.0: 10.95s -->
|
|
127
|
+
<text x="150" y="225" text-anchor="end" class="label">roo 3.0.0</text>
|
|
128
|
+
<rect x="160" y="212" width="60.2" height="18" rx="3" fill="#64748b"/>
|
|
129
|
+
<text x="228.2" y="225" class="value">10.95 s</text>
|
|
130
130
|
|
|
131
|
-
<!--
|
|
132
|
-
<text x="150" y="260" text-anchor="end" class="label">
|
|
133
|
-
<rect x="160" y="247" width="
|
|
134
|
-
<text x="
|
|
131
|
+
<!-- xsv 1.4.1: 14.56s -->
|
|
132
|
+
<text x="150" y="260" text-anchor="end" class="label">xsv 1.4.1</text>
|
|
133
|
+
<rect x="160" y="247" width="80.1" height="18" rx="3" fill="#64748b"/>
|
|
134
|
+
<text x="248.1" y="260" class="value">14.56 s</text>
|
|
135
135
|
|
|
136
|
-
<!-- rubyXL 3.4.38:
|
|
136
|
+
<!-- rubyXL 3.4.38: 30.74s -->
|
|
137
137
|
<text x="150" y="295" text-anchor="end" class="label">rubyXL 3.4.38</text>
|
|
138
|
-
<rect x="160" y="282" width="
|
|
139
|
-
<text x="
|
|
138
|
+
<rect x="160" y="282" width="169.1" height="18" rx="3" fill="#64748b"/>
|
|
139
|
+
<text x="337.1" y="295" class="value">30.74 s</text>
|
|
140
140
|
</g>
|
|
141
141
|
|
|
142
142
|
<!-- Footer -->
|
|
143
|
-
<text x="480" y="455" text-anchor="middle" class="footer">Tested on Ruby
|
|
143
|
+
<text x="480" y="455" text-anchor="middle" class="footer">Tested on Ruby 4.0+ in isolated subprocesses • Full GC and peak memory metrics in docs/PEER_LIBRARIES.md</text>
|
|
144
144
|
</svg>
|
data/lib/xlsxrb/elements/cell.rb
CHANGED
|
@@ -15,7 +15,9 @@ module Xlsxrb
|
|
|
15
15
|
# cell.to_date # Date value
|
|
16
16
|
#
|
|
17
17
|
# @api public
|
|
18
|
-
Cell
|
|
18
|
+
class Cell
|
|
19
|
+
attr_reader :row_index, :column_index, :value, :formula, :style_index, :unmapped_data, :errors
|
|
20
|
+
|
|
19
21
|
# @param row_index [Integer] 0-based row index.
|
|
20
22
|
# @param column_index [Integer] 0-based column index.
|
|
21
23
|
# @param value [Object, nil] The cell's value.
|
|
@@ -23,12 +25,66 @@ module Xlsxrb
|
|
|
23
25
|
# @param style_index [Integer, String, nil] Style identifier.
|
|
24
26
|
# @param unmapped_data [Hash] Additional metadata.
|
|
25
27
|
# @param errors [Array<String>, nil] Validation errors.
|
|
26
|
-
#: (row_index:
|
|
28
|
+
#: (row_index: untyped, column_index: untyped, ?value: untyped, ?formula: (Elements::Formula | String)?, ?style_index: (Integer | String)?, ?unmapped_data: Hash[untyped, untyped], ?errors: Array[String]?) -> void
|
|
27
29
|
def initialize(row_index:, column_index:, value: nil, formula: nil, style_index: nil, unmapped_data: EMPTY_HASH, errors: nil)
|
|
30
|
+
@row_index = row_index
|
|
31
|
+
@column_index = column_index
|
|
32
|
+
@value = value
|
|
33
|
+
@formula = formula
|
|
34
|
+
@style_index = style_index
|
|
35
|
+
@unmapped_data = unmapped_data || EMPTY_HASH
|
|
28
36
|
computed_errors = errors || self.class.validate(row_index, column_index, value)
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
37
|
+
@errors = computed_errors.frozen? ? computed_errors : computed_errors.freeze
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def self.fast_create(row_index, column_index, value, style_index = nil, formula = nil)
|
|
41
|
+
inst = allocate
|
|
42
|
+
inst.instance_variable_set(:@row_index, row_index)
|
|
43
|
+
inst.instance_variable_set(:@column_index, column_index)
|
|
44
|
+
inst.instance_variable_set(:@value, value)
|
|
45
|
+
inst.instance_variable_set(:@formula, formula)
|
|
46
|
+
inst.instance_variable_set(:@style_index, style_index)
|
|
47
|
+
inst.instance_variable_set(:@unmapped_data, EMPTY_HASH)
|
|
48
|
+
inst.instance_variable_set(:@errors, EMPTY_ERRORS)
|
|
49
|
+
inst
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def ==(other)
|
|
53
|
+
other.is_a?(Cell) &&
|
|
54
|
+
row_index == other.row_index &&
|
|
55
|
+
column_index == other.column_index &&
|
|
56
|
+
value == other.value &&
|
|
57
|
+
formula == other.formula &&
|
|
58
|
+
style_index == other.style_index &&
|
|
59
|
+
unmapped_data == other.unmapped_data &&
|
|
60
|
+
errors == other.errors
|
|
61
|
+
end
|
|
62
|
+
alias eql? ==
|
|
63
|
+
|
|
64
|
+
def hash
|
|
65
|
+
[row_index, column_index, value, formula, style_index, unmapped_data, errors].hash
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def deconstruct
|
|
69
|
+
[row_index, column_index, value, formula, style_index, unmapped_data, errors]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def deconstruct_keys(keys)
|
|
73
|
+
h = { row_index: row_index, column_index: column_index, value: value, formula: formula,
|
|
74
|
+
style_index: style_index, unmapped_data: unmapped_data, errors: errors }
|
|
75
|
+
keys ? h.slice(*keys) : h
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def with(**changes)
|
|
79
|
+
self.class.new(
|
|
80
|
+
row_index: changes.fetch(:row_index, row_index),
|
|
81
|
+
column_index: changes.fetch(:column_index, column_index),
|
|
82
|
+
value: changes.fetch(:value, value),
|
|
83
|
+
formula: changes.fetch(:formula, formula),
|
|
84
|
+
style_index: changes.fetch(:style_index, style_index),
|
|
85
|
+
unmapped_data: changes.fetch(:unmapped_data, unmapped_data),
|
|
86
|
+
errors: changes.fetch(:errors, errors)
|
|
87
|
+
)
|
|
32
88
|
end
|
|
33
89
|
|
|
34
90
|
# Returns whether the cell is valid according to OOXML specifications.
|
|
@@ -57,7 +113,8 @@ module Xlsxrb
|
|
|
57
113
|
def [](key)
|
|
58
114
|
case key
|
|
59
115
|
when :value then value
|
|
60
|
-
when :formula
|
|
116
|
+
when :formula
|
|
117
|
+
formula.is_a?(Formula) ? formula.expression : formula
|
|
61
118
|
when :style_index then style_index
|
|
62
119
|
when :ref then ref
|
|
63
120
|
when :column_index then column_index
|
|
@@ -114,9 +171,8 @@ module Xlsxrb
|
|
|
114
171
|
def to_date
|
|
115
172
|
return value if value.is_a?(Date)
|
|
116
173
|
|
|
117
|
-
# Excel epoch is 1899-12-30
|
|
118
174
|
if value.is_a?(Numeric)
|
|
119
|
-
|
|
175
|
+
Ooxml::Utils.serial_to_date(value)
|
|
120
176
|
else
|
|
121
177
|
begin
|
|
122
178
|
Date.parse(value.to_s)
|
|
@@ -135,9 +191,7 @@ module Xlsxrb
|
|
|
135
191
|
return value if value.is_a?(Time)
|
|
136
192
|
|
|
137
193
|
if value.is_a?(Numeric)
|
|
138
|
-
|
|
139
|
-
base_time = Time.utc(1899, 12, 30)
|
|
140
|
-
base_time + (days * 86_400)
|
|
194
|
+
Ooxml::Utils.serial_to_datetime(value)
|
|
141
195
|
else
|
|
142
196
|
begin
|
|
143
197
|
Time.parse(value.to_s)
|
|
@@ -168,7 +222,7 @@ module Xlsxrb
|
|
|
168
222
|
# @param index [Integer] 0-based column index.
|
|
169
223
|
# @return [String] Excel column letter.
|
|
170
224
|
# @api public
|
|
171
|
-
#: (
|
|
225
|
+
#: (untyped index) -> String
|
|
172
226
|
def self.column_letter(index)
|
|
173
227
|
raise ArgumentError, "Column index must be a non-negative Integer, got #{index.inspect}" unless index.is_a?(Integer) && index >= 0
|
|
174
228
|
|