xlsxrb 0.1.13 โ 0.1.15
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 +104 -0
- data/README.md +17 -14
- data/lib/xlsxrb/colors.rb +118 -0
- data/lib/xlsxrb/elements/cell.rb +205 -16
- data/lib/xlsxrb/elements/column.rb +6 -4
- data/lib/xlsxrb/elements/coordinate_access.rb +32 -0
- data/lib/xlsxrb/elements/image.rb +128 -0
- data/lib/xlsxrb/elements/row.rb +206 -9
- data/lib/xlsxrb/elements/styles.rb +157 -0
- data/lib/xlsxrb/elements/types.rb +95 -1
- data/lib/xlsxrb/elements/workbook.rb +121 -4
- data/lib/xlsxrb/elements/worksheet.rb +519 -29
- data/lib/xlsxrb/elements.rb +2 -0
- data/lib/xlsxrb/number_formatter.rb +429 -0
- data/lib/xlsxrb/ooxml/cfb.rb +1 -1
- data/lib/xlsxrb/ooxml/reader/listeners/core_listeners.rb +7 -5
- data/lib/xlsxrb/ooxml/reader/listeners/drawing_listeners.rb +11 -4
- data/lib/xlsxrb/ooxml/reader/listeners/feature_listeners.rb +7 -1
- data/lib/xlsxrb/ooxml/reader.rb +14 -17
- data/lib/xlsxrb/ooxml/shared_strings_parser.rb +7 -1
- data/lib/xlsxrb/ooxml/styles_parser.rb +39 -9
- data/lib/xlsxrb/ooxml/utils.rb +34 -18
- data/lib/xlsxrb/ooxml/workbook_parser.rb +74 -16
- data/lib/xlsxrb/ooxml/workbook_writer.rb +82 -23
- data/lib/xlsxrb/ooxml/worksheet_parser.rb +319 -79
- data/lib/xlsxrb/ooxml/worksheet_writer.rb +263 -66
- data/lib/xlsxrb/ooxml/writer/features_xml.rb +5 -3
- data/lib/xlsxrb/ooxml/writer.rb +14 -0
- data/lib/xlsxrb/ooxml/xml_builder.rb +14 -2
- data/lib/xlsxrb/ooxml/zip_reader.rb +144 -28
- data/lib/xlsxrb/stream_row.rb +243 -16
- data/lib/xlsxrb/stream_sheet.rb +647 -16
- data/lib/xlsxrb/stream_writer.rb +375 -34
- data/lib/xlsxrb/style_builder.rb +308 -22
- data/lib/xlsxrb/utils.rb +211 -0
- data/lib/xlsxrb/version.rb +1 -1
- data/lib/xlsxrb/workbook_builder.rb +72 -11
- data/lib/xlsxrb/worksheet_builder.rb +738 -24
- data/lib/xlsxrb.rb +1073 -83
- data/sig/generated/xlsxrb/colors.rbs +40 -0
- data/sig/generated/xlsxrb/elements/cell.rbs +113 -8
- data/sig/generated/xlsxrb/elements/column.rbs +3 -2
- data/sig/generated/xlsxrb/elements/coordinate_access.rbs +18 -0
- data/sig/generated/xlsxrb/elements/image.rbs +82 -0
- data/sig/generated/xlsxrb/elements/row.rbs +83 -4
- data/sig/generated/xlsxrb/elements/styles.rbs +79 -0
- data/sig/generated/xlsxrb/elements/types.rbs +43 -0
- data/sig/generated/xlsxrb/elements/workbook.rbs +79 -2
- data/sig/generated/xlsxrb/elements/worksheet.rbs +282 -18
- data/sig/generated/xlsxrb/number_formatter.rbs +132 -0
- data/sig/generated/xlsxrb/ooxml/reader.rbs +6 -0
- data/sig/generated/xlsxrb/ooxml/shared_strings_parser.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/styles_parser.rbs +5 -2
- data/sig/generated/xlsxrb/ooxml/utils.rbs +17 -8
- data/sig/generated/xlsxrb/ooxml/workbook_parser.rbs +9 -3
- data/sig/generated/xlsxrb/ooxml/workbook_writer.rbs +1 -1
- data/sig/generated/xlsxrb/ooxml/worksheet_parser.rbs +28 -6
- data/sig/generated/xlsxrb/ooxml/worksheet_writer.rbs +13 -3
- data/sig/generated/xlsxrb/ooxml/writer.rbs +2 -0
- data/sig/generated/xlsxrb/ooxml/xml_builder.rbs +3 -1
- data/sig/generated/xlsxrb/ooxml/zip_reader.rbs +13 -0
- data/sig/generated/xlsxrb/stream_row.rbs +100 -6
- data/sig/generated/xlsxrb/stream_sheet.rbs +358 -14
- data/sig/generated/xlsxrb/stream_writer.rbs +220 -30
- data/sig/generated/xlsxrb/style_builder.rbs +55 -18
- data/sig/generated/xlsxrb/utils.rbs +151 -0
- data/sig/generated/xlsxrb/workbook_builder.rbs +26 -0
- data/sig/generated/xlsxrb/worksheet_builder.rbs +356 -18
- data/sig/generated/xlsxrb.rbs +223 -27
- metadata +11 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0ec522a5f1d603d001d74555842823cfd56bf1fc96239e3e04daabadd345b5e9
|
|
4
|
+
data.tar.gz: b8cb5562079da225ceae806972851c9f0a1462083a1d8a05753f6896d511b6b5
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: d3344f027a164d86a5546b45be5cac8213588ef99aa27d5a3b466b0c0504f5fe8607cb34d6b95e6bc42685108b1403eb8a0e5a28fa268a1707911c65fcc42e2d
|
|
7
|
+
data.tar.gz: 47f50e238ff4f5209421d99f34ddd58fb26c6428020f0ff9731b8b34374e9b757621fe833f57763978346adc5243064d2bb8e16ceca27f05a0627402b5bf0b3d
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,109 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.1.15] - 2026-10-17
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
- 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.
|
|
7
|
+
- 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`.
|
|
8
|
+
- 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.
|
|
9
|
+
- 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`.
|
|
10
|
+
- 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.
|
|
11
|
+
- 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.
|
|
12
|
+
- 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`.
|
|
13
|
+
- 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>`.
|
|
14
|
+
- 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.
|
|
15
|
+
- 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.
|
|
16
|
+
- 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.
|
|
17
|
+
- 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.
|
|
18
|
+
- 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`.
|
|
19
|
+
- 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).
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
- 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.
|
|
23
|
+
- 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.
|
|
24
|
+
- 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.
|
|
25
|
+
- 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.
|
|
26
|
+
- 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.
|
|
27
|
+
- Documentation callout banners: Transformed GitHub-style markdown alert blockquotes (`[!TIP]`, `[!NOTE]`, `[!WARNING]`) into styled callout banners with SVGs.
|
|
28
|
+
- Cleaned up duplicated inline doc tags: Stripped repeated `rbs_inline: enabled` and `@api public` tags from generated module documentation.
|
|
29
|
+
- 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`).
|
|
30
|
+
- 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.
|
|
31
|
+
- 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.
|
|
32
|
+
- Use `nil` for unstyled cells in `embedded_images.rb` example instead of undefined `"left"`.
|
|
33
|
+
|
|
34
|
+
### Fixed
|
|
35
|
+
- 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`.
|
|
36
|
+
- 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.
|
|
37
|
+
- 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.
|
|
38
|
+
- 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.
|
|
39
|
+
- 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.
|
|
40
|
+
- Resolve WebAssembly Live Playground (`docs/preview.html`) console errors and warnings across Chromium and Firefox:
|
|
41
|
+
- 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.
|
|
42
|
+
- 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`).
|
|
43
|
+
- Filter benign C/C++ Emscripten/Qt runtime stderr diagnostics in `Module.printErr` and route diagnostic output to `console.log` rather than `console.warn`.
|
|
44
|
+
- 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.
|
|
45
|
+
- 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`.
|
|
46
|
+
- 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.
|
|
47
|
+
- 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`).
|
|
48
|
+
- 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`).
|
|
49
|
+
|
|
50
|
+
## [0.1.14] - 2026-10-10
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
- Non-self-closing `<sheet>` and `<xf>` tag compatibility: Verify and support spreadsheet XML where `<sheet>...</sheet>` in `workbook.xml` or `<xf>...</xf>` in `styles.xml` are serialized with explicit closing tags rather than self-closing syntax.
|
|
54
|
+
- Namespace prefix resilience for relationship and embed attributes: Match relationship and embed attributes by local name or any namespace prefix (`r:id`, `d3p1:id`, `rel:id`, `id`, `r:embed`, `embed`) across `WorkbookListener`, `HyperlinksListener`, `DrawingListener`, and `WorksheetParser`, ensuring reliable sheet, hyperlink, and media resolution for non-standard XML generators.
|
|
55
|
+
- UTF-16LE, UTF-16BE, and UTF-8 BOM encoding normalization in `ZipReader`: Automatically detect and transcode Byte Order Mark (BOM) encoded XML streams (`\xFF\xFE`, `\xFE\xFF`, and `\xEF\xBB\xBF`) to UTF-8 in `ZipReader#read_entry` and `EntryStreamIO`, enabling seamless parsing of workbooks generated on Windows Phone and legacy platforms.
|
|
56
|
+
- XML 1.0 line ending normalization (`\r\n` and `\r` to `\n`): Normalize line breaks in shared strings, inline strings, and cell text values per W3C XML 1.0 ยง2.11 across `SharedStringsParser` and `WorksheetParser`.
|
|
57
|
+
- Whitespace and newline tolerance in cell regex scanning: Allow whitespace and newline sequences between `<c>` child tags (`<f>`, `<v>`, `<is>`) and strip whitespace on extracted values in `WorksheetParser`, ensuring reliable parsing of pretty-printed or formatted worksheet XML.
|
|
58
|
+
- Sequential row index fallback for omitted `r` attributes: Track previous row index and fall back to sequential 1-based indexing when `<row>` elements omit the `r` attribute per ECMA-376 Part 1 ยง18.3.1.73 across direct string scanning, chunked stream scanning, and event scanning in `WorksheetParser`.
|
|
59
|
+
- Case-insensitive part name lookup in `ZipReader`: Fall back to case-insensitive lookup for package part entries per ECMA-376 Part 2 ยง8.1.1, allowing workbooks with case-varying part names (such as lower-case `xl/sharedstrings.xml` or `xl/styles.xml`) to resolve transparently.
|
|
60
|
+
- Windows backslash path separator normalization in `ZipReader`: Normalize Windows backslash separators (`\`) in ZIP central directory and local headers to standard forward slashes (`/`), enabling transparent extraction and catalog lookup for XLSX archives generated on Windows.
|
|
61
|
+
- First-class sparkline groups on worksheet and `add_sparkline` helper: Expose `sparkline_groups` reader and keyword argument on `Elements::Worksheet`, propagate `ws.sparkline_groups` during `Xlsxrb.write` DOM serialization, and add `add_sparkline(location:, range:, type:, **opts)` helper to `WorksheetBuilder`, `StreamWriter`, and `StreamWriter::SheetContext` supporting `:win_loss` mapping to `"stacked"`.
|
|
62
|
+
- High-level print area and print titles DSL: Add `print_area`, `print_titles`, `repeat_rows`, and `repeat_columns` to `WorksheetBuilder`, `StreamWriter::SheetContext`, and `StreamWriter`, expose `print_area` and `print_titles` on `Elements::Worksheet`, and auto-generate `_xlnm.Print_Area` and `_xlnm.Print_Titles` defined names in `WorkbookBuilder#build` and `Xlsxrb.write` DOM export.
|
|
63
|
+
- ECMA-376 indexed color palette and `Xlsxrb::Colors`: Add `Xlsxrb::Colors` providing `INDEXED_COLORS` (indices 0..63 per ECMA-376 Part 4 ยง18.8.27), `palette_color`, and `to_hex` utilities, expose `Xlsxrb.palette_color` and `Xlsxrb.to_hex_color` facade methods, and resolve integer palette indices 0..63 automatically in `StyleBuilder.resolve_color`.
|
|
64
|
+
- Flexible rich text run input in `Xlsxrb.rich_text`: Support `[text, font_hash]` pair arrays, alternating varargs of plain strings and format hashes or objects responding to `to_font_hash`, and mixed `Elements::RichTextRun` instances.
|
|
65
|
+
- First-class `Elements::Hyperlink`, `Xlsxrb.hyperlink`, and `Cell#tooltip`: Add `Elements::Hyperlink` data class and `Xlsxrb.hyperlink` factory helper with `tooltip:` support, expose `Cell#tooltip` and `:tooltip`, `:url` symbol key access on `Elements::Cell`, and support `Elements::Hyperlink` instances in `WorksheetBuilder#hyperlink`, `StreamWriter#hyperlink`, and `Ooxml::Writer#hyperlink`.
|
|
66
|
+
- Array and dynamic array formula serialization and `Xlsxrb.array_formula`: Add `Xlsxrb.array_formula(expression, ref, cached_value:)` factory method, extend `Xlsxrb.formula` with optional `type:` and `ref:` keywords, and serialize `<f t="array" ref="...">` and shared formula attributes across all `WorksheetWriter` serialization paths.
|
|
67
|
+
- First-class `style_index:` keyword on `Elements::Column`: Add `style_index:` keyword argument directly to `Elements::Column.new`, storing it in `Data.define` attributes and populating it from `rc[:style_index]` during worksheet parsing and DSL column definitions.
|
|
68
|
+
- In-memory streaming write and row append chaining: Support `Xlsxrb.write` with omitted target in block mode to return an in-memory binary String, support self-returning `<<` row appending for chaining across `StreamWriter`, `SheetContext`, and `WorksheetBuilder`, and add `add_row` aliases.
|
|
69
|
+
- Unified color and border style normalizers in `StyleBuilder`: Add `StyleBuilder.normalize_color` (supporting 140+ CSS named colors, `#RGB`, `#RRGGBB`, `#AARRGGBB` hex strings, numeric RGB integers, and optional alpha channel) and `StyleBuilder.normalize_border_style` (supporting border style symbols, aliases, strings, and 0..13 numeric border indices).
|
|
70
|
+
- Public date and time serial conversion utilities: Expose `date_to_serial`, `serial_to_date`, `datetime_to_serial`, and `serial_to_time` (aliased `serial_to_datetime`) on `Xlsxrb` and `Xlsxrb::Utils` for converting Ruby `Date` and `Time` instances to and from Excel 1900 and 1904 serial numbers.
|
|
71
|
+
- Cascade style inheritance and column styles: Support cascade style inheritance (Cell Style > Row Style > Column Style) in `WorksheetWriter`, and add `style:` parameter to `StreamWriter#column` and `WorksheetBuilder#column`.
|
|
72
|
+
- Embedded drawing and image extraction: Add `Elements::Image` representing anchored embedded images, expose `images`, `images_at`, and `with_images` across `StreamSheet` and `Elements::Worksheet`, and expose `images` and `images_at` across `Elements::Workbook`.
|
|
73
|
+
- Configurable sparse vs padded row and cell iteration: Add `pad_empty_rows` and `pad_empty_cells` options to `Xlsxrb.read`, `Xlsxrb.build_worksheet`, `StreamSheet`, `WorksheetParser.each_row`, and `Elements::Worksheet` to pad skipped rows or missing cells up to the maximum column, and add `StreamRow#to_h` and `Elements::Row#cells_hash` for coordinate-keyed row maps.
|
|
74
|
+
- Row XML metadata accessors and serialization: Expose row XML metadata (`collapsed`, `collapsed?`, `hidden?`, `custom_height?`, `attributes`) on `StreamRow` and `Elements::Row`, support `collapsed:` in `StreamWriter#row` and `WorksheetBuilder#row`, and serialize `collapsed="1"` in `WorksheetWriter`.
|
|
75
|
+
- Format classification helpers: Add `Elements::Styles#format_code_for` and `#classification_for` aliases, allow `NumberFormatter` format predicates (`date_format?`, `time_format?`, etc.) to resolve built-in formats by `num_fmt_id`, and expose `format_type`, `date_format?`, and `time_format?` on `Elements::Cell`.
|
|
76
|
+
- Date1904 accessor: Expose `Ooxml::Reader#date1904?` and add `date1904:` keyword argument to `Elements::Workbook#initialize`.
|
|
77
|
+
- Coordinate utilities module: Add `Xlsxrb::Utils` exposing public coordinate helpers (`ref_to_row_col`, `row_col_to_ref`, `col_name_to_index`, `col_index_to_name`, `split_coordinate`).
|
|
78
|
+
- Configurable trailing empty row trimming: Add `trim_empty_rows` option across `Xlsxrb.read`, `Xlsxrb.build_worksheet`, `WorksheetParser.each_row`, `StreamSheet#initialize`, `StreamSheet#each_row`, `StreamSheet#each_row_values`, `StreamSheet#each`, `Elements::Worksheet#initialize`, `Elements::Worksheet#each_row`, and `Elements::Worksheet#each_row_values` to omit trailing empty rows, and add `empty?` predicate to `StreamRow` and `Elements::Row`.
|
|
79
|
+
- Direct typed values streaming iterator: Add `StreamSheet#each_row_values` and `Elements::Worksheet#each_row_values` to stream row values directly as Arrays without allocating `Elements::Cell` objects, and add `type_cast: true` support across `StreamSheet#each_row_values`, `Elements::Worksheet#each_row_values`, `StreamRow#values`, and `Elements::Row#values` to coerce date/time serial numbers into `Date` and `Time` instances.
|
|
80
|
+
- Precomputed number format classifications in Styles: Add `Xlsxrb::Elements::Styles` (subclass of `Hash`) with precomputed $O(1)$ format classification lookups (`number_format`, `format_type`, `date_format?`, `datetime_format?`, `time_format?`, `date_only_format?`), update `StylesParser.parse` to return `Elements::Styles`, and add classification helper methods to `Xlsxrb::NumberFormatter`.
|
|
81
|
+
- Worksheet dimension and coordinate bounds: Expose `dimension`, `first_row`, `first_column` (aliased `first_col`), `last_row`, and `last_column` (aliased `last_col`) on `StreamSheet` and `Elements::Worksheet` (and `Elements::CoordinateAccess`), lazily extracting `<dimension ref="..."/>` in $O(1)$ memory without scanning the full sheet.
|
|
82
|
+
- Date1904 propagation to streaming sheets and rows: Propagate the workbook's 1904 date system flag to `StreamSheet` and `StreamRow`, expose `date1904?` on `StreamSheet`, `StreamRow`, `Elements::Worksheet`, and `Elements::Cell`, and default `Cell#to_date` and `Cell#to_time` to the cell's `date1904` setting.
|
|
83
|
+
- `Elements::RichTextRun`: Add `RichTextRun` data class representing formatted text runs within `RichText`, supporting hash-like bracket access and seamless integration with `Xlsxrb.rich_text`.
|
|
84
|
+
- First-class conditional formatting and data validation on `Elements::Worksheet`: Expose `conditional_formatting` (and alias `conditional_formats`) and `data_validations` as first-class fields on `Elements::Worksheet`, populate them during round-trip parsing in `Xlsxrb.build_worksheet`, and serialize them in in-memory workbook serialization.
|
|
85
|
+
- Date1904 calendar system arithmetic: Support the 1904 date system (1904-01-01 base epoch) across serial date conversions, `Cell#to_date`, `Cell#to_time`, `Elements::Workbook#date1904?`, `Ooxml::Reader`, `Ooxml::WorksheetWriter`, `Ooxml::WorkbookWriter`, and `StreamWriter`.
|
|
86
|
+
- Row and column styles persistence: Expose `style_index` on `Row`, `Column`, and `StreamRow`, and persist row and column styles (`<row s="..." customFormat="1">` and `<col style="..."/>`) during serialization and round-trip parsing.
|
|
87
|
+
- Styles metadata persistence: Support border colors, cell alignment, and protection attributes in stylesheet generation and round-trip parsing.
|
|
88
|
+
- Dual format support for `num_fmts`: Support both `Hash` (`{ 164 => "format" }`) and `Array` (`[{ num_fmt_id: 164, format_code: "format" }]`) structures for custom number formats in `WorkbookWriter`.
|
|
89
|
+
- Initial shared strings table seeding: Support pre-seeding `sst` in `Xlsxrb.write` when `workbook.shared_strings` is provided.
|
|
90
|
+
- Sheet visibility state: Support worksheet visibility state (`state`, `hidden?`, `visible?`) across `StreamSheet`, `Elements::Worksheet`, `WorkbookParser`, `WorkbookBuilder`, and `WorkbookWriter`, preserving `:visible`, `:hidden`, and `:very_hidden` visibility in streaming read, in-memory representations, and XML serialization.
|
|
91
|
+
- Workbook defined names: Parse `<definedNames>` in `WorkbookParser` and expose `defined_names` array and `defined_name(name, sheet: nil)` lookup on `Elements::Workbook`, supporting global and sheet-scoped named ranges and formula constants.
|
|
92
|
+
- Cell formula query and expression methods: Expose `formula?` predicate and `formula_expression` string accessor on `Elements::Cell`, and normalize empty formula expressions to `nil` in streaming and DOM cell parsing.
|
|
93
|
+
- Worksheet and cell hyperlinks: Parse and expose hyperlink metadata across `StreamSheet#hyperlinks`, `Elements::Worksheet#hyperlinks`, and `Elements::Cell#hyperlink`, `#link?`, and `#url`, supporting external targets and internal sheet references in streaming read, DOM models, and builders.
|
|
94
|
+
- Worksheet and cell comments: Parse and expose comment and note metadata across `StreamSheet#comments`, `StreamSheet#comment`, `Elements::Worksheet#comments`, and `Elements::Cell#comment`, `#comment?`, and `#comment_text`, supporting comment annotations and coordinate lookups in streaming read, DOM models, and builders.
|
|
95
|
+
- Number formatting engine and extended cell metadata: Add `Xlsxrb::NumberFormatter` supporting standard and custom OpenXML format codes (currencies, percentages, date/time, fixed-point padding, accounting patterns, scientific notation, and text), expose `formatted_value`, `raw_value`, and `format_code` on `Elements::Cell`, add `formatted_value` coordinate lookups on `Elements::Worksheet`, `StreamSheet`, and `Elements::Workbook`, and expose `raw_values`, `formatted_values`, and `formulas` metadata on `Elements::Row` and `StreamRow`.
|
|
96
|
+
- Fallback serialization for DOM model attributes: Support serializing first-class `ws.state`, `ws.comments`, `ws.hyperlinks`, and `workbook.defined_names` in `Xlsxrb.write(workbook)` when not explicitly packaged inside `unmapped_data[:facade]` metadata.
|
|
97
|
+
|
|
98
|
+
### Changed
|
|
99
|
+
- Optimize chunked streaming read performance: Hoist `</sheetData>` tag lookup outside row iteration, eliminate byte delimiter array allocations, and terminate entry inflation early once worksheet rows are fully parsed, restoring streaming read throughput faster than in-memory read while preserving $O(1)$ memory consumption.
|
|
100
|
+
|
|
101
|
+
### Fixed
|
|
102
|
+
- Fallback cached value for formula cells: Emit `<v>0</v>` instead of omitting `<v>` when a formula cell does not specify a cached value, ensuring compatibility with OpenXML parsers (such as Roo and LibreOffice) that discard formula cells lacking `<v>` elements.
|
|
103
|
+
- Shared formula cell parsing: Support self-closing formula tags (e.g. `<f t="shared" si="0"/>`) in `WorksheetParser` regex scanners, preventing cells containing shared formulas from being silently omitted.
|
|
104
|
+
- Fixed missing `dcterms:created` and `dcterms:modified` serialization in `WorkbookWriter` core properties (`docProps/core.xml`).
|
|
105
|
+
- Prevent `Encoding::CompatibilityError` in `Xlsxrb.read` and `Cfb::Reader.cfb?` when inspecting raw string buffers in UTF-8 encoding.
|
|
106
|
+
|
|
3
107
|
## [0.1.13] - 2026-09-25
|
|
4
108
|
|
|
5
109
|
### Added
|
data/README.md
CHANGED
|
@@ -2,22 +2,25 @@
|
|
|
2
2
|
|
|
3
3
|
A Ruby library for reading and writing XLSX files with streaming support.
|
|
4
4
|
|
|
5
|
+
Drop-in compatibility adapters for peer Ruby XLSX libraries are available at [xlsxrb-adapters](https://github.com/niku/xlsxrb-adapters).
|
|
6
|
+
|
|
5
7
|
## Motivation
|
|
6
8
|
|
|
7
9
|
The Ruby ecosystem has several XLSX libraries designed for specific tradeoffs:
|
|
8
10
|
|
|
9
11
|
| Library | Read | Write | Streaming | In-Memory |
|
|
10
12
|
| :--- | :---: | :---: | :---: | :---: |
|
|
11
|
-
| [roo](https://rubygems.org/gems/roo) |
|
|
12
|
-
| [creek](https://rubygems.org/gems/creek) |
|
|
13
|
-
| [xsv](https://rubygems.org/gems/xsv) |
|
|
14
|
-
| [simple_xlsx_reader](https://rubygems.org/gems/simple_xlsx_reader) |
|
|
15
|
-
| [caxlsx / axlsx](https://rubygems.org/gems/caxlsx) |
|
|
16
|
-
| [write_xlsx](https://rubygems.org/gems/write_xlsx) |
|
|
17
|
-
| [xlsxtream](https://rubygems.org/gems/xlsxtream) |
|
|
18
|
-
| [fast_excel](https://rubygems.org/gems/fast_excel) |
|
|
19
|
-
| [rubyXL](https://rubygems.org/gems/rubyXL) |
|
|
20
|
-
| [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
|
+
|
|
21
24
|
|
|
22
25
|
These libraries make different architectural tradeoffs:
|
|
23
26
|
* Streaming Model: Writes or reads rows sequentially on-the-fly to maintain a constant $O(1)$, low-memory footprint regardless of dataset size.
|
|
@@ -37,7 +40,7 @@ Maintaining a gem that supports both reading and writing across streaming and in
|
|
|
37
40
|
|
|
38
41
|
### Autonomous Quality Assurance
|
|
39
42
|
|
|
40
|
-
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)).
|
|
41
44
|
|
|
42
45
|
## Installation
|
|
43
46
|
|
|
@@ -50,13 +53,13 @@ bundle add xlsxrb
|
|
|
50
53
|
|
|
51
54
|
Try `xlsxrb` directly in your browser without installing anything!
|
|
52
55
|
|
|
53
|
-
[
|
|
56
|
+
[Try the Live Demo / Interactive Playground](https://niku.github.io/xlsxrb/preview.html)
|
|
54
57
|
|
|
55
58
|
<p align="center">
|
|
56
59
|
<img src="docs/assets/playground_preview.png" width="100%" alt="Interactive WebAssembly Playground with Live LibreOffice Preview"/>
|
|
57
60
|
</p>
|
|
58
61
|
|
|
59
|
-
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).
|
|
60
63
|
|
|
61
64
|
## Usage
|
|
62
65
|
|
|
@@ -170,7 +173,7 @@ Verified by a multi-layered QA architecture:
|
|
|
170
173
|
* Microsoft Open XML SDK Validation: Validates generated OOXML structures against Microsoft's official SDK.
|
|
171
174
|
* Visual Regression Testing (VRT): Headless LibreOffice Calc pixel-by-pixel rendering checks.
|
|
172
175
|
* Contract & Round-Trip Tests: Verifies parity between Streaming and In-Memory APIs and round-trip read/write accuracy.
|
|
173
|
-
* Mutation Testing (Mutant): 100% mutant kill rate (1,
|
|
176
|
+
* 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)).
|
|
174
177
|
* Security & DoS Protection: Formula injection mitigation and ZIP bomb protection.
|
|
175
178
|
|
|
176
179
|
For full architectural details, see [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) and [docs/QUALITY_ASSURANCE.md](docs/QUALITY_ASSURANCE.md).
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
# rbs_inline: enabled
|
|
4
|
+
|
|
5
|
+
module Xlsxrb
|
|
6
|
+
# ECMA-376 Part 4 ยง18.8.27 Standard Indexed Color Palette and utilities.
|
|
7
|
+
module Colors
|
|
8
|
+
# Standard ECMA-376 indexed colors (indices 0 through 63 as 6-character RRGGBB hex strings).
|
|
9
|
+
# Indices 8 through 63 represent the classic 56-color palette.
|
|
10
|
+
INDEXED_COLORS = [
|
|
11
|
+
"000000", # 0
|
|
12
|
+
"FFFFFF", # 1
|
|
13
|
+
"FF0000", # 2
|
|
14
|
+
"00FF00", # 3
|
|
15
|
+
"0000FF", # 4
|
|
16
|
+
"FFFF00", # 5
|
|
17
|
+
"FF00FF", # 6
|
|
18
|
+
"00FFFF", # 7
|
|
19
|
+
"000000", # 8: Black
|
|
20
|
+
"FFFFFF", # 9: White
|
|
21
|
+
"FF0000", # 10: Red
|
|
22
|
+
"00FF00", # 11: Green
|
|
23
|
+
"0000FF", # 12: Blue
|
|
24
|
+
"FFFF00", # 13: Yellow
|
|
25
|
+
"FF00FF", # 14: Magenta
|
|
26
|
+
"00FFFF", # 15: Cyan
|
|
27
|
+
"800000", # 16: Brown / Dark Red
|
|
28
|
+
"008000", # 17: Olive / Dark Green
|
|
29
|
+
"000080", # 18: Navy / Dark Blue
|
|
30
|
+
"808000", # 19: Dark Yellow
|
|
31
|
+
"800080", # 20: Purple
|
|
32
|
+
"008080", # 21: Teal
|
|
33
|
+
"C0C0C0", # 22: Silver / Light Gray
|
|
34
|
+
"808080", # 23: Gray
|
|
35
|
+
"9999FF", # 24
|
|
36
|
+
"993366", # 25
|
|
37
|
+
"FFFFCC", # 26
|
|
38
|
+
"CCFFFF", # 27
|
|
39
|
+
"660066", # 28
|
|
40
|
+
"FF8080", # 29
|
|
41
|
+
"0066CC", # 30
|
|
42
|
+
"CCCCFF", # 31
|
|
43
|
+
"000080", # 32
|
|
44
|
+
"FF00FF", # 33
|
|
45
|
+
"FFFF00", # 34
|
|
46
|
+
"00FFFF", # 35
|
|
47
|
+
"800080", # 36
|
|
48
|
+
"800000", # 37
|
|
49
|
+
"008080", # 38
|
|
50
|
+
"0000FF", # 39
|
|
51
|
+
"00CCFF", # 40
|
|
52
|
+
"CCFFFF", # 41
|
|
53
|
+
"CCFFCC", # 42
|
|
54
|
+
"FFFFC0", # 43
|
|
55
|
+
"CCE5FF", # 44
|
|
56
|
+
"99CCFF", # 45
|
|
57
|
+
"FF99CC", # 46
|
|
58
|
+
"CC99FF", # 47
|
|
59
|
+
"FFCC99", # 48
|
|
60
|
+
"3366FF", # 49
|
|
61
|
+
"33CCCC", # 50
|
|
62
|
+
"99CC00", # 51
|
|
63
|
+
"FFCC00", # 52
|
|
64
|
+
"FF9900", # 53
|
|
65
|
+
"FF6600", # 54
|
|
66
|
+
"666699", # 55
|
|
67
|
+
"969696", # 56
|
|
68
|
+
"003366", # 57
|
|
69
|
+
"339966", # 58
|
|
70
|
+
"003300", # 59
|
|
71
|
+
"333300", # 60
|
|
72
|
+
"993300", # 61
|
|
73
|
+
"993366", # 62
|
|
74
|
+
"333333" # 63
|
|
75
|
+
].freeze
|
|
76
|
+
|
|
77
|
+
# Resolves a palette index (0..63) to an RRGGBB hex string (or AARRGGBB if alpha: true).
|
|
78
|
+
#
|
|
79
|
+
# @example
|
|
80
|
+
# Xlsxrb::Colors.palette_color(12) #=> "0000FF"
|
|
81
|
+
# Xlsxrb::Colors.palette_color(12, alpha: true) #=> "FF0000FF"
|
|
82
|
+
#
|
|
83
|
+
# @param index [Object, nil] Palette index (0..63).
|
|
84
|
+
# @param alpha [Boolean] Whether to prefix "FF" alpha channel.
|
|
85
|
+
# @return [String, nil]
|
|
86
|
+
# @api public
|
|
87
|
+
#: (untyped index, ?alpha: bool) -> String?
|
|
88
|
+
def self.palette_color(index, alpha: false)
|
|
89
|
+
return nil unless index.is_a?(Integer) && index >= 0 && index < INDEXED_COLORS.size
|
|
90
|
+
|
|
91
|
+
hex = INDEXED_COLORS[index]
|
|
92
|
+
alpha ? "FF#{hex}" : hex
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Converts any supported color representation (palette index 0..63, CSS name, #RGB, #RRGGBB, #AARRGGBB, integer RGB)
|
|
96
|
+
# to a normalized hex string.
|
|
97
|
+
#
|
|
98
|
+
# @example
|
|
99
|
+
# Xlsxrb::Colors.to_hex(12) #=> "0000FF"
|
|
100
|
+
# Xlsxrb::Colors.to_hex(12, alpha: true) #=> "FF0000FF"
|
|
101
|
+
# Xlsxrb::Colors.to_hex(:navy) #=> "000080"
|
|
102
|
+
# Xlsxrb::Colors.to_hex("#FF0000") #=> "FF0000"
|
|
103
|
+
# Xlsxrb::Colors.to_hex(0xFF0000) #=> "FF0000"
|
|
104
|
+
#
|
|
105
|
+
# @param color [Integer, String, Symbol, nil]
|
|
106
|
+
# @param alpha [Boolean] Whether to include the alpha channel (default false -> "RRGGBB").
|
|
107
|
+
# @return [String, nil]
|
|
108
|
+
# @api public
|
|
109
|
+
#: (Integer | String | Symbol | nil color, ?alpha: bool) -> String?
|
|
110
|
+
def self.to_hex(color, alpha: false)
|
|
111
|
+
return nil if color.nil?
|
|
112
|
+
|
|
113
|
+
return palette_color(color, alpha: alpha) if color.is_a?(Integer) && color >= 0 && color < INDEXED_COLORS.size
|
|
114
|
+
|
|
115
|
+
StyleBuilder.normalize_color(color, alpha: alpha)
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
end
|