xlsxrb 0.1.11 → 0.1.13
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 +86 -34
- data/README.md +26 -21
- data/lib/xlsxrb/chart_builder.rb +18 -18
- data/lib/xlsxrb/dsl_helpers.rb +175 -0
- data/lib/xlsxrb/elements/cell.rb +56 -22
- data/lib/xlsxrb/elements/column.rb +27 -3
- data/lib/xlsxrb/elements/row.rb +27 -8
- data/lib/xlsxrb/elements/workbook.rb +27 -14
- data/lib/xlsxrb/elements/worksheet.rb +17 -1
- data/lib/xlsxrb/ooxml/cfb.rb +9 -6
- data/lib/xlsxrb/ooxml/crypto/agile.rb +5 -5
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +784 -0
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +3478 -0
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +1796 -0
- data/lib/xlsxrb/ooxml/reader/listeners/style_listeners.rb +428 -0
- data/lib/xlsxrb/ooxml/reader/listeners.rb +4 -6446
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +3 -5
- data/lib/xlsxrb/ooxml/utils.rb +5 -6
- data/lib/xlsxrb/ooxml/workbook_writer.rb +5 -7
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +172 -9
- data/lib/xlsxrb/ooxml/writer/drawing_xml.rb +1602 -0
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +731 -0
- data/lib/xlsxrb/ooxml/writer/styles_xml.rb +348 -0
- data/lib/xlsxrb/ooxml/writer.rb +9 -2646
- data/lib/xlsxrb/ooxml/xml_builder.rb +31 -2
- data/lib/xlsxrb/ooxml/zip_generator.rb +26 -5
- data/lib/xlsxrb/ooxml/zip_reader.rb +364 -78
- data/lib/xlsxrb/ooxml/zip_writer.rb +32 -5
- data/lib/xlsxrb/stream_sheet.rb +94 -6
- data/lib/xlsxrb/stream_writer.rb +48 -115
- data/lib/xlsxrb/style_builder.rb +10 -1
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +1 -1
- data/lib/xlsxrb/worksheet_builder.rb +19 -81
- data/lib/xlsxrb.rb +449 -171
- data/sig/generated/xlsxrb/chart_builder.rbs +36 -36
- data/sig/generated/xlsxrb/dsl_helpers.rbs +92 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +29 -0
- data/sig/generated/xlsxrb/elements/column.rbs +32 -21
- data/sig/generated/xlsxrb/elements/row.rbs +94 -14
- data/sig/generated/xlsxrb/elements/workbook.rbs +102 -10
- data/sig/generated/xlsxrb/elements/worksheet.rbs +9 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners/core_listeners.rbs +173 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners/drawing_listeners.rbs +400 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners/feature_listeners.rbs +442 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners/style_listeners.rbs +80 -0
- data/sig/generated/xlsxrb/ooxml/reader/listeners.rbs +0 -1072
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +0 -2
- data/sig/generated/xlsxrb/ooxml/utils.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +5 -4
- data/sig/generated/xlsxrb/ooxml/writer/drawing_xml.rbs +79 -0
- data/sig/generated/xlsxrb/ooxml/writer/features_xml.rbs +83 -0
- data/sig/generated/xlsxrb/ooxml/writer/styles_xml.rbs +53 -0
- data/sig/generated/xlsxrb/ooxml/writer.rbs +6 -185
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +18 -0
- data/sig/generated/xlsxrb/ooxml/zip_generator.rbs +15 -0
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +96 -8
- data/sig/generated/xlsxrb/ooxml/zip_writer.rbs +5 -1
- data/sig/generated/xlsxrb/stream_sheet.rbs +43 -3
- data/sig/generated/xlsxrb/style_builder.rbs +7 -0
- data/sig/generated/xlsxrb.rbs +18 -11
- metadata +22 -144
- data/.devcontainer/Dockerfile +0 -65
- data/.devcontainer/devcontainer.json +0 -17
- data/.gem_rbs_collection/ast/2.4/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/ast/2.4/ast.rbs +0 -73
- data/.gem_rbs_collection/concurrent-ruby/1.1/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/concurrent-ruby/1.1/array.rbs +0 -4
- data/.gem_rbs_collection/concurrent-ruby/1.1/atomic_reference.rbs +0 -16
- data/.gem_rbs_collection/concurrent-ruby/1.1/executor.rbs +0 -96
- data/.gem_rbs_collection/concurrent-ruby/1.1/hash.rbs +0 -4
- data/.gem_rbs_collection/concurrent-ruby/1.1/map.rbs +0 -68
- data/.gem_rbs_collection/concurrent-ruby/1.1/promises.rbs +0 -249
- data/.gem_rbs_collection/concurrent-ruby/1.1/set.rbs +0 -4
- data/.gem_rbs_collection/concurrent-ruby/1.1/timer_task.rbs +0 -47
- data/.gem_rbs_collection/concurrent-ruby/1.1/utility/processor_counter.rbs +0 -5
- data/.gem_rbs_collection/csv/3.3/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/csv/3.3/csv.rbs +0 -3871
- data/.gem_rbs_collection/csv/3.3/manifest.yaml +0 -3
- data/.gem_rbs_collection/lint_roller/1.1/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/lint_roller/1.1/lint_roller.rbs +0 -48
- data/.gem_rbs_collection/listen/3.9/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/listen/3.9/listen.rbs +0 -25
- data/.gem_rbs_collection/listen/3.9/listener.rbs +0 -24
- data/.gem_rbs_collection/logger/1.7/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/logger/1.7/formatter.rbs +0 -45
- data/.gem_rbs_collection/logger/1.7/log_device.rbs +0 -100
- data/.gem_rbs_collection/logger/1.7/logger.rbs +0 -796
- data/.gem_rbs_collection/logger/1.7/manifest.yaml +0 -2
- data/.gem_rbs_collection/logger/1.7/period.rbs +0 -17
- data/.gem_rbs_collection/logger/1.7/severity.rbs +0 -34
- data/.gem_rbs_collection/nokogiri/1.11/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/nokogiri/1.11/nokogiri.rbs +0 -2332
- data/.gem_rbs_collection/nokogiri/1.11/patch.rbs +0 -4
- data/.gem_rbs_collection/parallel/1.20/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/parallel/1.20/parallel.rbs +0 -86
- data/.gem_rbs_collection/parser/3.2/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/parser/3.2/manifest.yaml +0 -7
- data/.gem_rbs_collection/parser/3.2/parser.rbs +0 -194
- data/.gem_rbs_collection/parser/3.2/polyfill.rbs +0 -4
- data/.gem_rbs_collection/rainbow/3.0/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rainbow/3.0/global.rbs +0 -7
- data/.gem_rbs_collection/rainbow/3.0/presenter.rbs +0 -209
- data/.gem_rbs_collection/rainbow/3.0/rainbow.rbs +0 -5
- data/.gem_rbs_collection/rake/13.0/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rake/13.0/manifest.yaml +0 -2
- data/.gem_rbs_collection/rake/13.0/rake.rbs +0 -39
- data/.gem_rbs_collection/regexp_parser/2.8/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/regexp_parser/2.8/regexp_parser.rbs +0 -17
- data/.gem_rbs_collection/rubocop/1.57/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rubocop/1.57/rubocop.rbs +0 -208
- data/.gem_rbs_collection/rubocop-ast/1.46/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rubocop-ast/1.46/rubocop-ast.rbs +0 -903
- data/.gem_rbs_collection/rubyzip/3.2/.rbs_meta.yaml +0 -9
- data/.gem_rbs_collection/rubyzip/3.2/manifest.yaml +0 -8
- data/.gem_rbs_collection/rubyzip/3.2/zip/central_directory.rbs +0 -42
- data/.gem_rbs_collection/rubyzip/3.2/zip/compressor.rbs +0 -5
- data/.gem_rbs_collection/rubyzip/3.2/zip/constants.rbs +0 -47
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/aes_encryption.rbs +0 -30
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/decrypted_io.rbs +0 -9
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/encryption.rbs +0 -7
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/null_encryption.rbs +0 -19
- data/.gem_rbs_collection/rubyzip/3.2/zip/crypto/traditional_encryption.rbs +0 -31
- data/.gem_rbs_collection/rubyzip/3.2/zip/decompressor.rbs +0 -18
- data/.gem_rbs_collection/rubyzip/3.2/zip/deflater.rbs +0 -12
- data/.gem_rbs_collection/rubyzip/3.2/zip/dirtyable.rbs +0 -11
- data/.gem_rbs_collection/rubyzip/3.2/zip/dos_time.rbs +0 -13
- data/.gem_rbs_collection/rubyzip/3.2/zip/entry.rbs +0 -95
- data/.gem_rbs_collection/rubyzip/3.2/zip/entry_set.rbs +0 -31
- data/.gem_rbs_collection/rubyzip/3.2/zip/errors.rbs +0 -58
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/aes.rbs +0 -24
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/generic.rbs +0 -17
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/ntfs.rbs +0 -23
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/old_unix.rbs +0 -22
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/universal_time.rbs +0 -30
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unix.rbs +0 -20
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/unknown.rbs +0 -15
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field/zip64.rbs +0 -26
- data/.gem_rbs_collection/rubyzip/3.2/zip/extra_field.rbs +0 -21
- data/.gem_rbs_collection/rubyzip/3.2/zip/file.rbs +0 -131
- data/.gem_rbs_collection/rubyzip/3.2/zip/file_split.rbs +0 -14
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/dir.rbs +0 -33
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/directory_iterator.rbs +0 -21
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file.rbs +0 -63
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/file_stat.rbs +0 -55
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem/zip_file_name_mapper.rbs +0 -35
- data/.gem_rbs_collection/rubyzip/3.2/zip/filesystem.rbs +0 -7
- data/.gem_rbs_collection/rubyzip/3.2/zip/inflater.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/input_stream.rbs +0 -22
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_input_stream.rbs +0 -29
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras/abstract_output_stream.rbs +0 -17
- data/.gem_rbs_collection/rubyzip/3.2/zip/ioextras.rbs +0 -13
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_compressor.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_decompressor.rbs +0 -8
- data/.gem_rbs_collection/rubyzip/3.2/zip/null_input_stream.rbs +0 -6
- data/.gem_rbs_collection/rubyzip/3.2/zip/output_stream.rbs +0 -30
- data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_compressor.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/pass_thru_decompressor.rbs +0 -10
- data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_directory.rbs +0 -5
- data/.gem_rbs_collection/rubyzip/3.2/zip/streamable_stream.rbs +0 -15
- data/.gem_rbs_collection/rubyzip/3.2/zip/version.rbs +0 -3
- data/.gem_rbs_collection/rubyzip/3.2/zip.rbs +0 -40
- data/Rakefile +0 -567
- data/Steepfile +0 -18
- data/benchmark.rb +0 -406
- data/docs/ARCHITECTURE.md +0 -514
- data/docs/DEVELOPMENT.md +0 -133
- data/docs/PEER_LIBRARIES.md +0 -121
- data/docs/QUALITY_ASSURANCE.md +0 -25
- data/docs/SPEC_SOURCES.md +0 -48
- data/docs/assets/benchmark_results.svg +0 -144
- data/docs/assets/lsp_autocompletion.png +0 -0
- data/docs/assets/playground_preview.png +0 -0
- data/docs/coi-serviceworker.js +0 -82
- data/docs/office_thread.js +0 -77
- data/docs/preview.html +0 -719
- data/docs/visual/VisualGallery.md +0 -4672
- data/docs/wasm/ruby.wasm +0 -0
- data/docs/wasm/wasm_doc_helper.css +0 -351
- data/docs/wasm/wasm_doc_helper.js +0 -439
- data/docs/zeta.js +0 -1107
- data/rbs_collection.lock.yaml +0 -252
- data/rbs_collection.yaml +0 -19
- data/vendor/sdk_runner/Program.cs +0 -93
- data/vendor/sdk_runner/sdk_runner.csproj +0 -13
data/docs/PEER_LIBRARIES.md
DELETED
|
@@ -1,121 +0,0 @@
|
|
|
1
|
-
# Ruby XLSX Ecosystem & Peer Libraries
|
|
2
|
-
|
|
3
|
-
The Ruby ecosystem is fortunate to have a rich set of mature, well-engineered XLSX libraries. Each library represents deliberate architectural choices tailored for specific problem spaces.
|
|
4
|
-
|
|
5
|
-
This document provides a respectful overview of the peer libraries in the Ruby ecosystem, explains the underlying engineering tradeoffs (such as Streaming vs. In-Memory and Shared String Tables vs. Inline Strings), and shares comprehensive benchmark measurements.
|
|
6
|
-
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
## The Peer Libraries
|
|
10
|
-
|
|
11
|
-
| Library | I/O | Official Self-Description / Focus | Best Fit (In Our View) |
|
|
12
|
-
| :--- | :---: | :--- | :--- |
|
|
13
|
-
| **[roo](https://rubygems.org/gems/roo)** | `R` | *"Roo can access the contents of various spreadsheet files (Excelx, LibreOffice, OpenOffice, CSV)."* | Unified interface for reading across diverse spreadsheet formats. |
|
|
14
|
-
| **[creek](https://rubygems.org/gems/creek)** | `R` | *"A Ruby gem that streams and parses large Excel (xlsx and xlsm) files fast and efficiently."* | Streaming large spreadsheet uploads row-by-row with lightweight SAX parsing. |
|
|
15
|
-
| **[xsv](https://rubygems.org/gems/xsv)** | `R` | *"A fast and lightweight xlsx parser that provides nothing a CSV parser wouldn't."* | High-speed, CSV-like tabular data ingestion without styling overhead. |
|
|
16
|
-
| **[simple_xlsx_reader](https://rubygems.org/gems/simple_xlsx_reader)** | `R` | *"Read xlsx data the Ruby way"* — parses sheets into Ruby primitives with low memory. | Memory-conscious tabular data extraction directly into Ruby types. |
|
|
17
|
-
| **[caxlsx / axlsx](https://rubygems.org/gems/caxlsx)** | `W` | *"Excel OOXML (xlsx) with charts, styles, images and autowidth columns"* with full schema validation. | Generating rich, styled business reports with charts, images, and visual design. |
|
|
18
|
-
| **[write_xlsx](https://rubygems.org/gems/write_xlsx)** | `W` | Pure Ruby port of Perl's `Excel::Writer::XLSX` to create files in modern Excel 2007+ format. | Creating complex spreadsheets requiring exact Excel feature parity. |
|
|
19
|
-
| **[xlsxtream](https://rubygems.org/gems/xlsxtream)** | `W` | *"A streaming XLSX spreadsheet writer"* allowing very efficient writing of CSV-style data. | Ultra-fast, low-memory streaming exports of massive tabular datasets. |
|
|
20
|
-
| **[fast_excel](https://rubygems.org/gems/fast_excel)** | `W` | *"Ultra Fast Excel Writer"* — C-extension wrapper for `libxlsxwriter` with constant memory mode. | Maximum-throughput spreadsheet generation when C-extensions are available. |
|
|
21
|
-
| **[rubyXL](https://rubygems.org/gems/rubyXL)** | `RW` | *"Allows the parsing, creation, and manipulation of Microsoft Excel (.xlsx/.xlsm) Documents."* | Full document DOM inspection, in-memory cell modification, and template editing. |
|
|
22
|
-
| **[xlsxrb](https://github.com/niku/xlsxrb)** | `RW` | Pure Ruby library unifying streaming read/write ($O(1)$ memory) and in-memory manipulation with native encryption. | Unified reading, writing, template modification, and password encryption in pure Ruby. |
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
---
|
|
26
|
-
|
|
27
|
-
## Architectural Tradeoffs
|
|
28
|
-
|
|
29
|
-
Spreadsheet libraries must balance multiple competing dimensions: memory consumption, execution speed, formatting capabilities, and strict specification compliance.
|
|
30
|
-
|
|
31
|
-
### 1. Memory & Execution Model: Streaming vs. In-Memory
|
|
32
|
-
|
|
33
|
-
```
|
|
34
|
-
┌─────────────────────────────────────────────────────────────┐
|
|
35
|
-
│ Execution Models │
|
|
36
|
-
├──────────────────────────────┬──────────────────────────────┤
|
|
37
|
-
│ Streaming Model │ In-Memory Model │
|
|
38
|
-
├──────────────────────────────┼──────────────────────────────┤
|
|
39
|
-
│ • Processes rows on-the-fly │ • Builds complete DOM tree │
|
|
40
|
-
│ • O(1) constant RAM footprint│ • Enables random cell access │
|
|
41
|
-
│ • Cannot seek backward │ • High RAM on large datasets │
|
|
42
|
-
│ • Ideal for batch exports/ETL│ • Ideal for templates/edits │
|
|
43
|
-
└──────────────────────────────┴──────────────────────────────┘
|
|
44
|
-
```
|
|
45
|
-
|
|
46
|
-
* **Streaming Model** (`xlsxrb`, `xlsxtream`, `simple_xlsx_reader`, `roo`, `creek`, `xsv`):
|
|
47
|
-
Rows and cells are processed sequentially and flushed/discarded immediately. This keeps memory usage completely flat and predictable, regardless of whether the file has 10 rows or 1,000,000 rows. However, random access (e.g., modifying `cell("A1")` after writing row 100) is not possible.
|
|
48
|
-
* **In-Memory Model** (`xlsxrb`, `caxlsx`, `write_xlsx`, `rubyXL`):
|
|
49
|
-
The entire workbook structure is parsed into Ruby objects, providing complete flexibility to inspect, modify, insert, or reorder cells and worksheets. The tradeoff is that memory consumption scales with the number of cells.
|
|
50
|
-
|
|
51
|
-
---
|
|
52
|
-
|
|
53
|
-
### 2. String Storage Architecture: Shared String Table (SST) vs. Inline Strings
|
|
54
|
-
|
|
55
|
-
The OpenXML (ECMA-376) specification defines two ways to store text in cells:
|
|
56
|
-
|
|
57
|
-
```xml
|
|
58
|
-
<!-- 1. Shared String Table (SST): Deduplicated dictionary reference -->
|
|
59
|
-
<c r="A1" t="s"><v>0</v></c>
|
|
60
|
-
|
|
61
|
-
<!-- 2. Inline String: Raw text payload inside the cell -->
|
|
62
|
-
<c r="A1" t="inlineStr"><is><t>Hello World</t></is></c>
|
|
63
|
-
```
|
|
64
|
-
|
|
65
|
-
#### Shared String Table (SST)
|
|
66
|
-
* **How it works**: Strings across all worksheets are collected into a single central dictionary (`xl/sharedStrings.xml`). Cells only store numeric integer IDs pointing to dictionary entries.
|
|
67
|
-
* **Strengths**:
|
|
68
|
-
* **Smaller file footprint**: Deduplication significantly reduces the uncompressed XML size (typically 50% to 80% smaller for business datasets with repetitive categories, statuses, dates, and labels).
|
|
69
|
-
* **Standard Microsoft Excel behavior**: Excel defaults to SST. Opening SST-based spreadsheets in Excel consumes less memory and renders faster.
|
|
70
|
-
* **Rich Text & Shared Styles**: Supports rich text formatting within strings.
|
|
71
|
-
* **Tradeoff**:
|
|
72
|
-
* Writing requires managing a string table dictionary or making a multi-pass serialization, adding slight CPU overhead during generation.
|
|
73
|
-
|
|
74
|
-
#### Inline Strings
|
|
75
|
-
* **How it works**: Text is written directly into each `<c>` element (`<is><t>...</t></is>`) as the stream proceeds.
|
|
76
|
-
* **Strengths**:
|
|
77
|
-
* **Raw Throughput**: Bypassing string deduplication allows immediate row-by-row flushing with minimal CPU overhead (as demonstrated by `xlsxtream`).
|
|
78
|
-
* **Tradeoff**:
|
|
79
|
-
* Produces significantly larger raw XML files when strings repeat, and some third-party spreadsheet viewers or legacy tools have limited support for inline strings compared to SST.
|
|
80
|
-
|
|
81
|
-
---
|
|
82
|
-
|
|
83
|
-
## Detailed Benchmark Results
|
|
84
|
-
|
|
85
|
-
The following benchmarks evaluate processing **1,000,000 cells** (100,000 rows × 10 columns) containing standard business data (integers, strings, floats, booleans, and dates) across 3 isolated subprocess runs.
|
|
86
|
-
|
|
87
|
-
### Write Performance (1,000,000 cells)
|
|
88
|
-
|
|
89
|
-
| Library | Version | Model | String Storage | Time (Median) | Time (Mean) | Peak Memory | GC Count |
|
|
90
|
-
| :--- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
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
|
-
|
|
99
|
-
### Read Performance (1,000,000 cells)
|
|
100
|
-
|
|
101
|
-
| Library | Version | Model | Time (Median) | Time (Mean) | Peak Memory | GC Count |
|
|
102
|
-
| :--- | :--- | :--- | :--- | :--- | :--- | :--- |
|
|
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
|
-
|
|
111
|
-
---
|
|
112
|
-
|
|
113
|
-
## Reproducing Benchmarks Locally
|
|
114
|
-
|
|
115
|
-
The benchmark suite leverages [`bundler/inline`](https://bundler.io/v2.5/guides/bundler_in_a_single_file_ruby_script.html) to run each library in an isolated subprocess (`Bundler.with_unbundled_env`), eliminating cross-gem pollution and ensuring accurate memory measurements.
|
|
116
|
-
|
|
117
|
-
To run the suite on your machine:
|
|
118
|
-
|
|
119
|
-
```bash
|
|
120
|
-
ruby benchmark.rb 100000 10
|
|
121
|
-
```
|
data/docs/QUALITY_ASSURANCE.md
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
# Quality Assurance (QA) & Testing Architecture
|
|
2
|
-
|
|
3
|
-
`xlsxrb` is designed to be an enterprise-grade, highly reliable, and highly performant library for reading and writing Excel spreadsheets. To achieve and maintain this standard, we have implemented a comprehensive Quality Assurance matrix that covers everything from static code analysis and dynamic runtime validation to performance benchmarking and visual regression testing.
|
|
4
|
-
|
|
5
|
-
Below is an overview of the inspection mechanisms, when they run, the quality attributes they guarantee, and the specific bugs they prevent.
|
|
6
|
-
|
|
7
|
-
## QA Matrix
|
|
8
|
-
|
|
9
|
-
| Inspection Mechanism / Tool | Execution Command / Mechanism | Local | CI (PR/Push) | Scheduled (Weekly) | Target Quality Attribute | Validation Method | Prevented Bugs / Issues |
|
|
10
|
-
| :--- | :--- | :---: | :---: | :---: | :--- | :--- | :--- |
|
|
11
|
-
| **RuboCop** | `rake rubocop` | ⭕ | ⭕ | - | Readability / Maintainability | Static Analysis (Syntax/Linting) | Overly complex methods, non-standard syntax, unused variables. |
|
|
12
|
-
| **Steep & RBS** | `rake typecheck` | ⭕ | ⭕ | - | Type Safety (Static) | Static Analysis (Type Check) | `NoMethodError`, passing incorrect arguments, method typo bugs. |
|
|
13
|
-
| **Bundler Audit** | `rake audit` | - | ⭕ | - | Security | Dependency Scanning | Inclusion of external gems with known vulnerabilities (CVEs). |
|
|
14
|
-
| **Dependabot** | `.github/dependabot.yml` | - | - | ⭕ | Currency / Maintenance | Repository Monitoring | Outdated dependencies or CI actions. |
|
|
15
|
-
| **Unit & Contract Tests** | `rake test:unit test:contract` | ⭕ | ⭕ | - | Accuracy / Functional Reqs | Dynamic Analysis (Assertions) | Method specification violations, unexpected return values, edge-case failures. |
|
|
16
|
-
| **Runtime Type Validation (RBS::Test)** | `rake test:rbs` | △ (Opt-in) | ⭕ | - | Type Safety (Dynamic) | Dynamic Analysis (Runtime Hooks) | Type errors slipping past static checks, divergence between RBS docs and implementation. |
|
|
17
|
-
| **Property-Based Testing (PBT)** | `rake test:pbt` | ⭕ | ⭕ | - | Robustness / Exhaustiveness | Automated Random Generation | Crashes caused by "unexpected inputs" (e.g., empty strings, huge numbers, special symbols like `=`). |
|
|
18
|
-
| **Security Validation (DoS Protection)** | Included in `rake test:unit` | ⭕ | ⭕ | - | Availability / Safety | Dynamic Analysis (Malicious Input) | Memory/disk exhaustion from ZIP bombs, infinite parsing loops from malformed files. |
|
|
19
|
-
| **Concurrency Validation (Thread/Ractor)** | Included in `rake test:unit` | ⭕ | ⭕ | - | Thread Safety | Dynamic Analysis (Parallel Execution) | Global variable pollution, data mixing during concurrent request processing. |
|
|
20
|
-
| **XSD Schema Validation** | Included in `rake test:unit` | ⭕ | ⭕ | - | Compatibility / Compliance | Structural Validation | "We found a problem with some content in it" errors when opening in Excel. |
|
|
21
|
-
| **E2E Interoperability Tests** | `rake test:e2e` | △ (Opt-in) | ⭕ | - | Compatibility (Real-world) | 3rd-party SDK Execution | Structural defects so severe that the official .NET SDK cannot read them. |
|
|
22
|
-
| **Memory & Performance Tests** | `rake test:perf` / Action: `performance.yml` | ⭕ | ⭕ | - | Performance / Stability | Continuous Profiling (10k+ rows) | Out of Memory (OOM) leaks or unbounded memory retention in streaming mode. |
|
|
23
|
-
| **Ecosystem Benchmarks** | `ruby benchmark.rb` | ⭕ | - | - | Performance Comparison | Multi-Gem Isolated Profiling (1M cells) | Throughput and allocation comparison against competing libraries. |
|
|
24
|
-
| **Visual Regression Testing (VRT)** | `rake test:visual` | - | ⭕ | - | Visual Accuracy (UI/UX) | Headless Rendering / Pixel Diff | Visual bugs like "cell background colors dropping" or "chart layouts breaking" after code changes. |
|
|
25
|
-
|
data/docs/SPEC_SOURCES.md
DELETED
|
@@ -1,48 +0,0 @@
|
|
|
1
|
-
# Specification Reference Policy
|
|
2
|
-
|
|
3
|
-
This document defines the specification reference policy for `xlsxrb`.
|
|
4
|
-
|
|
5
|
-
## Canonical Specification (Normative)
|
|
6
|
-
The primary reference for this library is **ECMA-376 (Office Open XML File Formats)**.
|
|
7
|
-
Specifically, `xlsxrb` targets the **Transitional** version of the specification (Part 4) to ensure maximum compatibility with existing applications such as Microsoft Excel, LibreOffice, and Google Sheets.
|
|
8
|
-
|
|
9
|
-
Local copies of the ECMA-376 specifications are located in the `vendor/docs/` directory:
|
|
10
|
-
- [Part 1: Fundamentals And Markup Language Reference](file:///workspaces/xlsxrb/vendor/docs/ECMA-376-Part1/Ecma%20Office%20Open%20XML%20Part%201%20-%20Fundamentals%20And%20Markup%20Language%20Reference.pdf)
|
|
11
|
-
- [Part 2: Open Packaging Conventions](file:///workspaces/xlsxrb/vendor/docs/ECMA-376-Part2/ECMA-376-2_5th_edition_december_2021.pdf)
|
|
12
|
-
- [Part 3: Markup Compatibility and Extensibility](file:///workspaces/xlsxrb/vendor/docs/ECMA-376-Part3/Ecma%20Office%20Open%20XML%20Part%203%20-%20Markup%20Compatibility%20and%20Extensibility.pdf)
|
|
13
|
-
- [Part 4: Transitional Migration Features](file:///workspaces/xlsxrb/vendor/docs/ECMA-376-Part4/Ecma%20Office%20Open%20XML%20Part%204%20-%20Transitional%20Migration%20Features.pdf)
|
|
14
|
-
|
|
15
|
-
## Supplementary Specifications (Excel Real-world Behavior)
|
|
16
|
-
To address gaps between the official ECMA standard and actual implementations in Microsoft Excel, the following Microsoft Open Specifications are used. Note that these files are not bundled in the repository to avoid licensing/redistribution issues; instead, they are referenced via online links and versioned here:
|
|
17
|
-
|
|
18
|
-
1. **[[MS-XLSX]: Excel Extensions to OOXML SpreadsheetML Structure](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-xlsx/)**
|
|
19
|
-
- **Role:** Explains Excel-specific extensions, default attributes, and schema extensions.
|
|
20
|
-
- **Referenced Version:** July 2024 / Version 12.0 (or current release).
|
|
21
|
-
2. **[[MS-OI29500]: Office Implementation Information for ISO/IEC 29500](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-oi29500/)**
|
|
22
|
-
- **Role:** Identifies how Excel actually reads/writes files, including deviations and compatibility behaviors.
|
|
23
|
-
- **Referenced Version:** July 2024 / Version 12.0 (or current release).
|
|
24
|
-
3. **[[MS-OFFCRYPTO]: Office Document Cryptography Structure](https://learn.microsoft.com/en-us/openspecs/office_standards/ms-offcrypto/)**
|
|
25
|
-
- **Role:** Provides details on encryption, passwords, and hashing algorithms used for document/sheet protection (Agile Encryption and Standard Encryption).
|
|
26
|
-
- **Referenced Version:** July 2024 / Version 12.0 (or current release).
|
|
27
|
-
4. **[[MS-CFB]: Compound File Binary File Format](https://learn.microsoft.com/en-us/openspecs/windows_protocols/ms-cfb/)**
|
|
28
|
-
- **Role:** Container format (OLE structured storage) wrapping encrypted Office documents (`EncryptionInfo` and `EncryptedPackage` streams).
|
|
29
|
-
- **Referenced Version:** July 2024 / Version 14.0 (or current release).
|
|
30
|
-
|
|
31
|
-
### ISO/IEC 29500 Note
|
|
32
|
-
ISO/IEC 29500 is contents-wise equivalent to ECMA-376. However, ISO/IEC 29500 requires paid purchase in general, whereas ECMA-376 is freely available. Therefore, we primarily cite ECMA-376 sections.
|
|
33
|
-
|
|
34
|
-
## Source Attribution Policy
|
|
35
|
-
When implementing features or fixing bugs that depend on specific behaviors defined in these specifications, developers should:
|
|
36
|
-
1. Reference the specific part, section, or page number in code comments (e.g., `# Reference: ECMA-376 Part 1, Section 18.3.1.73`).
|
|
37
|
-
2. Update the mapping table below to maintain a central registry of implemented standard behaviors.
|
|
38
|
-
|
|
39
|
-
## Implementation Specification Mapping Table
|
|
40
|
-
| Feature | Primary Standard | Specification Section | Notes |
|
|
41
|
-
| :--- | :--- | :--- | :--- |
|
|
42
|
-
| Cell Value Types | ECMA-376 Part 1 | §18.18.11 (ST_CellType) | Defines cell data types (boolean, number, string, formula, etc.) |
|
|
43
|
-
| Shared Strings | ECMA-376 Part 1 | §18.4 (Shared String Table) | Handling of `<sst>` and `<si>` for cell value reuse |
|
|
44
|
-
| Styles & Formatting | ECMA-376 Part 1 | §18.8 (Styles) | Cell style XF indexes, font, fill, border mappings |
|
|
45
|
-
| Hyperlinks | ECMA-376 Part 1 | §18.3.1.48 (hyperlink) | Worksheet hyperlinks referencing external URLs or internal targets |
|
|
46
|
-
| Document Encryption (Agile) | [MS-OFFCRYPTO] | §2.3.4 (Agile Encryption) | AES-256-CBC, PBKDF2/SHA-512, HMAC-SHA512 data integrity |
|
|
47
|
-
| Document Encryption (Standard) | [MS-OFFCRYPTO] | §2.3.6 (Standard Encryption) | AES-128-ECB, SHA-1 with CryptoAPI 50,000-spin key derivation |
|
|
48
|
-
| Encryption Container | [MS-CFB] | §2 (Compound File Structure) | Mini Stream, FAT/MiniFAT sectors, and Red-Black tree directory |
|
|
@@ -1,144 +0,0 @@
|
|
|
1
|
-
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 960 480" width="100%" height="100%">
|
|
2
|
-
<defs>
|
|
3
|
-
<linearGradient id="bg-grad" x1="0%" y1="0%" x2="100%" y2="100%">
|
|
4
|
-
<stop offset="0%" stop-color="#161b22"/>
|
|
5
|
-
<stop offset="100%" stop-color="#0d1117"/>
|
|
6
|
-
</linearGradient>
|
|
7
|
-
</defs>
|
|
8
|
-
|
|
9
|
-
<style>
|
|
10
|
-
.card { fill: #161b22; stroke: #30363d; stroke-width: 1px; rx: 8px; }
|
|
11
|
-
.title { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 18px; font-weight: 700; fill: #f0f6fc; }
|
|
12
|
-
.subtitle { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 12px; fill: #8b949e; }
|
|
13
|
-
.section-title { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 14px; font-weight: 700; fill: #e6edf3; }
|
|
14
|
-
.label { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 12px; fill: #c9d1d9; }
|
|
15
|
-
.label-accent { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 12px; font-weight: 700; fill: #58a6ff; }
|
|
16
|
-
.value { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 11px; font-weight: 600; fill: #ffffff; }
|
|
17
|
-
.grid { stroke: #21262d; stroke-width: 1px; stroke-dasharray: 4 4; }
|
|
18
|
-
.footer { font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; font-size: 11px; fill: #8b949e; }
|
|
19
|
-
</style>
|
|
20
|
-
|
|
21
|
-
<!-- Container -->
|
|
22
|
-
<rect width="960" height="480" rx="12" fill="url(#bg-grad)" stroke="#30363d" stroke-width="1"/>
|
|
23
|
-
|
|
24
|
-
<!-- Main Header -->
|
|
25
|
-
<text x="480" y="38" text-anchor="middle" class="title">Ruby XLSX Performance Benchmarks (1,000,000 Cells)</text>
|
|
26
|
-
<text x="480" y="58" text-anchor="middle" class="subtitle">100,000 rows × 10 cols • Mixed business data • Linear time scale (0s – 40s)</text>
|
|
27
|
-
|
|
28
|
-
<!-- Left: Write Performance -->
|
|
29
|
-
<g transform="translate(35, 75)">
|
|
30
|
-
<rect width="430" height="350" class="card"/>
|
|
31
|
-
<text x="20" y="30" class="section-title">Write Execution Time</text>
|
|
32
|
-
<text x="20" y="46" font-family="sans-serif" font-size="10" fill="#8b949e">Time to generate 1M cells (Lower is faster)</text>
|
|
33
|
-
|
|
34
|
-
<line x1="160.0" y1="65" x2="160.0" y2="320" class="grid"/>
|
|
35
|
-
<text x="160.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">0s</text>
|
|
36
|
-
|
|
37
|
-
<line x1="215.0" y1="65" x2="215.0" y2="320" class="grid"/>
|
|
38
|
-
<text x="215.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">10s</text>
|
|
39
|
-
|
|
40
|
-
<line x1="270.0" y1="65" x2="270.0" y2="320" class="grid"/>
|
|
41
|
-
<text x="270.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">20s</text>
|
|
42
|
-
|
|
43
|
-
<line x1="325.0" y1="65" x2="325.0" y2="320" class="grid"/>
|
|
44
|
-
<text x="325.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">30s</text>
|
|
45
|
-
|
|
46
|
-
<line x1="380.0" y1="65" x2="380.0" y2="320" class="grid"/>
|
|
47
|
-
<text x="380.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">40s</text>
|
|
48
|
-
|
|
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
|
-
|
|
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
|
-
|
|
59
|
-
<!-- fast_excel 0.5.0: 2.02s -->
|
|
60
|
-
<text x="150" y="155" text-anchor="end" class="label">fast_excel 0.5.0</text>
|
|
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
|
-
|
|
64
|
-
<!-- xlsxrb (In-Memory): 2.42s -->
|
|
65
|
-
<text x="150" y="190" text-anchor="end" class="label-accent">xlsxrb (In-Memory)</text>
|
|
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
|
-
|
|
69
|
-
<!-- write_xlsx 1.15.0: 4.39s -->
|
|
70
|
-
<text x="150" y="225" text-anchor="end" class="label">write_xlsx 1.15.0</text>
|
|
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
|
-
|
|
74
|
-
<!-- caxlsx 4.5.0: 5.28s -->
|
|
75
|
-
<text x="150" y="260" text-anchor="end" class="label">caxlsx 4.5.0</text>
|
|
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
|
-
|
|
79
|
-
<!-- rubyXL 3.4.38: 43.13s -->
|
|
80
|
-
<text x="150" y="295" text-anchor="end" class="label">rubyXL 3.4.38</text>
|
|
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
|
-
</g>
|
|
84
|
-
|
|
85
|
-
<!-- Right: Read Performance -->
|
|
86
|
-
<g transform="translate(495, 75)">
|
|
87
|
-
<rect width="430" height="350" class="card"/>
|
|
88
|
-
<text x="20" y="30" class="section-title">Read Execution Time</text>
|
|
89
|
-
<text x="20" y="46" font-family="sans-serif" font-size="10" fill="#8b949e">Time to parse 1M cells (Lower is faster)</text>
|
|
90
|
-
|
|
91
|
-
<line x1="160.0" y1="65" x2="160.0" y2="320" class="grid"/>
|
|
92
|
-
<text x="160.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">0s</text>
|
|
93
|
-
|
|
94
|
-
<line x1="215.0" y1="65" x2="215.0" y2="320" class="grid"/>
|
|
95
|
-
<text x="215.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">10s</text>
|
|
96
|
-
|
|
97
|
-
<line x1="270.0" y1="65" x2="270.0" y2="320" class="grid"/>
|
|
98
|
-
<text x="270.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">20s</text>
|
|
99
|
-
|
|
100
|
-
<line x1="325.0" y1="65" x2="325.0" y2="320" class="grid"/>
|
|
101
|
-
<text x="325.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">30s</text>
|
|
102
|
-
|
|
103
|
-
<line x1="380.0" y1="65" x2="380.0" y2="320" class="grid"/>
|
|
104
|
-
<text x="380.0" y="335" font-family="sans-serif" font-size="10" fill="#64748b" text-anchor="middle">40s</text>
|
|
105
|
-
|
|
106
|
-
<!-- xlsxrb (Streaming): 1.73s -->
|
|
107
|
-
<text x="150" y="85" text-anchor="end" class="label-accent">xlsxrb (Streaming)</text>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
121
|
-
<!-- creek 2.6.3: 7.12s -->
|
|
122
|
-
<text x="150" y="190" text-anchor="end" class="label">creek 2.6.3</text>
|
|
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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
136
|
-
<!-- rubyXL 3.4.38: 30.74s -->
|
|
137
|
-
<text x="150" y="295" text-anchor="end" class="label">rubyXL 3.4.38</text>
|
|
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
|
-
</g>
|
|
141
|
-
|
|
142
|
-
<!-- Footer -->
|
|
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
|
-
</svg>
|
|
Binary file
|
|
Binary file
|
data/docs/coi-serviceworker.js
DELETED
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
/*! coi-serviceworker v0.1.7 - Guido Zuidhof and contributors, licensed under MIT */
|
|
2
|
-
// Source: https://github.com/gzguidoti/coi-serviceworker
|
|
3
|
-
// Purpose: Allows running WebAssembly with SharedArrayBuffer on browsers by setting COOP and COEP headers via Service Worker.
|
|
4
|
-
let coepCredentialless = false;
|
|
5
|
-
if (typeof window === 'undefined') {
|
|
6
|
-
self.addEventListener("install", () => self.skipWaiting());
|
|
7
|
-
self.addEventListener("activate", (event) => event.waitUntil(self.clients.claim()));
|
|
8
|
-
|
|
9
|
-
self.addEventListener("message", (ev) => {
|
|
10
|
-
if (!ev.data) {
|
|
11
|
-
return;
|
|
12
|
-
} else if (ev.data.type === "deregister") {
|
|
13
|
-
self.registration
|
|
14
|
-
.unregister()
|
|
15
|
-
.then(() => {
|
|
16
|
-
return self.clients.matchAll();
|
|
17
|
-
})
|
|
18
|
-
.then(clients => {
|
|
19
|
-
clients.forEach((client) => client.navigate(client.url));
|
|
20
|
-
});
|
|
21
|
-
} else if (ev.data.type === "coepCredentialless") {
|
|
22
|
-
coepCredentialless = ev.data.value;
|
|
23
|
-
}
|
|
24
|
-
});
|
|
25
|
-
|
|
26
|
-
self.addEventListener("fetch", function (event) {
|
|
27
|
-
const r = event.request;
|
|
28
|
-
if (r.cache === "only-if-cached" && r.mode !== "same-origin") {
|
|
29
|
-
return;
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
const request = (coepCredentialless && r.mode === "no-cors")
|
|
33
|
-
? new Request(r, { credentials: "omit" })
|
|
34
|
-
: r;
|
|
35
|
-
event.respondWith(
|
|
36
|
-
fetch(request)
|
|
37
|
-
.then((response) => {
|
|
38
|
-
if (response.status === 0) {
|
|
39
|
-
return response;
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
const newHeaders = new Headers(response.headers);
|
|
43
|
-
newHeaders.set("Cross-Origin-Embedder-Policy",
|
|
44
|
-
coepCredentialless ? "credentialless" : "require-corp"
|
|
45
|
-
);
|
|
46
|
-
if (!coepCredentialless) {
|
|
47
|
-
newHeaders.set("Cross-Origin-Resource-Policy", "cross-origin");
|
|
48
|
-
}
|
|
49
|
-
newHeaders.set("Cross-Origin-Opener-Policy", "same-origin");
|
|
50
|
-
|
|
51
|
-
return new Response(response.body, {
|
|
52
|
-
status: response.status,
|
|
53
|
-
statusText: response.statusText,
|
|
54
|
-
headers: newHeaders,
|
|
55
|
-
});
|
|
56
|
-
})
|
|
57
|
-
.catch((e) => console.error(e))
|
|
58
|
-
);
|
|
59
|
-
});
|
|
60
|
-
} else {
|
|
61
|
-
(() => {
|
|
62
|
-
const reloaded = sessionStorage.getItem("coiReloaded");
|
|
63
|
-
const isSecureContext = window.isSecureContext;
|
|
64
|
-
if (!isSecureContext) return;
|
|
65
|
-
|
|
66
|
-
if (navigator.serviceWorker) {
|
|
67
|
-
navigator.serviceWorker.register(window.document.currentScript.src).then(
|
|
68
|
-
(registration) => {
|
|
69
|
-
registration.addEventListener("updatefound", () => {
|
|
70
|
-
sessionStorage.setItem("coiReloaded", "true");
|
|
71
|
-
window.location.reload();
|
|
72
|
-
});
|
|
73
|
-
if (registration.active && !navigator.serviceWorker.controller) {
|
|
74
|
-
sessionStorage.setItem("coiReloaded", "true");
|
|
75
|
-
window.location.reload();
|
|
76
|
-
}
|
|
77
|
-
},
|
|
78
|
-
(err) => console.error("COI registration failed: ", err)
|
|
79
|
-
);
|
|
80
|
-
}
|
|
81
|
-
})();
|
|
82
|
-
}
|
data/docs/office_thread.js
DELETED
|
@@ -1,77 +0,0 @@
|
|
|
1
|
-
/* -*- Mode: JS; tab-width: 2; indent-tabs-mode: nil; js-indent-level: 2; fill-column: 100 -*- */
|
|
2
|
-
// SPDX-License-Identifier: MIT
|
|
3
|
-
// Source: Derived from ZetaOffice WebAssembly example (https://github.com/zetaoffice/zeta-wasm-examples)
|
|
4
|
-
// Purpose: Runs WebAssembly-based LibreOffice (Calc) in a separate Web Worker thread.
|
|
5
|
-
|
|
6
|
-
// Debugging note:
|
|
7
|
-
// Switch the web worker in the browsers debug tab to debug this code.
|
|
8
|
-
// It's the "em-pthread" web worker with the most memory usage, where "zetajs" is defined.
|
|
9
|
-
|
|
10
|
-
'use strict';
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
// global variables - zetajs environment:
|
|
14
|
-
let zetajs, css;
|
|
15
|
-
|
|
16
|
-
// = global variables (some are global for easier debugging) =
|
|
17
|
-
// common variables:
|
|
18
|
-
let context, desktop, xModel, ctrl;
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
function demo() {
|
|
22
|
-
context = zetajs.getUnoComponentContext();
|
|
23
|
-
const bean_overwrite = new css.beans.PropertyValue({Name: 'Overwrite', Value: true});
|
|
24
|
-
const bean_odt_export = new css.beans.PropertyValue({Name: 'FilterName', Value: 'writer8'});
|
|
25
|
-
desktop = css.frame.Desktop.create(context);
|
|
26
|
-
|
|
27
|
-
zetajs.mainPort.onmessage = function (e) {
|
|
28
|
-
switch (e.data.cmd) {
|
|
29
|
-
case 'upload':
|
|
30
|
-
loadFile(e.data.filename);
|
|
31
|
-
break;
|
|
32
|
-
case 'download':
|
|
33
|
-
xModel.store();
|
|
34
|
-
zetajs.mainPort.postMessage({cmd: 'download', id: e.data.id});
|
|
35
|
-
break;
|
|
36
|
-
default:
|
|
37
|
-
throw Error('Unknown message command: ' + e.data.cmd);
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
zetajs.mainPort.postMessage({cmd: 'thr_running'});
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function loadFile(filename) {
|
|
44
|
-
if (xModel) {
|
|
45
|
-
try {
|
|
46
|
-
const xCloseable = css.util.XCloseable.query(xModel);
|
|
47
|
-
if (xCloseable) {
|
|
48
|
-
xCloseable.close(true);
|
|
49
|
-
} else {
|
|
50
|
-
xModel.dispose();
|
|
51
|
-
}
|
|
52
|
-
} catch (e) {
|
|
53
|
-
console.warn("xCloseable.close failed, trying dispose:", e);
|
|
54
|
-
try {
|
|
55
|
-
xModel.dispose();
|
|
56
|
-
} catch (e2) {
|
|
57
|
-
console.error("Failed to dispose old xModel:", e2);
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
xModel = null;
|
|
61
|
-
}
|
|
62
|
-
|
|
63
|
-
const in_path = 'file:///tmp/office/' + filename;
|
|
64
|
-
xModel = desktop.loadComponentFromURL(in_path, '_default', 0, []);
|
|
65
|
-
ctrl = xModel.getCurrentController();
|
|
66
|
-
ctrl.getFrame().getContainerWindow().FullScreen = true;
|
|
67
|
-
zetajs.mainPort.postMessage({cmd: 'ui_ready'});
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
Module.zetajs.then(function(pZetajs) {
|
|
71
|
-
// initializing zetajs environment:
|
|
72
|
-
zetajs = pZetajs;
|
|
73
|
-
css = zetajs.uno.com.sun.star;
|
|
74
|
-
demo(); // launching demo
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
/* vim:set shiftwidth=2 softtabstop=2 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */
|