xlsxrb 0.1.14 โ 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 +108 -0
- data/README.md +37 -17
- data/benchmark/micro_ips.rb +70 -0
- data/lib/xlsxrb/elements/styles.rb +427 -15
- data/lib/xlsxrb/elements/workbook.rb +67 -4
- data/lib/xlsxrb/elements/worksheet.rb +117 -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 +14 -2
- data/lib/xlsxrb/ooxml/reader/listeners/style_listeners.rb +12 -7
- data/lib/xlsxrb/ooxml/reader.rb +167 -139
- 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 +63 -4
- data/lib/xlsxrb/ooxml/workbook_writer.rb +232 -59
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +192 -123
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +307 -125
- data/lib/xlsxrb/ooxml/writer/drawing_xml.rb +16 -12
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +1 -1
- 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 +22 -2
- data/lib/xlsxrb/ooxml/xml_parser.rb +45 -0
- data/lib/xlsxrb/ooxml/zip_reader.rb +83 -32
- data/lib/xlsxrb/stream_row.rb +4 -3
- data/lib/xlsxrb/stream_sheet.rb +259 -7
- data/lib/xlsxrb/stream_writer.rb +197 -31
- data/lib/xlsxrb/utils.rb +68 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +110 -19
- data/lib/xlsxrb/worksheet_builder.rb +526 -15
- data/lib/xlsxrb.rb +889 -90
- data/sig/generated/xlsxrb/elements/styles.rbs +271 -5
- data/sig/generated/xlsxrb/elements/workbook.rbs +54 -3
- data/sig/generated/xlsxrb/elements/worksheet.rbs +63 -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 +13 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +18 -2
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +13 -3
- data/sig/generated/xlsxrb/ooxml/writer/styles_xml.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +6 -1
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +9 -6
- data/sig/generated/xlsxrb/stream_row.rbs +3 -2
- data/sig/generated/xlsxrb/stream_sheet.rbs +132 -6
- data/sig/generated/xlsxrb/stream_writer.rbs +118 -27
- data/sig/generated/xlsxrb/utils.rbs +45 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +252 -9
- data/sig/generated/xlsxrb.rbs +84 -10
- metadata +2 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 7edcf69207f83781642d4628e25802bd9f25e6db4caac46c4419cc803c225d4c
|
|
4
|
+
data.tar.gz: 6af71208f72dd6f2b94f4127faca05bce3046cd40c5a1ca9c605935eac754bad
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: b52768fc57d885db35b14c793e451c99c60045d56e5dad8ff549108fd1b25c825b8ad49dfb98d70e8f17a4512542129aeec0d793f3ed1d148b5cbcd228493523
|
|
7
|
+
data.tar.gz: d701b2f511498b462377ab7dcfcbe3288f331bd5e3df2c1c25c9a326abee7e5b1c6b583973f9afb5359a8affd158a33350aee186c4949055ea4d711e5db1a5fc
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,113 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.1.16] - 2026-10-24
|
|
4
|
+
|
|
5
|
+
### Changed
|
|
6
|
+
- Encapsulate `Elements::Styles` with dedicated collection readers (`fonts`, `fills`, `borders`, `cell_xfs`, `num_fmts`, `dxfs`, `cell_style_xfs`, `cell_styles`, `table_styles`, `indexed_colors`, `mru_colors`, `colors`) and item lookups (`font`, `fill`, `border`, `cell_xf` / `xf`, `num_fmt`, `dxf`, `cell_style_xf`, `cell_style`), removing public Hash delegation (`[]`, `[]=`, `fetch`, `dig`, `keys`, `values`, `each`, `merge!`), and provide builder helpers (`add_font`, `add_fill`, `add_border`, `add_num_fmt`, `add_xf`, `add_dxf`, `add_cell_style_xf`, `add_cell_style`, `add_style`) that append entries, invalidate memoized caches, and return allocated IDs.
|
|
7
|
+
- Enforce binary encoding (`ASCII-8BIT`) on raw XML buffers in `StreamRow` and document byte vs character indexing consistency policy in `AGENTS.md` to prevent terminal row truncation or byte-offset drift when scanning documents with multibyte UTF-8 characters.
|
|
8
|
+
- Clarify streaming write memory profile and date/time timezone semantics in README and YARD documentation.
|
|
9
|
+
- Reading a file that is not a ZIP archive (including an empty file) raises `Xlsxrb::ZipError` instead of `ArgumentError`.
|
|
10
|
+
- Strict numeric cell values: an explicit numeric cell (`t="n"`) with an invalid number raises `Xlsxrb::ParseError`, while an empty `<v>` reads as `nil` instead of `0`, exponent notation such as `1E-3` reads as a Float, and non-numeric values in cells without `t` fall back to their string payload. Inline string and formula string cells without text read as `nil`, and `t="d"` cells read as their ISO 8601 text.
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
- Compound File Binary (CFB) header validation: Validate major version (3 or 4) and sector shifts in `Ooxml::Cfb::Reader#parse_header` and bounds-check sector reading against file size in `read_sector`, preventing `RangeError` integer overflows on corrupted or tampered inputs and raising `Xlsxrb::Error` gracefully.
|
|
14
|
+
- Unstyled empty cells and column ranges: Suppress style attribute (`s="..."`) emission on unstyled empty cells in `WorksheetWriter#write_row`, `write_cell`, and `write_row_values` to prevent unintended style inheritance explosion when rows or columns have styles, and preserve column `min`..`max` ranges on round-trip across `build_worksheet`, `Elements::Column`, and `WorksheetWriter#write_columns`.
|
|
15
|
+
- Data validation `showDropDown` and `imeMode` attributes: Serialize `showDropDown="1"` and `imeMode` on `<dataValidation>` elements in `WorksheetWriter#write_data_validations`, matching `Ooxml::Writer` and `DataValidationsListener`.
|
|
16
|
+
- Sheet views and selection serialization: Omit hardcoded `tabSelected="1"` in `WorksheetWriter#write_sheet_views` unless `tab_selected` is true, preventing multiple sheets from opening simultaneously selected in Excel, serialize full sheet view properties (`top_left_cell`, `zoom_scale_normal`, `view`, etc.), and preserve active cell selection across `WorksheetWriter`, `Elements::Worksheet`, `StreamSheet`, and `Xlsxrb.write`.
|
|
17
|
+
- Differential format (`<dxfs>`) parsing and boolean font properties: Parse differential formats (`<dxf>`) in `Ooxml::StylesParser` and serialize font, `numFmt`, fill, alignment, border, and protection in `WorkbookWriter`, parse and serialize ECMA-376 `CT_BooleanProperty` attributes (`<b val="0"/>`, `<i val="0"/>`) for font properties, and preserve `<color auto="1"/>` in `StylesParser`.
|
|
18
|
+
- Column and row style inheritance and serialization: Resolve named and inline column and row styles to integer style indices and propagate style inheritance to unstyled cells in `WorkbookBuilder#process_styles`, serialize row style attribute `s` on streaming `<row>` elements in `WorksheetWriter#write_row_values`, and guard `<col style>` emission against non-integer identifiers.
|
|
19
|
+
- Resolve boolean (`t="b"`) formula `cached_value` payloads (`"1"`, `"0"`, `"true"`, `"false"`) to `true` and `false` in `Ooxml::Reader::WorksheetListener#store_cell_value`, matching streaming and DOM cell parsers.
|
|
20
|
+
- Forward `:type`, `:ref`, and `:shared_index` (`:si`) formula attributes when building cells from a formula Hash (`{ formula: ..., type: :array, ref: ... }`) in `WorksheetBuilder#row`, `Xlsxrb.build_raw_cell`, and `Xlsxrb.build_raw_cell_from_value`.
|
|
21
|
+
- Unify `Ooxml::Reader#extract_zip_entry` and `Ooxml::Reader#entry_names` with `Ooxml::ZipReader` to support case-insensitive OPC part name resolution (per ECMA-376 Part 2 ยง9.1.1.2), ZIP64 archives, and data-descriptor streams uniformly across all reader APIs.
|
|
22
|
+
- Exclude non-worksheet relationship parts (`chartsheet`, `dialogsheet`, `macrosheet`, `xlMacrosheet`, `xlIntlMacrosheet`) and `xl/chartsheets/`, `xl/dialogsheets/`, `xl/macrosheets/` targets from standard worksheet enumeration in `Xlsxrb.read`, `Xlsxrb.modify`, and `Ooxml::Reader#discover_sheets`.
|
|
23
|
+
- Excel date boundary guards: Raise `ArgumentError` when writing dates before the date system epoch (`1899-12-31` / `1900-01-01` in 1900 date system or `1904-01-01` in 1904 date system) or after `9999-12-31` in `date_to_serial`, and raise `ArgumentError` when reading negative serials or serials exceeding `9999-12-31` (`serial >= 2_958_466` in 1900 system or `serial >= 2_957_004` in 1904 system) in `serial_to_date`, adhering to ECMA-376 date constraints and preventing corrupted Julian day calculations or negative date representation errors.
|
|
24
|
+
- Formula cached value falsy resolution and boolean typing: Fix falsy checks on formula `cached_value` across `Xlsxrb`, `build_raw_cell_from_value`, and `WorksheetWriter` so that boolean `false` and numeric `0` are not skipped or converted to `nil`, and serialize boolean cached values with cell type `t="b"` and `<v>1</v>` / `<v>0</v>` per ECMA-376 Part 4 ยง18.3.1.4.
|
|
25
|
+
- Boolean cell parsing tolerance: Support text payloads `"true"` and `"false"` (case-insensitive) in addition to numeric `"1"` and `"0"` for cells with boolean type attribute `t="b"`, conforming to ECMA-376 `xs:boolean` specification and preventing boolean `true` cells from evaluating to `false`.
|
|
26
|
+
- Template modification in `Xlsxrb.modify`: Support case-insensitive and slash-normalized archive entry replacement per ECMA-376 Part 2 ยง7.3, preventing shadowed or duplicate entries when archives use mixed casing (such as `xl/SharedStrings.xml`) or Windows backslashes (such as `xl\worksheets\sheet1.xml`). Preserve XML namespace prefixes (such as `<x:worksheet>`, `<x:sst>`, `<x:si>`) during sheetData replacement and shared strings appending, prevent duplicate `xmlns:r` attribute definitions in namespaced and ISO/IEC 29500 Strict documents, and correctly anchor `<hyperlinks>` and `<legacyDrawing>` after preceding root container elements to avoid illegal nesting inside `<customSheetViews>` or extension blocks.
|
|
27
|
+
- Resolve Open Packaging Conventions (OPC) workbook part path dynamically via root relationships (`_rels/.rels`), enabling reading and modifying workbooks with non-standard part names or root locations (such as `xl/workbook2.xml` or `workbook.xml`), and fall back to standard sheet and part locations when workbook relationships are missing or corrupted.
|
|
28
|
+
- Handle multibyte UTF-8 characters encoded as ASCII-8BIT (binary) strings during XML escaping and buffer concatenation in worksheet writer, workbook writer, and streaming sheet, preventing `Encoding::CompatibilityError` when cell values or formulas contain multibyte text.
|
|
29
|
+
- ECMA-376 schema conformance during workbook serialization: Format hash-based colors (`{ theme: ... }`, `{ indexed: ... }`, `{ auto: ... }`) into schema-compliant `<color>` elements in stylesheets and workbooks instead of emitting unparseable Hash string representations (`rgb="{...}"`), strictly validate 6/8-character hex colors against `ST_UnsignedIntHex`, reorder DrawingML line and character properties (`a:ln`, `a:rPr`) to satisfy ECMA-376 `xs:sequence` child constraints, preserve leading and trailing whitespace using `xml:space="preserve"` on `<si><t>` elements in `sharedStrings.xml`, drop data validations missing required `sqref` references, and omit negative `firstPageNumber` values in worksheet `page_setup`.
|
|
30
|
+
- String fallback when cell type attribute `t` is omitted: Parse numeric strings (integers, floats, exponents) when cell type attribute is omitted, while treating non-numeric text payloads in `<v>` as raw strings rather than raising `Xlsxrb::ParseError`, allowing parsing of cells generated by Open XML SDK and other spreadsheet producers without crashing.
|
|
31
|
+
- XML namespace prefix tolerance in shared strings parser (`Ooxml::SharedStringsParser`): Locate `<sst>`, `<si>`, `<t>`, and `<rPh>` tags dynamically regardless of XML namespace prefixes (such as `<x:sst>`, `<x:si>`, `<x:t>`), preventing dropped shared strings in spreadsheets produced by Microsoft Open XML SDK, ClosedXML, and other XML-prefixed generators.
|
|
32
|
+
- Consolidate cell value interpretation across streaming fast-scan direct, row values, events, and SAX listener parsers into a centralized `Ooxml::WorksheetParser.resolve_cell_value` helper, eliminating redundant logic and preventing parser divergence.
|
|
33
|
+
- Preserve worksheet and workbook attributes during in-memory writes (`Xlsxrb.write(workbook)`): accurately map and serialize `freeze_pane`, `split_pane`, `sheet_view`, `page_setup`, `page_margins`, `header_footer`, `print_options`, `sheet_protection`, `tables`, `merged_cells`, `auto_filter`, `row_breaks`, `col_breaks`, and embedded images from `Elements::Worksheet`, and propagate workbook properties (`core_properties`, `app_properties`, `custom_properties`, `workbook_protection`).
|
|
34
|
+
- Support arbitrary XML attribute ordering on cells (such as `t` before `s` or `r` after `s`) in streaming fast-scan parsers, ensuring cell types and styles are never dropped regardless of producer attribute sequence.
|
|
35
|
+
- Empty self-closing string cells without `<v>` in fast scan parsers evaluate to `nil` instead of empty string `""`.
|
|
36
|
+
- In-memory SAX listeners (`WorksheetListener` and `SharedStringsListener`) skip phonetic readings (`<rPh>`) and treat empty self-closing string cells (`<c ... t="s"/>`) as nil, matching streaming reader behavior.
|
|
37
|
+
- Rich text parsing in shared strings parser (`Ooxml::SharedStringsParser`): Handle self-closing `<t/>` tags when the first run is empty without dropping subsequent runs, while bounding phonetic tag scans to maintain linear throughput.
|
|
38
|
+
- `extract_inline_text` and `extract_multi_t` strictly distinguish `<t>` elements from other XML tags containing 't' (such as `<rPr>`, `<vertAlign>`, or `<table>`), preventing corrupted inline string parsing in rich text runs.
|
|
39
|
+
- Formulas are serialized strictly when explicitly defined via `Xlsxrb.formula(...)` or `{ formula: ... }`. Plain string cells starting with `=` are always serialized as text cells, preventing formula injection vulnerabilities and unintended 0-value coercions on reload.
|
|
40
|
+
- Streaming reads no longer drop the cell that follows a self-closing empty cell (`<c r="A1" s="1"/>`) in `StreamRow#values` and `StreamRow#cells`.
|
|
41
|
+
- Streaming reads place a row-leading cell with a multi-letter column reference (`AB1`) in its own column instead of column A.
|
|
42
|
+
- Phonetic readings (`<rPh>`) are excluded from shared strings and inline strings, so cells with furigana no longer concatenate phonetic readings to display text.
|
|
43
|
+
|
|
44
|
+
### Added
|
|
45
|
+
- Extract and preserve `activeTab` (`<workbookView>`) and `fullCalcOnLoad` (`<calcPr>`) in `Ooxml::WorkbookParser`, `Xlsxrb.read`, and `Xlsxrb.modify`, and expose `workbook_properties`, `active_tab`, and `full_calc_on_load?` (`full_calc_on_load`) readers on `Elements::Workbook`.
|
|
46
|
+
- Support self-closing row tags (`<row r="N" .../>`): Extract row indices and custom row attributes (`ht`, `hidden`, `customHeight`, `outlineLevel`, `collapsed`, `s`) and emit `:row_start` / `:row_end` events and empty `StreamRow` instances across direct and streaming worksheet parsers.
|
|
47
|
+
- ISO/IEC 29500-1 ST_Xstring control character decoding: Support decoding `_xHHHH_` hexadecimal escape sequences (such as `_x000D_` carriage returns and `_x005F_` literal underscores) in `XmlBuilder.unescape`, `SharedStringsParser`, and `SharedStringsListener`, correctly normalizing newlines and preserving control character fidelity in cell strings.
|
|
48
|
+
- Record Architecture Decision Record [ADR 0001: Excel Date System Boundary Handling](docs/adr/0001-excel-date-system-boundary-handling.md) documenting date conversion semantics, ecosystem survey, and design rationale across 1900 and 1904 date systems.
|
|
49
|
+
- Date validation and boundary checks: Add `Xlsxrb::Ooxml::Utils.valid_excel_date?` (and delegates on `Xlsxrb::Utils` and `Xlsxrb`) to check if a numeric serial value falls within the supported Excel date boundaries [0, 2,958,465] (1900 system) or [0, 2,957,003] (1904 system).
|
|
50
|
+
- `ZipReader#open_entry_io` and `ZipReader#each_entry_chunk` support an `encoding:` parameter and automatically resolve `.xml` and `.rels` entries to UTF-8 encoding, preventing `Encoding::CompatibilityError` in downstream text and regular expression operations.
|
|
51
|
+
- `Xlsxrb::Ooxml::Utils.booleanize` and `Xlsxrb::Ooxml::Utils.camelize` helper methods for OOXML attribute serialization and name casing conversion.
|
|
52
|
+
- Round-trip contract tests in `test/contract/round_trip_fidelity_test.rb` verifying that `read -> write -> read` preserves worksheet and workbook attributes across streaming and loaded in-memory representations.
|
|
53
|
+
- Alias `conditional_formatting` to `conditional_formats` on `StreamSheet` for complete API symmetry with `Elements::Worksheet`.
|
|
54
|
+
- Property-based tests for cell XML parsing in `test/pbt/cell_xml_parser_pbt_test.rb`, validating 100% equivalence between streaming fast-scan and SAX listener parsers across random attribute permutations, namespaces, rich text, and phonetic elements.
|
|
55
|
+
- Dedicated exception `Xlsxrb::ZipBombError < Xlsxrb::ZipError` for archive expansion limit violations.
|
|
56
|
+
- Workbook view and calculation properties in in-memory writes: `Xlsxrb.write(workbook)` emits `<bookViews><workbookView activeTab="n"/></bookViews>` and `<calcPr fullCalcOnLoad="1"/>` when the workbook properties carry `active_tab:` and `full_calc_on_load: true`.
|
|
57
|
+
- Autonomous QA agent squad skill definitions and documentation: Added skill playbooks in `.agents/skills/` (`throughput-performance`, `security-resilience`, `api-contract`, `concurrency-safety`, `visual-fidelity`), and updated `docs/QA_AGENTS.md`, `docs/QUALITY_ASSURANCE.md`, `.agents/rules/qa_agents.md`, and `AGENTS.md`.
|
|
58
|
+
- Visual fidelity and Wasm compatibility verification agent (`visual-fidelity`): Formulated autonomous skill playbook covering headless LibreOffice Calc visual regression testing (`rake test:visual`) and WebAssembly playground asset verification (`rake doc:check`).
|
|
59
|
+
- API symmetry and contract verification agent (`api-contract`): Added reflective method signature and parameter arity parity tests between `WorksheetBuilder`, `StreamWriter`, and `WorksheetProxy` in `test/contract/api_symmetry_test.rb`, added `very_hidden?` predicate on both `Elements::Worksheet` and `StreamSheet`, and enforced lossless round-trip serialization contracts between streaming and in-memory workflows.
|
|
60
|
+
- Security and resilience verification agent (`security-resilience`): Added regular expression ReDoS audit tests in `test/security_resilience_test.rb` verifying linear processing under 10k+ character adversarial inputs, supported `max_uncompressed_size` option on `Xlsxrb.read` block form to protect streaming decompression from ZIP bombs, and added `escape_formulas: true` option on `Xlsxrb.write`, `StreamWriter`, and `WorksheetWriter` to prevent formula and CSV injection vulnerabilities.
|
|
61
|
+
- Throughput and complexity verification agent (`throughput-performance`): Added deterministic allocation bounds testing (< 25 objects/row write, < 15 objects/row read for 10k rows) and scaling ratio tests in `test/performance/throughput_test.rb`, hot-path microbenchmarks with `benchmark-ips` (`benchmark/micro_ips.rb`), and corresponding `benchmark:ips` rake task.
|
|
62
|
+
- Concurrency and Ractor safety verification agent (`concurrency-safety`): Added automated reflection scan testing that 100% of constants in the `Xlsxrb` namespace are `Ractor.shareable?`, deeply froze `EPOCH_1900`, `EPOCH_1904`, `INTEGER_STRINGS`, and `LOCAL_HEADER_SIG`, added Ractor-safe accessors for REXML security settings in `XmlParser`, and added full parallel write/read/modify pipeline verification across concurrent Ractors in `test/concurrent_test.rb`.
|
|
63
|
+
|
|
64
|
+
## [0.1.15] - 2026-10-17
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- Block form for table and data validation configuration: Support optional configuration block in `table` and `validate_data` methods on `WorksheetBuilder`, `StreamWriter`, and `WorksheetProxy` using `TableBuilder` and `DataValidationBuilder` contexts.
|
|
68
|
+
- Protected range and cell watch configuration DSL and properties (`protected_range` and `cell_watch`): Add `protected_range` (and alias `add_protected_range`) and `cell_watch` (and alias `add_cell_watch`) methods to `WorksheetBuilder`, `StreamWriter`, and `WorksheetProxy`, normalize passwords into ECMA-376 compliant hashes or modern SHA-512 protection attributes, serialize `<protectedRanges>` and `<cellWatches>` according to OOXML schema sequence rules in `WorksheetWriter`, and expose `protected_ranges` and `cell_watches` readers on `Elements::Worksheet` and `StreamSheet`.
|
|
69
|
+
- Range coordinate conversion utilities (`Xlsxrb::Utils.parse_range` and `range_to_ref`): Parse cell range references (`"A1:C10"`, `"A1"`) to 0-based `[[top_row, left_col], [bottom_row, right_col]]` coordinate pairs, and format bounding coordinate tuples into A1-style range references (`"A1:C10"`) with `Xlsxrb.parse_range` and `Xlsxrb.range_to_ref` facade methods.
|
|
70
|
+
- Sheet format configuration DSL and properties (`sheet_format`): Add `sheet_format` method to `WorksheetBuilder`, `StreamWriter`, and `WorksheetProxy` supporting `default_row_height:`, `default_col_width:`, and extended properties (`outline_level_row`, `outline_level_col`, `zero_height`, `custom_height`, `thick_top`, `thick_bottom`), serialize `<sheetFormatPr>` schema-compliantly in `WorksheetWriter` and `WorkbookWriter`, and expose `sheet_format` reader on `Elements::Worksheet` and `StreamSheet`.
|
|
71
|
+
- Numeric and hexadecimal XML entity decoding in `XmlBuilder.unescape`: Support decoding decimal (`&#...;`) and hexadecimal (`&#x...;`) XML numeric character references with UTF-8 encoding and `RangeError` fallback.
|
|
72
|
+
- ZIP64 extra field support in `ZipReader`: Support reading ZIP64 extra fields (`0x0001`) in both central directory headers and local file headers for 64-bit uncompressed sizes, compressed sizes, and local header offsets.
|
|
73
|
+
- Expose `merged_cells` and `auto_filter` on `Elements::Worksheet`: Expose parsed sheet merge ranges and auto filter definitions directly on in-memory worksheets when loaded via `Xlsxrb.read` and `StreamSheet#load`.
|
|
74
|
+
- Expose document properties and protection settings on `Elements::Workbook`: Expose `core_properties`, `app_properties`, `custom_properties`, and `workbook_protection` readers on in-memory workbooks, populating them during `Xlsxrb.read` from `docProps/core.xml`, `docProps/app.xml`, `docProps/custom.xml`, and `<workbookProtection>`.
|
|
75
|
+
- Support updating cell hyperlinks and comments in `Xlsxrb.modify`: Synchronize modified cell hyperlinks and comments during template modification, updating or creating `_rels/sheetN.xml.rels`, `commentsN.xml`, `vmlDrawingN.vml`, and schema-compliant `<hyperlinks>` and `<legacyDrawing>` tags in worksheet XML.
|
|
76
|
+
- Expose sheet structure, print, and view metadata on `Elements::Worksheet` and `StreamSheet`: Expose `tables`, `shapes`, `freeze_pane`, `page_setup`, `page_margins`, `header_footer`, `print_options`, `sheet_protection`, `sheet_view`, `sheet_properties`, `row_breaks`, and `col_breaks` on both streaming and in-memory worksheets.
|
|
77
|
+
- WebAssembly Live Playground Monaco Editor integration: Replaced `<textarea>` with Monaco Editor in `docs/preview.html` featuring `vs-dark` theme, Ruby syntax highlighting, 2-space auto-indentation, auto-closing brackets and quotes, minimap, line numbers, and xlsxrb DSL snippet completion candidates (`Xlsxrb.write`, `wb.sheet`, `wb.style`, `s.row`, `s.column`, `s.chart`, `s.table`, `s.merge`, etc.). Implemented Blob URL worker initialization for Cross-Origin Isolation (COOP/COEP) compatibility and isolated AMD loader state during UMD binary bootstrap.
|
|
78
|
+
- Automated documentation and playground verification (`rake doc:check`): Validate generated documentation assets (file existence, minimum sizes, and magic bytes), verify HTTP server responses (status 200/206, MIME types, COOP/COEP headers, and absence of invalid compression headers) via byte-range requests, and automatically parse and execute all Live Playground presets to guarantee error-free generation prior to preview and deployment.
|
|
79
|
+
- WebAssembly Live Playground: Revamped `docs/preview.html` with current `Xlsxrb.write` DSL, added visually striking Executive Dashboard first view featuring an embedded Ruby gem logo image, KPI summary cards, zebra-striped table, currency formats, `=SUM` formulas, and a clustered bar chart in ~55 lines, added interactive preset selector with 11 spreadsheet scenarios (executive dashboard, sales reports, bar/line/pie charts, tables, borders, number formats, conditional formatting, hyperlinks, and Japanese text), direct URL deeplinking (`?example=...`), and seamless link integration throughout `VisualGallery.md` and `README.md`.
|
|
80
|
+
- New visual examples and VRT baselines for missing formatting and print features: `hyperlinks.rb` (external and internal cell hyperlinks), `column_styles.rb` (column-level default number formats and styling), `page_repeat_rows.rb` (repeating header rows for print setup), and `sheet_protection.rb` (password protection with granular permissions).
|
|
81
|
+
|
|
82
|
+
### Changed
|
|
83
|
+
- Standardized top navigation header across all documentation pages and Live Playground: Unified navbar with `Documentation`, `Visual Gallery`, `Live Playground`, and `GitHub` navigation links, active page highlighting, search input, and SVG theme toggle.
|
|
84
|
+
- Reorganized documentation sidebar navigation: Promoted `Visual Gallery` and `Live Playground` to prominent action items at the top of the sidebar, renamed the collapsible `docs` folder to an open `Guides` section, and formatted screaming uppercase filenames into clean Title Case labels (`Architecture`, `Development Guide`, etc.) to eliminate visual noise.
|
|
85
|
+
- Enhanced search index discoverability: Pre-indexed all documentation guides, pages, and the Live Playground in `search_data.js` so search queries for "Visual Gallery", "Playground", and "Architecture" yield instant results.
|
|
86
|
+
- Universal rendering without font tofu: Replaced theme toggle emojis with SVG sun and moon icons, and replaced README comparison table emoji checkmarks with accessible text badges (`Yes` / `-`) to eliminate tofu glyphs (`โก`) across Linux and headless environments.
|
|
87
|
+
- Visual Gallery layout polish: Constrained gallery overview thumbnails to 160px width with neat borders, styled `Live Playground` actions as interactive buttons, and constrained full baseline preview images to a maximum height of 480px to avoid unbounded scrolling whitespace.
|
|
88
|
+
- Documentation callout banners: Transformed GitHub-style markdown alert blockquotes (`[!TIP]`, `[!NOTE]`, `[!WARNING]`) into styled callout banners with SVGs.
|
|
89
|
+
- Cleaned up duplicated inline doc tags: Stripped repeated `rbs_inline: enabled` and `@api public` tags from generated module documentation.
|
|
90
|
+
- Align WebAssembly Live Playground design with documentation: Unify `docs/preview.html` visual styling with the RDoc Aliki documentation design system, adding light and dark theme support with local storage persistence, synchronized Monaco Editor theme switching (`vs` and `vs-dark`), top navigation bar matching documentation layout with links to documentation and visual gallery, solid brand coral red Run button matching documentation accent tokens, and dynamic status dot indicator (`Initializing...`, `Ready`, `Rendering...`, `Error`).
|
|
91
|
+
- Cleaned up visual examples and gallery generator: Stripped internal read validation debug dumps across all visual examples to present concise DSL code snippets, refreshed formula and merge syntax to use modern public APIs (`Xlsxrb.formula`, `A1:C1` ranges), and reorganized `VisualGallery.md` into 9 structured capability categories with dedicated preview tables and live playground links.
|
|
92
|
+
- Removed non-visual and redundant visual examples: Removed `invoice_statement.rb` and `streaming_append.rb` and their baseline directories from the visual regression test suite and gallery.
|
|
93
|
+
- Use `nil` for unstyled cells in `embedded_images.rb` example instead of undefined `"left"`.
|
|
94
|
+
|
|
95
|
+
### Fixed
|
|
96
|
+
- XML namespace prefix tolerance in template modification (`replace_sheet_data`): Locate `<sheetData>` and matching closing tags dynamically regardless of XML namespace prefixes (such as `<x:sheetData>` or `<d:sheetData>`) or self-closing syntax during `Xlsxrb.modify`.
|
|
97
|
+
- Resilience against duplicate XML declarations and malformed `.rels` files in `RelationshipsParser`: Sanitize duplicate or multiple `<?xml ...?>` declarations and provide regex fallback scanning if SAX parsing fails on malformed relationship XML.
|
|
98
|
+
- Fix false positive date detection for color tags like `[Red]` in `Ooxml::Reader#date_pattern?`: Unify custom number format date evaluation with `NumberFormatter.date_format?`, ignoring bracketed formatting codes (such as `[Red]` or `[Green]`) so negative numbers with colored styles are not misidentified as dates.
|
|
99
|
+
- Fix layout overlap between Playground Run & Preview button and theme toggle: Override absolute positioning of `.theme-toggle` from RDoc Aliki styles with static inline-flex flow in `docs/preview.html` to eliminate button collision and preserve clean spacing across light and dark modes.
|
|
100
|
+
- Prevent WebAssembly out-of-memory error during ZetaOffice instantiation on Firefox: Provide custom `Module.instantiateWasm` handler in `docs/preview.html` with streaming-first compilation (`WebAssembly.instantiateStreaming` / `WebAssembly.compileStreaming`) to bypass Emscripten's default `instantiateArrayBuffer` fallback that allocates an extra 160MB ArrayBuffer on memory pressure, and sequence Ruby Wasm and LibreOffice Wasm engine initialization to eliminate concurrent memory peaks.
|
|
101
|
+
- Resolve WebAssembly Live Playground (`docs/preview.html`) console errors and warnings across Chromium and Firefox:
|
|
102
|
+
- Compile `ruby.wasm` via streaming (`WebAssembly.compileStreaming`) with automatic fallback to avoid large intermediate ArrayBuffer heap allocations, eliminating `InternalError: out of memory` on memory-constrained browser environments.
|
|
103
|
+
- Bypass service worker registration and reloading in `coi-serviceworker.js` when native Cross-Origin Isolation headers (`COOP`/`COEP`) are already present, preventing in-flight network request abortions (`NS_BINDING_ABORTED`).
|
|
104
|
+
- Filter benign C/C++ Emscripten/Qt runtime stderr diagnostics in `Module.printErr` and route diagnostic output to `console.log` rather than `console.warn`.
|
|
105
|
+
- Guard UNO document model close/dispose handling in `office_thread.js` to cleanly close previous models without emitting `console.warn` on preset switching or re-runs.
|
|
106
|
+
- Prevent unhandled clipboard permission errors in Live Playground on Firefox: Intercept `navigator.permissions.query` in `docs/preview.html` and worker thread bootstrap to resolve dummy `PermissionStatus` objects for `clipboard-read` and `clipboard-write`, preventing uncaught `TypeError` exceptions from Embind in browsers that do not support clipboard descriptors in `PermissionDescriptor`.
|
|
107
|
+
- Fix missing closing angle bracket on styled formula cells in `WorksheetWriter`: Add missing `>` before `<f>` element when emitting styled formula cells in `WorksheetWriter#write_row_values`, resolving XML syntax errors (`<c r="..." s="..."<f>`) that caused LibreOffice and spreadsheet engines to reject sheet formatting.
|
|
108
|
+
- Prevent serialization of unresolved non-integer style names as `s` attribute in `WorksheetWriter`: Guard style resolution in `WorksheetWriter` to only emit valid integer style indices, ignoring unresolved strings or symbols to maintain ECMA-376 XML Schema conformance (`xs:unsignedInt`).
|
|
109
|
+
- Prevent invalid `Content-Encoding: br` header in local `doc:preview` server: Remove erroneous Brotli encoding header injected on uncompressed Emscripten `.data` packages (such as `soffice.data`), and supply native Cross-Origin Isolation headers (`COOP`, `COEP`, `CORP`) to resolve browser decompression failures (`NS_ERROR_INVALID_CONTENT_ENCODING`).
|
|
110
|
+
|
|
3
111
|
## [0.1.14] - 2026-10-10
|
|
4
112
|
|
|
5
113
|
### Added
|
data/README.md
CHANGED
|
@@ -10,19 +10,20 @@ The Ruby ecosystem has several XLSX libraries designed for specific tradeoffs:
|
|
|
10
10
|
|
|
11
11
|
| Library | Read | Write | Streaming | In-Memory |
|
|
12
12
|
| :--- | :---: | :---: | :---: | :---: |
|
|
13
|
-
| [roo](https://rubygems.org/gems/roo) |
|
|
14
|
-
| [creek](https://rubygems.org/gems/creek) |
|
|
15
|
-
| [xsv](https://rubygems.org/gems/xsv) |
|
|
16
|
-
| [simple_xlsx_reader](https://rubygems.org/gems/simple_xlsx_reader) |
|
|
17
|
-
| [caxlsx / axlsx](https://rubygems.org/gems/caxlsx) |
|
|
18
|
-
| [write_xlsx](https://rubygems.org/gems/write_xlsx) |
|
|
19
|
-
| [xlsxtream](https://rubygems.org/gems/xlsxtream) |
|
|
20
|
-
| [fast_excel](https://rubygems.org/gems/fast_excel) |
|
|
21
|
-
| [rubyXL](https://rubygems.org/gems/rubyXL) |
|
|
22
|
-
| [xlsxrb](https://github.com/niku/xlsxrb) |
|
|
13
|
+
| [roo](https://rubygems.org/gems/roo) | Yes | - | - | Yes |
|
|
14
|
+
| [creek](https://rubygems.org/gems/creek) | Yes | - | Yes | - |
|
|
15
|
+
| [xsv](https://rubygems.org/gems/xsv) | Yes | - | Yes | - |
|
|
16
|
+
| [simple_xlsx_reader](https://rubygems.org/gems/simple_xlsx_reader) | Yes | - | Yes | - |
|
|
17
|
+
| [caxlsx / axlsx](https://rubygems.org/gems/caxlsx) | - | Yes | - | Yes |
|
|
18
|
+
| [write_xlsx](https://rubygems.org/gems/write_xlsx) | - | Yes | - | Yes |
|
|
19
|
+
| [xlsxtream](https://rubygems.org/gems/xlsxtream) | - | Yes | Yes | - |
|
|
20
|
+
| [fast_excel](https://rubygems.org/gems/fast_excel) | - | Yes | Yes | - |
|
|
21
|
+
| [rubyXL](https://rubygems.org/gems/rubyXL) | Yes | Yes | - | Yes |
|
|
22
|
+
| [xlsxrb](https://github.com/niku/xlsxrb) | Yes | Yes | Yes | Yes |
|
|
23
|
+
|
|
23
24
|
|
|
24
25
|
These libraries make different architectural tradeoffs:
|
|
25
|
-
* Streaming Model: Writes or reads rows sequentially on-the-fly to maintain a
|
|
26
|
+
* Streaming Model: Writes or reads rows sequentially on-the-fly to maintain a low-memory footprint regardless of dataset size.
|
|
26
27
|
* In-Memory Model: Builds a complete document object model, offering flexible random access, cell updates, and document templates at the cost of memory usage on large spreadsheets.
|
|
27
28
|
|
|
28
29
|
Maintaining a gem that supports both reading and writing across streaming and in-memory models, alongside OOXML features and specification compatibility, involves significant ongoing maintenance overhead.
|
|
@@ -32,14 +33,14 @@ Maintaining a gem that supports both reading and writing across streaming and in
|
|
|
32
33
|
### Design Principles
|
|
33
34
|
|
|
34
35
|
- Zero Runtime Dependencies: Built strictly on the Ruby standard library and bundled gems (`zlib`, `rexml`, etc.) with zero third-party runtime dependencies.
|
|
35
|
-
- Streaming Support:
|
|
36
|
+
- Streaming Support: Low-memory row streaming for reading and writing spreadsheets ($O(1)$ memory on reads; writes buffer unique shared strings).
|
|
36
37
|
- OpenXML Interoperability: Compliant with ISO/IEC 29500 (ECMA-376) and validated against the Microsoft [Open XML SDK](https://github.com/dotnet/Open-XML-SDK).
|
|
37
38
|
- AI-Assisted Maintenance: Uses AI coding agents for automated quality assurance and verification workflows. Operational guidelines are defined in [AGENTS.md](AGENTS.md).
|
|
38
39
|
- Ruby 4.0+: Requires Ruby 4.0 or higher.
|
|
39
40
|
|
|
40
41
|
### Autonomous Quality Assurance
|
|
41
42
|
|
|
42
|
-
To maintain its multi-layered QA suite (Steep static typing, 100% mutation kill rate across
|
|
43
|
+
To maintain its multi-layered QA suite (Steep static typing, 100% mutation kill rate across 43 subjects, ECMA-376 XSD validation, and $O(1)$ streaming memory) without high manual maintenance overhead, xlsxrb defines remediation workflows for AI coding agents ([AGENTS.md](AGENTS.md), [docs/QA_AGENTS.md](docs/QA_AGENTS.md)).
|
|
43
44
|
|
|
44
45
|
## Installation
|
|
45
46
|
|
|
@@ -52,19 +53,19 @@ bundle add xlsxrb
|
|
|
52
53
|
|
|
53
54
|
Try `xlsxrb` directly in your browser without installing anything!
|
|
54
55
|
|
|
55
|
-
[
|
|
56
|
+
[Try the Live Demo / Interactive Playground](https://niku.github.io/xlsxrb/preview.html)
|
|
56
57
|
|
|
57
58
|
<p align="center">
|
|
58
59
|
<img src="docs/assets/playground_preview.png" width="100%" alt="Interactive WebAssembly Playground with Live LibreOffice Preview"/>
|
|
59
60
|
</p>
|
|
60
61
|
|
|
61
|
-
You can also browse
|
|
62
|
+
You can also browse 80+ rendered visual examples across all features in the [Visual Examples Gallery](docs/visual/VisualGallery.md).
|
|
62
63
|
|
|
63
64
|
## Usage
|
|
64
65
|
|
|
65
66
|
### Quick Start: Streaming (Recommended for Large Files)
|
|
66
67
|
|
|
67
|
-
#### Streaming Write (
|
|
68
|
+
#### Streaming Write (Low Memory)
|
|
68
69
|
```ruby
|
|
69
70
|
require "xlsxrb"
|
|
70
71
|
|
|
@@ -77,6 +78,9 @@ Xlsxrb.write("large_output.xlsx") do |writer|
|
|
|
77
78
|
end
|
|
78
79
|
```
|
|
79
80
|
|
|
81
|
+
> [!NOTE]
|
|
82
|
+
> Streaming writes pipe row and cell XML directly to the archive without buffering rows, keeping cell data memory constant. Because shared strings are indexed across the workbook to minimize output file size, memory scales with the count of distinct strings.
|
|
83
|
+
|
|
80
84
|
#### Streaming Read ($O(1)$ Memory)
|
|
81
85
|
```ruby
|
|
82
86
|
require "xlsxrb"
|
|
@@ -138,6 +142,22 @@ Xlsxrb.read("confidential.xlsx", password: "SecretPassword123") do |sheet|
|
|
|
138
142
|
end
|
|
139
143
|
```
|
|
140
144
|
|
|
145
|
+
### Date and Time Handling
|
|
146
|
+
|
|
147
|
+
Excel stores dates and times as floating-point serial numbers without timezone information. When reading spreadsheet files, `xlsxrb` returns date-formatted cells as UTC `Time` objects (`Time.utc`).
|
|
148
|
+
|
|
149
|
+
To interpret an Excel timestamp in a specific application timezone (such as JST or America/New_York), construct a local time using the year, month, day, hour, min, and sec components:
|
|
150
|
+
|
|
151
|
+
```ruby
|
|
152
|
+
# With ActiveSupport / Rails:
|
|
153
|
+
local_time = Time.zone.local(cell.value.year, cell.value.month, cell.value.day,
|
|
154
|
+
cell.value.hour, cell.value.min, cell.value.sec)
|
|
155
|
+
|
|
156
|
+
# With Ruby standard library:
|
|
157
|
+
local_time = Time.local(cell.value.year, cell.value.month, cell.value.day,
|
|
158
|
+
cell.value.hour, cell.value.min, cell.value.sec)
|
|
159
|
+
```
|
|
160
|
+
|
|
141
161
|
### IDE Autocompletion & Ruby LSP Support
|
|
142
162
|
|
|
143
163
|
Includes a native Ruby LSP Add-on and full RBS signatures for zero-configuration method autocompletion and hover documentation in VS Code and other editors:
|
|
@@ -172,7 +192,7 @@ Verified by a multi-layered QA architecture:
|
|
|
172
192
|
* Microsoft Open XML SDK Validation: Validates generated OOXML structures against Microsoft's official SDK.
|
|
173
193
|
* Visual Regression Testing (VRT): Headless LibreOffice Calc pixel-by-pixel rendering checks.
|
|
174
194
|
* Contract & Round-Trip Tests: Verifies parity between Streaming and In-Memory APIs and round-trip read/write accuracy.
|
|
175
|
-
* Mutation Testing (Mutant): 100% mutant kill rate (1,
|
|
195
|
+
* Mutation Testing (Mutant): 100% mutant kill rate (1,528/1,528 mutations across 43 subjects) on pure algorithms, predicates, and coordinates ([docs/MUTATION_TESTING.md](docs/MUTATION_TESTING.md)).
|
|
176
196
|
* Security & DoS Protection: Formula injection mitigation and ZIP bomb protection.
|
|
177
197
|
|
|
178
198
|
For full architectural details, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and [docs/QUALITY_ASSURANCE.md](docs/QUALITY_ASSURANCE.md).
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require "benchmark/ips"
|
|
4
|
+
require_relative "../lib/xlsxrb"
|
|
5
|
+
|
|
6
|
+
puts "=" * 70
|
|
7
|
+
puts "xlsxrb Hot-Path Microbenchmarks (benchmark-ips)"
|
|
8
|
+
puts "Ruby: #{RUBY_DESCRIPTION}"
|
|
9
|
+
puts "=" * 70
|
|
10
|
+
|
|
11
|
+
ips_time = (ENV["IPS_TIME"] || "2").to_f
|
|
12
|
+
ips_warmup = (ENV["IPS_WARMUP"] || "1").to_f
|
|
13
|
+
|
|
14
|
+
# 1. XML escaping hot path
|
|
15
|
+
sample_escape_string = "Customer & Company <sales@example.com> \"Q1 '2026'\""
|
|
16
|
+
puts "\n--- 1. XmlBuilder.escape ---"
|
|
17
|
+
Benchmark.ips do |x|
|
|
18
|
+
x.config(time: ips_time, warmup: ips_warmup)
|
|
19
|
+
x.report("XmlBuilder.escape") do
|
|
20
|
+
Xlsxrb::Ooxml::XmlBuilder.escape(sample_escape_string)
|
|
21
|
+
end
|
|
22
|
+
x.compare!
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
# 2. Coordinate conversion hot path
|
|
26
|
+
puts "\n--- 2. Cell.calculate_column_index ---"
|
|
27
|
+
Benchmark.ips do |x|
|
|
28
|
+
x.config(time: ips_time, warmup: ips_warmup)
|
|
29
|
+
x.report("Cell.calculate_column_index ('XFD1048576')") do
|
|
30
|
+
Xlsxrb::Elements::Cell.calculate_column_index("XFD1048576")
|
|
31
|
+
end
|
|
32
|
+
x.report("Cell.calculate_column_letter (16384)") do
|
|
33
|
+
Xlsxrb::Elements::Cell.calculate_column_letter(16_384)
|
|
34
|
+
end
|
|
35
|
+
x.compare!
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# 3. Number formatting hot path
|
|
39
|
+
sample_numbers = [1234.5678, -42.0, 0.05, 1_000_000.99]
|
|
40
|
+
sample_format_code = "#,##0.00;(#,##0.00);\"-\""
|
|
41
|
+
puts "\n--- 3. NumberFormatter.format ---"
|
|
42
|
+
Benchmark.ips do |x|
|
|
43
|
+
x.config(time: ips_time, warmup: ips_warmup)
|
|
44
|
+
x.report("NumberFormatter.format (custom pattern)") do
|
|
45
|
+
sample_numbers.each do |num|
|
|
46
|
+
Xlsxrb::NumberFormatter.format(num, sample_format_code)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
x.report("NumberFormatter.format (currency)") do
|
|
50
|
+
sample_numbers.each do |num|
|
|
51
|
+
Xlsxrb::NumberFormatter.format(num, "$#,##0.00")
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
x.compare!
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
# 4. WorksheetParser row scanning hot path
|
|
58
|
+
sample_row_xml = '<row r="1" spans="1:4"><c r="A1" t="s"><v>0</v></c><c r="B1"><v>123.45</v></c><c r="C1" s="1"><v>44927</v></c><c r="D1" t="inlineStr"><is><t>Inline text</t></is></c></row>'
|
|
59
|
+
shared_strings = ["First String", "Second String"]
|
|
60
|
+
styles = {}
|
|
61
|
+
puts "\n--- 4. WorksheetParser Row Scanning ---"
|
|
62
|
+
Benchmark.ips do |x|
|
|
63
|
+
x.config(time: ips_time, warmup: ips_warmup)
|
|
64
|
+
x.report("WorksheetParser.fast_scan_row_values") do
|
|
65
|
+
Xlsxrb::Ooxml::WorksheetParser.fast_scan_row_values(sample_row_xml, 0, sample_row_xml.bytesize, shared_strings, styles)
|
|
66
|
+
end
|
|
67
|
+
x.compare!
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
puts "\nMicrobenchmarks complete."
|