fast_xlsx 0.8.1 → 1.0.0

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f530f027eb2e902f4bed36fdfd75af2851ff93a9762915a56f9de3e966eab593
4
- data.tar.gz: 794ddb87412acfa82840681a9caf32f85eb0d5b47fc0921c7091f3bbde020677
3
+ metadata.gz: 0642c1f4069d2b6537757d873ed2e591ddd3c7dab25f4bd1c867fad4fe8f0ead
4
+ data.tar.gz: d0b7696cc3ee573ec02821a3b210ef34ce68fb821c83666f2fa0938c8bbabc16
5
5
  SHA512:
6
- metadata.gz: 915d233e6c422187d23853c1c521bdefbf3336d85af03574882dc14a8055b1f692e3044588281c33c94e451be5123f516c4b07e2596111782c2b2a1f68fa261a
7
- data.tar.gz: 98aa0c5de0d29816828a8fe6215c5132b7bd88297ed13bf6db9df9ddd6f0221e27f7a804a082e4430daffbb235193f1c85ffb898f41f6fee94940625d0caabb2
6
+ metadata.gz: 40fbd10f5ad43e8fc7a6bedccdc68cee4a324fa5ae9586dd7e9281272c6c2b1a465049c53fd67f042c9dffe00ca7c21c1512d4e1ffcbd01e2ea5ce52dc658938
7
+ data.tar.gz: 5a6ca0279e195f3b109d23f0bf1afbed5680c6f6fd844aa0e30411468e1f8d7203680d30bba838cdb15b2dfac1f9c170a9b9576ed5db0650439c331fd2ff11be
data/CHANGELOG.md CHANGED
@@ -1,5 +1,14 @@
1
1
  ## [Unreleased]
2
2
 
3
+ ## [1.0.0] - 2026-10-18
4
+
5
+ The first stable release, with the same API as 0.8.1. From now on fast_xlsx follows Semantic Versioning: no breaking change before 2.0, and anything to be removed first prints a deprecation warning for at least one minor release.
6
+
7
+ ### Fixed
8
+
9
+ - Updated rust_xlsxwriter to 0.100, which brings zip 9.0 (RUSTSEC-2026-0367, -0368 and -0369; those affect extracting archives, which fast_xlsx never does).
10
+ - In `memory: :constant` and `:low` mode, a temporary file that can't be created (e.g. an unwritable temp directory) raises `FastXlsx::Error` instead of crashing the process. The file is also created only when the first row is flushed, not by `add_worksheet`.
11
+
3
12
  ## [0.8.1] - 2026-10-03
4
13
 
5
14
  ### Fixed
data/Cargo.lock CHANGED
@@ -56,6 +56,12 @@ version = "1.0.5"
56
56
  source = "registry+https://github.com/rust-lang/crates.io-index"
57
57
  checksum = "4e7648175b45a9a48536d676f68d918270699102aa8dab5496df06904c914600"
58
58
 
59
+ [[package]]
60
+ name = "cfg_aliases"
61
+ version = "0.2.2"
62
+ source = "registry+https://github.com/rust-lang/crates.io-index"
63
+ checksum = "f079e83a288787bcd14a6aea84cee5c87a67c5a3e660c30f557a3d24761b3527"
64
+
59
65
  [[package]]
60
66
  name = "clang-sys"
61
67
  version = "1.9.1"
@@ -201,9 +207,9 @@ checksum = "f9f8bd3e56ce4dfc153cf470fffbfa98c7620958b312ca5c3a4b8d5181fd13c6"
201
207
 
202
208
  [[package]]
203
209
  name = "magnus"
204
- version = "0.9.1"
210
+ version = "0.9.2"
205
211
  source = "registry+https://github.com/rust-lang/crates.io-index"
206
- checksum = "4c01bef153b8d0f086991f0e166474a1d57b738221f9a9c11405d498ac95a44d"
212
+ checksum = "b9068710e00d21be762edca59b9c4c8946dbdb29820d4f76ad559afea07982c9"
207
213
  dependencies = [
208
214
  "magnus-macros",
209
215
  "rb-sys",
@@ -234,6 +240,18 @@ version = "0.2.1"
234
240
  source = "registry+https://github.com/rust-lang/crates.io-index"
235
241
  checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a"
236
242
 
243
+ [[package]]
244
+ name = "nix"
245
+ version = "0.31.3"
246
+ source = "registry+https://github.com/rust-lang/crates.io-index"
247
+ checksum = "cf20d2fde8ff38632c426f1165ed7436270b44f199fc55284c38276f9db47c3d"
248
+ dependencies = [
249
+ "bitflags",
250
+ "cfg-if",
251
+ "cfg_aliases",
252
+ "libc",
253
+ ]
254
+
237
255
  [[package]]
238
256
  name = "nom"
239
257
  version = "7.1.3"
@@ -335,9 +353,9 @@ checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
335
353
 
336
354
  [[package]]
337
355
  name = "rust_xlsxwriter"
338
- version = "0.99.1"
356
+ version = "0.100.0"
339
357
  source = "registry+https://github.com/rust-lang/crates.io-index"
340
- checksum = "34f2d2cda7223168a14fb86bc7411dbc3379bd7d49749ecc53b91ed98585b6b0"
358
+ checksum = "c44904ffb6c57b148ffcc8ce3011c28bc49b97e1a8343b2d632283cd566e1393"
341
359
  dependencies = [
342
360
  "tempfile",
343
361
  "zip",
@@ -439,14 +457,15 @@ dependencies = [
439
457
 
440
458
  [[package]]
441
459
  name = "zip"
442
- version = "8.6.0"
460
+ version = "9.0.5"
443
461
  source = "registry+https://github.com/rust-lang/crates.io-index"
444
- checksum = "2d04a6b5381502aa6087c94c669499eb1602eb9c5e8198e534de571f7154809b"
462
+ checksum = "6e04976da629d3b04204ba8105b396a193af8ad2583b2c79bfb3ab8af580a11e"
445
463
  dependencies = [
446
464
  "crc32fast",
447
465
  "flate2",
448
466
  "indexmap",
449
467
  "memchr",
468
+ "nix",
450
469
  "typed-path",
451
470
  "zopfli",
452
471
  ]
data/README.md CHANGED
@@ -1,15 +1,17 @@
1
- # FastXlsx
1
+ # fast_xlsx
2
2
 
3
- [![Gem Version](https://badge.fury.io/rb/fast_xlsx.svg)](https://badge.fury.io/rb/fast_xlsx)
3
+ ![fast_xlsx: fast .xlsx writer for Ruby, powered by Rust](docs/social-preview.jpg)
4
+
5
+ [![Gem Version](https://img.shields.io/gem/v/fast_xlsx)](https://rubygems.org/gems/fast_xlsx)
4
6
  [![codecov](https://codecov.io/gh/7a6163/fast_xlsx/graph/badge.svg)](https://codecov.io/gh/7a6163/fast_xlsx)
5
7
 
6
- Fast `.xlsx` writer for Ruby, built on [rust_xlsxwriter](https://github.com/jmcnamara/rust_xlsxwriter) via [magnus](https://github.com/matsadler/magnus).
8
+ Write Excel `.xlsx` files from Ruby with a Rust engine ([rust_xlsxwriter](https://github.com/jmcnamara/rust_xlsxwriter), via [magnus](https://github.com/matsadler/magnus)): 20,000 rows in under 100 ms, with memory that stays flat for large exports.
7
9
 
8
- > **Status: release candidate.** The API is frozen as of 0.8: 0.8.x releases only fix bugs, and 1.0 follows once it has been in real use without needing changes.
10
+ > **Status: stable.** Since 1.0 the API follows [Semantic Versioning](https://semver.org): no breaking change before 2.0.
9
11
 
10
- **Roadmap:** [1.0.0](https://github.com/7a6163/fast_xlsx/milestone/1) (release plan) · [1.x](https://github.com/7a6163/fast_xlsx/milestone/2) (planned features)
12
+ **Roadmap:** [1.x](https://github.com/7a6163/fast_xlsx/milestone/2) (planned features)
11
13
 
12
- **Contents:** [Installation](#installation) · [Getting started](#getting-started) · [Guide](#guide) · [Performance](#performance) · [Support and versioning](#support-and-versioning) · [Development](#development)
14
+ **Contents:** [Installation](#installation) · [Getting started](#getting-started) · [Guide](#guide) · [Performance](#performance) · [Support and versioning](#support-and-versioning) · [Development](#development) · [Credits](#credits)
13
15
 
14
16
  ## Installation
15
17
 
@@ -81,7 +83,7 @@ The [Guide](#guide) below covers every feature; the [API docs](https://www.rubyd
81
83
 
82
84
  ## Guide
83
85
 
84
- [Writing cells](#writing-cells) · [Rails](#rails) · [Memory modes](#memory-modes) · [Formats](#formats) · [Columns and filters](#columns-and-filters) · [Sheet view and printing](#sheet-view-and-printing) · [Cell ranges](#cell-ranges) · [Layout](#layout) · [Outline groups](#outline-groups) · [Defined names](#defined-names) · [Protection](#protection) · [Conditional formats](#conditional-formats) · [Data validation](#data-validation) · [Comments](#comments) · [Images](#images) · [Tables](#tables) · [Charts](#charts) · [Errors](#errors)
86
+ [Writing cells](#writing-cells) · [Rails](#rails) · [Polars](#polars) · [Memory modes](#memory-modes) · [Formats](#formats) · [Columns and filters](#columns-and-filters) · [Sheet view and printing](#sheet-view-and-printing) · [Cell ranges](#cell-ranges) · [Layout](#layout) · [Outline groups](#outline-groups) · [Defined names](#defined-names) · [Protection](#protection) · [Conditional formats](#conditional-formats) · [Data validation](#data-validation) · [Comments](#comments) · [Images](#images) · [Tables](#tables) · [Charts](#charts) · [Errors](#errors)
85
87
 
86
88
  ### Writing cells
87
89
 
@@ -126,6 +128,23 @@ def export
126
128
  end
127
129
  ```
128
130
 
131
+ ### Polars
132
+
133
+ To write a [ruby-polars](https://github.com/ankane/ruby-polars) DataFrame (gem `polars-df`), hand its column names and rows to fast_xlsx:
134
+
135
+ ```ruby
136
+ df = Polars.read_csv("sales.csv")
137
+ summary = df.group_by("region").agg(Polars.col("amount").sum)
138
+
139
+ wb = FastXlsx::Workbook.new(memory: :constant)
140
+ ws = wb.add_worksheet("By region")
141
+ ws.append(summary.columns, format: { bold: true })
142
+ summary.iter_rows { |row| ws << row } # in batches of 512 rows, so memory stays flat
143
+ wb.save("by_region.xlsx")
144
+ ```
145
+
146
+ Polars `Date` and `Datetime` columns become dates (a `Datetime` with a time zone keeps its local time), `Decimal` numbers, and nulls empty cells.
147
+
129
148
  ### Memory modes
130
149
 
131
150
  By default every cell stays in memory until the file is saved. For large exports, two modes write each finished row to a temp file instead:
@@ -402,15 +421,15 @@ Apple Silicon, Ruby 4.0.5. Each library uses its own idiomatic row-append API; x
402
421
 
403
422
  | Library | Time | vs fastest | Ruby objects allocated |
404
423
  |---|---:|---:|---:|
405
- | **fast_xlsx** (`memory: :constant`) | **77 ms** | 1.0x | 7 |
406
- | **fast_xlsx** (`memory: :low`) | **86 ms** | 1.1x | 7 |
407
- | **fast_xlsx** | **89 ms** | 1.1x | 10 |
408
- | [xlsxtream](https://github.com/felixbuenemann/xlsxtream) 3.1 | 183 ms | 2.4x | 561,728 |
409
- | [fast_excel](https://github.com/Paxa/fast_excel) 0.5 (constant_memory) | 200 ms | 2.6x | 20,079 |
410
- | [fast_excel](https://github.com/Paxa/fast_excel) 0.5 | 238 ms | 3.1x | 320,076 |
411
- | [write_xlsx](https://github.com/cxn03651/write_xlsx) 1.15 | 608 ms | 7.8x | 1,483,899 |
412
- | [caxlsx](https://github.com/caxlsx/caxlsx) 4.5 | 689 ms | 8.9x | 745,122 |
413
- | [rubyXL](https://github.com/weshatheleopard/rubyXL) 3.4 | 2755 ms | 35.6x | 8,700,448 |
424
+ | **fast_xlsx** (`memory: :constant`) | **75 ms** | 1.0x | 7 |
425
+ | **fast_xlsx** (`memory: :low`) | **81 ms** | 1.1x | 7 |
426
+ | **fast_xlsx** | **85 ms** | 1.1x | 10 |
427
+ | [xlsxtream](https://github.com/felixbuenemann/xlsxtream) 3.1 | 173 ms | 2.3x | 561,740 |
428
+ | [fast_excel](https://github.com/Paxa/fast_excel) 0.5 (constant_memory) | 204 ms | 2.7x | 20,079 |
429
+ | [fast_excel](https://github.com/Paxa/fast_excel) 0.5 | 238 ms | 3.2x | 320,076 |
430
+ | [write_xlsx](https://github.com/cxn03651/write_xlsx) 1.15 | 592 ms | 7.9x | 1,483,899 |
431
+ | [caxlsx](https://github.com/caxlsx/caxlsx) 4.5 | 671 ms | 8.9x | 745,122 |
432
+ | [rubyXL](https://github.com/weshatheleopard/rubyXL) 3.4 | 2571 ms | 34.1x | 8,700,448 |
414
433
 
415
434
  All outputs are 689–750 KB.
416
435
 
@@ -448,8 +467,8 @@ BUNDLE_GEMFILE=bench/Gemfile /usr/bin/time -l bundle exec ruby bench/memory.rb f
448
467
 
449
468
  - **Ruby:** CRuby 3.3 and later. A Ruby version is dropped only after it reaches its end of life, and only in a minor release. JRuby and TruffleRuby are not supported (this is a native extension).
450
469
  - **Precompiled gems:** Linux (x86_64 and aarch64, glibc and musl; ARM musl), macOS (arm64 and x86_64) and Windows (x64). Before each release the Linux x86_64, macOS arm64 and Windows gems are installed and loaded on Ruby 3.3, 3.4 and 4.0. Other platforms build from source and need a Rust toolchain.
451
- - **Versions:** from 1.0, [Semantic Versioning](https://semver.org): no breaking API change before 2.0. Until then a minor release (0.x.0) can change behaviour; the [changelog](CHANGELOG.md) lists every change under "Changed".
452
- - **Deprecations:** from 1.0, a method or option to be removed first prints a warning (with `warn`, so on by default) for at least one minor release, with the CHANGELOG naming its replacement; it goes only in the next major version.
470
+ - **Versions:** [Semantic Versioning](https://semver.org) since 1.0: no breaking API change before 2.0. The [changelog](CHANGELOG.md) lists every change.
471
+ - **Deprecations:** a method or option to be removed first prints a warning (with `warn`, so on by default) for at least one minor release, with the CHANGELOG naming its replacement; it goes only in the next major version.
453
472
  - **Output:** `.xlsx` files that open in Excel 2007 and later, LibreOffice and Google Sheets. Updating rust_xlsxwriter can change the bytes of the file but not what it contains.
454
473
 
455
474
  ## Development
@@ -498,6 +517,10 @@ git tag v0.1.0 && git push origin v0.1.0
498
517
 
499
518
  The `Build gems` workflow builds the source gem plus precompiled gems for each platform and pushes them to RubyGems (trusted publishing) and GitHub Packages. It refuses to publish if the tag and `VERSION` differ.
500
519
 
520
+ ## Credits
521
+
522
+ Inspired by [fast_excel](https://github.com/Paxa/fast_excel), whose API and approach fast_xlsx builds on, and made possible by [rust_xlsxwriter](https://github.com/jmcnamara/rust_xlsxwriter) and [magnus](https://github.com/matsadler/magnus).
523
+
501
524
  ## License
502
525
 
503
526
  MIT
data/SECURITY.md ADDED
@@ -0,0 +1,26 @@
1
+ # Security policy
2
+
3
+ ## Supported versions
4
+
5
+ Security fixes go into the latest release of the newest minor version. Until 1.0 that is 0.8.x; from 1.0, the latest 1.x.
6
+
7
+ | Version | Supported |
8
+ |---|---|
9
+ | 0.8.x | ✅ |
10
+ | < 0.8 | ❌ (upgrade to 0.8.x; the [changelog](CHANGELOG.md) lists every change) |
11
+
12
+ ## Reporting a vulnerability
13
+
14
+ Please don't open a public issue. Report it privately through GitHub: on the repository's **Security** tab, choose **Report a vulnerability** ([direct link](https://github.com/7a6163/fast_xlsx/security/advisories/new)).
15
+
16
+ Include what an attacker could do, the fast_xlsx, Ruby and platform versions, and a script or input that shows it, if you have one.
17
+
18
+ What to expect:
19
+
20
+ - An acknowledgement within a week.
21
+ - A fix in a patch release, and a GitHub security advisory crediting you (unless you'd rather not be named), once users can upgrade.
22
+ - If it turns out to be in a dependency (rust_xlsxwriter, magnus, rb-sys, the Rust zip crates), a report to that project as well.
23
+
24
+ ## Scope
25
+
26
+ fast_xlsx only writes `.xlsx` files: it doesn't read or parse spreadsheets. Issues of interest include memory-safety bugs in the native extension (a crash or corruption reachable from Ruby), and output that makes Excel or other readers misbehave from data an application would reasonably pass in (cell text, formulas, URLs, images). Formulas and hyperlinks are written as given: an application writing untrusted input as a `FastXlsx::Formula` or `FastXlsx::URL` should validate it first, as with CSV formula injection.
@@ -4,7 +4,7 @@ fast_xlsx started as a rewrite of [fast_excel](https://github.com/Paxa/fast_exce
4
4
 
5
5
  **Why switch**
6
6
 
7
- - 2.8–3.3× faster on the [README benchmark](../README.md#speed), and `memory: :constant` adds about 1 MB however large the file.
7
+ - Faster writing (see the [README benchmark](../README.md#speed)), and `memory: :constant` adds about 1 MB however large the file.
8
8
  - Precompiled gems for Linux, macOS and Windows: no C compiler or FFI at install.
9
9
  - Dates show as dates without a format, every option is checked (a typo raises instead of being ignored), and saving doesn't block other threads.
10
10
  - Conditional formats, data validation, tables, charts, images, comments, protection and printing options as Ruby methods.
@@ -14,7 +14,7 @@ magnus = { version = "0.9", features = ["rb-sys"] }
14
14
  rb-sys = { version = "0.9", features = ["stable-api-compiled-fallback"] }
15
15
  # No "zlib" feature: without it zip compresses with zlib-rs, which saves
16
16
  # 20-30% faster than the system zlib (and needs no C library).
17
- rust_xlsxwriter = { version = "0.99.1", features = ["constant_memory"] }
17
+ rust_xlsxwriter = { version = "0.100.0", features = ["constant_memory"] }
18
18
 
19
19
  [build-dependencies]
20
20
  rb-sys-env = "0.2.2"
@@ -237,9 +237,9 @@ impl Workbook {
237
237
  .unwrap(),
238
238
  };
239
239
  let ws = if self.low_memory {
240
- wb.add_worksheet_with_low_memory()
240
+ wb.add_worksheet_with_low_memory().map_err(xerr)?
241
241
  } else if self.constant_memory {
242
- wb.add_worksheet_with_constant_memory()
242
+ wb.add_worksheet_with_constant_memory().map_err(xerr)?
243
243
  } else {
244
244
  wb.add_worksheet()
245
245
  };
@@ -2,5 +2,5 @@
2
2
 
3
3
  module FastXlsx
4
4
  # The gem version.
5
- VERSION = "0.8.1"
5
+ VERSION = "1.0.0"
6
6
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: fast_xlsx
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.8.1
4
+ version: 1.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Zac
@@ -23,8 +23,9 @@ dependencies:
23
23
  - - "~>"
24
24
  - !ruby/object:Gem::Version
25
25
  version: 0.9.130
26
- description: Writes Excel .xlsx files from Ruby through a native Rust extension (rust_xlsxwriter
27
- + magnus).
26
+ description: 'Writes Excel .xlsx files from Ruby through a native Rust extension (rust_xlsxwriter):
27
+ 20,000 rows in under 100 ms, and memory that stays flat for large exports. Formats,
28
+ formulas, tables, charts, conditional formats, data validation and more.'
28
29
  email:
29
30
  - 579103+7a6163@users.noreply.github.com
30
31
  executables: []
@@ -40,6 +41,7 @@ files:
40
41
  - LICENSE.txt
41
42
  - README.md
42
43
  - Rakefile
44
+ - SECURITY.md
43
45
  - bench/Gemfile
44
46
  - bench/Gemfile.lock
45
47
  - bench/compare.rb
@@ -81,5 +83,5 @@ required_rubygems_version: !ruby/object:Gem::Requirement
81
83
  requirements: []
82
84
  rubygems_version: 4.0.10
83
85
  specification_version: 4
84
- summary: Fast xlsx writer for Ruby, powered by rust_xlsxwriter
86
+ summary: Excel .xlsx writer for Ruby with a Rust engine
85
87
  test_files: []