fast_xlsx 0.4.0-aarch64-linux → 0.5.0-aarch64-linux
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/.yardopts +7 -0
- data/CHANGELOG.md +11 -0
- data/README.md +17 -3
- data/bench/Gemfile.lock +2 -2
- data/lib/fast_xlsx/3.3/fast_xlsx.so +0 -0
- data/lib/fast_xlsx/3.4/fast_xlsx.so +0 -0
- data/lib/fast_xlsx/4.0/fast_xlsx.so +0 -0
- data/lib/fast_xlsx/version.rb +2 -1
- data/lib/fast_xlsx.rb +261 -55
- data/sig/fast_xlsx.rbs +1 -1
- 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: d5ce755a7313239e1f8aed891577dd789243053ba8898298449e6f374f7fa1b0
|
|
4
|
+
data.tar.gz: 981326856ac95f0b000f6129608b66f9fd426add3b67693b606442f74e8908d7
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2004ba52b608f7ce2ed3bd8d2d2245c77c7967c2160a33b129841004443fadd9ea49b5895683e2d758f3cece3987cc6b5bcc5a768d55fc1a53a4f08623211418
|
|
7
|
+
data.tar.gz: 60d511eb64ae1935c8bd04b40961c22b74967f8bac929dea16dc2facd01a4eee5c8c5afedd717c30d61fc328b263ccdc79f7c069d53cb4e32109812871642b29
|
data/.yardopts
ADDED
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,16 @@
|
|
|
1
1
|
## [Unreleased]
|
|
2
2
|
|
|
3
|
+
## [0.5.0] - 2026-10-01
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- API documentation: every public method has YARD docs (shown on rubydoc.info).
|
|
8
|
+
|
|
9
|
+
### Changed
|
|
10
|
+
|
|
11
|
+
- Errors follow one rule (see the README): a row or column outside the sheet raises `RangeError` (row 1,048,576, column 16,384 or a row of more than 16,384 cells raised `FastXlsx::Error` or `ArgumentError`); a reversed range or single-cell merge raises `ArgumentError` (was `FastXlsx::Error`); a header or footer over 255 characters raises `FastXlsx::Error` like other text over Excel's limits (was `ArgumentError`); a negative or NaN image size, font size or margin raises `ArgumentError` (was written into the file or ignored); `zoom` converts numbers with `to_int` like other arguments (`zoom(150.9)` raised `TypeError`); `column_width` outside 0..255 and `row_height` outside 0..409 raise `ArgumentError` (a negative one hid the column or row).
|
|
12
|
+
- Date and time cells written with a format that has no `num_format` (e.g. `append(row, format: bold)`) get the default date format added, instead of showing as serial numbers. This applies to a cell's own format, a table column's and `column_format`'s; a format with a `num_format` is used as is.
|
|
13
|
+
|
|
3
14
|
## [0.4.0] - 2026-10-01
|
|
4
15
|
|
|
5
16
|
### Changed
|
data/README.md
CHANGED
|
@@ -82,7 +82,7 @@ ws.write(1, 2, Date.today, date) # format one cell
|
|
|
82
82
|
|
|
83
83
|
Per-side borders override `border`. Unknown options and invalid values raise `ArgumentError`.
|
|
84
84
|
|
|
85
|
-
Dates and times
|
|
85
|
+
Dates and times are shown as `yyyy-mm-dd` or `yyyy-mm-dd hh:mm:ss`. A format without a `num_format` (yours, a table column's or `column_format`'s) keeps its look and gets that date format added, so `append(row, format: bold)` gives bold dates; a format with a `num_format` is used as is.
|
|
86
86
|
|
|
87
87
|
### Columns and filters
|
|
88
88
|
|
|
@@ -263,7 +263,16 @@ Values are mapped by type:
|
|
|
263
263
|
|
|
264
264
|
`<<` and `concat` append after the last row written to that worksheet. In `:constant` / `:low` memory mode rows are written to disk as you go, so fill each worksheet top to bottom.
|
|
265
265
|
|
|
266
|
-
Errors
|
|
266
|
+
### Errors
|
|
267
|
+
|
|
268
|
+
| Error | Raised for |
|
|
269
|
+
|---|---|
|
|
270
|
+
| `TypeError` | an argument of the wrong type, e.g. a String where a row number goes |
|
|
271
|
+
| `RangeError` | a row or column outside the sheet (1,048,576 × 16,384), or a negative count (an infinite Float raises `FloatDomainError`, a `RangeError`) |
|
|
272
|
+
| `ArgumentError` | the right type but a value that isn't allowed: an unknown option or symbol, an invalid color or cell reference, a reversed range or single-cell merge, a size or margin that is negative, NaN or beyond Excel's limits |
|
|
273
|
+
| `FastXlsx::Error` | what the workbook can't do: duplicate or invalid names, writing to rows already on disk, overlapping merges, hiding the sheet Excel opens on, text over Excel's limits (cells, URLs, headers and footers), unsupported images |
|
|
274
|
+
|
|
275
|
+
Numbers are converted like Ruby's own methods do (`to_int`), so `1.9` as a row is row `1`.
|
|
267
276
|
|
|
268
277
|
## Performance
|
|
269
278
|
|
|
@@ -323,7 +332,12 @@ BUNDLE_GEMFILE=bench/Gemfile /usr/bin/time -l bundle exec ruby bench/memory.rb f
|
|
|
323
332
|
bundle add fast_xlsx
|
|
324
333
|
```
|
|
325
334
|
|
|
326
|
-
|
|
335
|
+
### Support and versioning
|
|
336
|
+
|
|
337
|
+
- **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).
|
|
338
|
+
- **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.
|
|
339
|
+
- **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".
|
|
340
|
+
- **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.
|
|
327
341
|
|
|
328
342
|
## Development
|
|
329
343
|
|
data/bench/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
fast_xlsx (0.
|
|
4
|
+
fast_xlsx (0.5.0)
|
|
5
5
|
rb_sys (~> 0.9.130)
|
|
6
6
|
|
|
7
7
|
GEM
|
|
@@ -77,7 +77,7 @@ DEPENDENCIES
|
|
|
77
77
|
CHECKSUMS
|
|
78
78
|
caxlsx (4.5.0) sha256=e3d98d859f148df05d5462086b5079b523f29c1766b569535f1d68629ce743ff
|
|
79
79
|
fast_excel (0.5.0) sha256=59c418bdcf586a6030798d4e3a9f575742badaceaf7bb90f38eee5feb5bdc478
|
|
80
|
-
fast_xlsx (0.
|
|
80
|
+
fast_xlsx (0.5.0)
|
|
81
81
|
ffi (1.17.4-aarch64-linux-gnu) sha256=b208f06f91ffd8f5e1193da3cae3d2ccfc27fc36fba577baf698d26d91c080df
|
|
82
82
|
ffi (1.17.4-aarch64-linux-musl) sha256=9286b7a615f2676245283aef0a0a3b475ae3aae2bb5448baace630bb77b91f39
|
|
83
83
|
ffi (1.17.4-arm-linux-gnu) sha256=d6dbddf7cb77bf955411af5f187a65b8cd378cb003c15c05697f5feee1cb1564
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
data/lib/fast_xlsx/version.rb
CHANGED
data/lib/fast_xlsx.rb
CHANGED
|
@@ -3,21 +3,48 @@
|
|
|
3
3
|
require_relative "fast_xlsx/version"
|
|
4
4
|
|
|
5
5
|
# Fast .xlsx writer backed by rust_xlsxwriter.
|
|
6
|
+
#
|
|
7
|
+
# @example
|
|
8
|
+
# wb = FastXlsx::Workbook.new
|
|
9
|
+
# ws = wb.add_worksheet("Report")
|
|
10
|
+
# ws << ["id", "name", "created_at"]
|
|
11
|
+
# ws.concat(records.map { |r| [r.id, r.name, r.created_at] })
|
|
12
|
+
# wb.save("report.xlsx")
|
|
13
|
+
#
|
|
14
|
+
# Rows and columns are 0-based. Errors: TypeError for an argument of the wrong
|
|
15
|
+
# type, RangeError for a row or column outside the sheet, ArgumentError for a
|
|
16
|
+
# value that isn't allowed, {FastXlsx::Error} for what the workbook can't do.
|
|
6
17
|
module FastXlsx
|
|
18
|
+
# Raised for what the workbook can't do: duplicate or invalid names, writing
|
|
19
|
+
# to rows already on disk, overlapping merges, text over Excel's limits, ...
|
|
7
20
|
class Error < StandardError; end
|
|
8
21
|
|
|
9
|
-
#
|
|
22
|
+
# A cell value written as an Excel formula.
|
|
23
|
+
#
|
|
24
|
+
# @!attribute [r] expression
|
|
25
|
+
# @return [String] the formula, without the leading "="
|
|
26
|
+
# @example
|
|
27
|
+
# ws << [1, 2, FastXlsx::Formula.new("SUM(A1:B1)")]
|
|
10
28
|
Formula = Data.define(:expression) do
|
|
11
29
|
def initialize(expression:)
|
|
12
30
|
super(expression: expression.to_s)
|
|
13
31
|
end
|
|
14
32
|
end
|
|
15
33
|
|
|
16
|
-
#
|
|
17
|
-
#
|
|
34
|
+
# A cell value written as a hyperlink.
|
|
35
|
+
#
|
|
36
|
+
# @!attribute [r] url
|
|
37
|
+
# @return [String] http(s)://, mailto:, file:// or internal:Sheet2!A1
|
|
38
|
+
# @!attribute [r] text
|
|
39
|
+
# @return [String, nil] shown in the cell instead of the URL
|
|
40
|
+
# @example
|
|
41
|
+
# FastXlsx::URL.new("https://example.com")
|
|
42
|
+
# FastXlsx::URL.new("https://example.com/report/42", text: "Q3 report")
|
|
18
43
|
# Subclassed (not a Data.define block) so .new can call super, which lets it
|
|
19
44
|
# accept URL.new(url, text: ...) as well as the usual Data forms.
|
|
20
45
|
class URL < Data.define(:url, :text) # rubocop:disable Style/DataInheritance
|
|
46
|
+
# @overload new(url, text = nil)
|
|
47
|
+
# @overload new(url:, text: nil)
|
|
21
48
|
def self.new(*args, **kwargs)
|
|
22
49
|
raise ArgumentError, "wrong number of arguments (given #{args.size}, expected 0..2)" if args.size > 2
|
|
23
50
|
|
|
@@ -32,11 +59,18 @@ module FastXlsx
|
|
|
32
59
|
end
|
|
33
60
|
end
|
|
34
61
|
|
|
35
|
-
# Text with a format per segment
|
|
36
|
-
#
|
|
62
|
+
# Text with a format per segment.
|
|
63
|
+
#
|
|
64
|
+
# @example
|
|
65
|
+
# bold = FastXlsx::Format.new(bold: true)
|
|
66
|
+
# ws << [FastXlsx::RichString.new(["Total: ", bold], "1,234")]
|
|
37
67
|
class RichString
|
|
68
|
+
# @return [Array<Array(String, Format)>] [text, format or nil] per segment
|
|
38
69
|
attr_reader :segments
|
|
39
70
|
|
|
71
|
+
# @param parts [Array<String, Array(String, Format)>] each a String (default
|
|
72
|
+
# font) or [String, Format]
|
|
73
|
+
# @raise [ArgumentError] when no segment is given
|
|
40
74
|
def initialize(*parts)
|
|
41
75
|
raise ArgumentError, "RichString needs at least one segment" if parts.empty?
|
|
42
76
|
|
|
@@ -53,15 +87,31 @@ module FastXlsx
|
|
|
53
87
|
require "fast_xlsx/fast_xlsx"
|
|
54
88
|
end
|
|
55
89
|
|
|
56
|
-
# Owns the worksheets; serialize with #to_xlsx or #save.
|
|
90
|
+
# Owns the worksheets; serialize with {#to_xlsx} or {#save}.
|
|
91
|
+
#
|
|
92
|
+
# @!method to_xlsx
|
|
93
|
+
# The workbook as an .xlsx file. Runs without Ruby's global lock, so
|
|
94
|
+
# other threads keep running meanwhile.
|
|
95
|
+
# @return [String] binary
|
|
96
|
+
# @raise [FastXlsx::Error] e.g. duplicate defined names
|
|
97
|
+
#
|
|
98
|
+
# @!method define_name(name, formula)
|
|
99
|
+
# A defined name: "Rate" for the whole workbook, "Sheet1!Sales" for one
|
|
100
|
+
# sheet. Duplicates and unknown sheets are reported when saving.
|
|
101
|
+
# @param name [String]
|
|
102
|
+
# @param formula [String] e.g. "=0.96" or "=Sheet1!$A$1:$A$9"
|
|
103
|
+
# @return [self]
|
|
104
|
+
# @raise [FastXlsx::Error] for a name Excel doesn't allow
|
|
57
105
|
class Workbook
|
|
106
|
+
# Accepted memory: modes.
|
|
58
107
|
MEMORY_MODES = %i[standard constant low].freeze
|
|
59
108
|
|
|
60
|
-
# memory
|
|
61
|
-
# :low write each finished row to disk, so each worksheet
|
|
62
|
-
# top to bottom
|
|
63
|
-
# keeps Excel's shared string table (memory grows with
|
|
64
|
-
# unique strings
|
|
109
|
+
# @param memory [Symbol] :standard keeps every cell in memory until saving.
|
|
110
|
+
# :constant and :low write each finished row to disk, so each worksheet
|
|
111
|
+
# must be filled top to bottom: :constant stores strings inline (memory
|
|
112
|
+
# stays flat), :low keeps Excel's shared string table (memory grows with
|
|
113
|
+
# the number of unique strings).
|
|
114
|
+
# @raise [ArgumentError] for an unknown mode
|
|
65
115
|
def self.new(memory: :standard)
|
|
66
116
|
unless MEMORY_MODES.include?(memory)
|
|
67
117
|
raise ArgumentError, "unknown memory mode #{memory.inspect} (expected one of #{MEMORY_MODES.join(", ")})"
|
|
@@ -70,28 +120,40 @@ module FastXlsx
|
|
|
70
120
|
_new(memory == :constant, memory == :low)
|
|
71
121
|
end
|
|
72
122
|
|
|
123
|
+
# @param name [String, nil] nil takes the first free "SheetN"
|
|
124
|
+
# @return [Worksheet]
|
|
125
|
+
# @raise [FastXlsx::Error] for an invalid name or one already used
|
|
126
|
+
# (names ignore case)
|
|
73
127
|
def add_worksheet(name = nil)
|
|
74
128
|
_add_worksheet(name).tap { |ws| worksheets << ws }
|
|
75
129
|
end
|
|
76
130
|
|
|
77
131
|
# The same Worksheet objects add_worksheet returned, so their append
|
|
78
132
|
# position is shared.
|
|
133
|
+
# @return [Array<Worksheet>]
|
|
79
134
|
def worksheets
|
|
80
135
|
@worksheets ||= []
|
|
81
136
|
end
|
|
82
137
|
|
|
138
|
+
# @param name [String]
|
|
139
|
+
# @return [Worksheet, nil]
|
|
83
140
|
def worksheet(name)
|
|
84
141
|
worksheets.find { |ws| ws.name == name }
|
|
85
142
|
end
|
|
86
143
|
|
|
87
|
-
#
|
|
144
|
+
# Writes the .xlsx file. Runs without Ruby's global lock, like {#to_xlsx}.
|
|
145
|
+
# @param path [String, Pathname, #to_path]
|
|
146
|
+
# @return [nil]
|
|
88
147
|
def save(path)
|
|
89
148
|
_save(File.path(path))
|
|
90
149
|
end
|
|
91
150
|
|
|
92
|
-
# Document properties shown in Excel's File > Info
|
|
93
|
-
#
|
|
94
|
-
#
|
|
151
|
+
# Document properties shown in Excel's File > Info. Later calls add to
|
|
152
|
+
# earlier ones.
|
|
153
|
+
# @param fields [Hash{Symbol => String}] title:, subject:, author:,
|
|
154
|
+
# manager:, company:, category:, keywords:, comments:, status:
|
|
155
|
+
# @return [self]
|
|
156
|
+
# @raise [ArgumentError] for an unknown field
|
|
95
157
|
def properties(**fields)
|
|
96
158
|
merged = (@properties || {}).merge(fields)
|
|
97
159
|
_properties(merged) # validates before anything is remembered
|
|
@@ -100,7 +162,73 @@ module FastXlsx
|
|
|
100
162
|
end
|
|
101
163
|
end
|
|
102
164
|
|
|
103
|
-
# Cell writer for one sheet; create with Workbook#add_worksheet.
|
|
165
|
+
# Cell writer for one sheet; create with {Workbook#add_worksheet}.
|
|
166
|
+
#
|
|
167
|
+
# A cell is (row, col) or a reference like "B2". A range is four 0-based
|
|
168
|
+
# numbers (first_row, first_col, last_row, last_col), a reference like
|
|
169
|
+
# "A1:D10", or rows and columns as Integers or Ranges, e.g. (0..9, 0..3).
|
|
170
|
+
#
|
|
171
|
+
# @!method write(*cell, value, format = nil)
|
|
172
|
+
# Writes one cell.
|
|
173
|
+
# @overload write(row, col, value, format = nil)
|
|
174
|
+
# @overload write(ref, value, format = nil)
|
|
175
|
+
# @param value [Numeric, String, Time, Date, DateTime, true, false, nil,
|
|
176
|
+
# Formula, URL, RichString, #to_s] dates get yyyy-mm-dd (hh:mm:ss) unless
|
|
177
|
+
# the format has a num_format
|
|
178
|
+
# @param format [Format, nil]
|
|
179
|
+
# @return [self]
|
|
180
|
+
#
|
|
181
|
+
# @!method <<(values)
|
|
182
|
+
# Appends a row after the last row written.
|
|
183
|
+
# @param values [Array] cell values, as for {#write}
|
|
184
|
+
# @return [self]
|
|
185
|
+
#
|
|
186
|
+
# @!method concat(rows)
|
|
187
|
+
# Appends several rows.
|
|
188
|
+
# @param rows [Array<Array>]
|
|
189
|
+
# @return [self]
|
|
190
|
+
#
|
|
191
|
+
# @!method next_row
|
|
192
|
+
# @return [Integer] the row {#<<} writes next
|
|
193
|
+
#
|
|
194
|
+
# @!method name
|
|
195
|
+
# @return [String]
|
|
196
|
+
#
|
|
197
|
+
# @!method row_height(row, height)
|
|
198
|
+
# @param height [Numeric] points, 0..409
|
|
199
|
+
# @return [self]
|
|
200
|
+
# @raise [ArgumentError] for a height outside 0..409
|
|
201
|
+
#
|
|
202
|
+
# @!method page_breaks(rows)
|
|
203
|
+
# Starts a printed page before each of these rows.
|
|
204
|
+
# @param rows [Array<Integer>]
|
|
205
|
+
# @return [self]
|
|
206
|
+
#
|
|
207
|
+
# @!method vertical_page_breaks(cols)
|
|
208
|
+
# Starts a printed page before each of these columns.
|
|
209
|
+
# @param cols [Array<Integer>]
|
|
210
|
+
# @return [self]
|
|
211
|
+
#
|
|
212
|
+
# @!method activate
|
|
213
|
+
# Makes Excel open on this sheet (un-hiding it if hidden).
|
|
214
|
+
# @return [self]
|
|
215
|
+
#
|
|
216
|
+
# @!method hide
|
|
217
|
+
# @return [self]
|
|
218
|
+
# @raise [FastXlsx::Error] for the sheet Excel opens on (the first one
|
|
219
|
+
# unless another is activated)
|
|
220
|
+
#
|
|
221
|
+
# @!method zoom(percent)
|
|
222
|
+
# @param percent [Integer, #to_int] 10..400
|
|
223
|
+
# @return [self]
|
|
224
|
+
#
|
|
225
|
+
# @!method tab_color(color)
|
|
226
|
+
# @param color [String, Integer] "#RRGGBB" or 0xRRGGBB
|
|
227
|
+
# @return [self]
|
|
228
|
+
#
|
|
229
|
+
# @!method hide_gridlines
|
|
230
|
+
# Hides the gridlines on screen (see {#page_setup} for printing).
|
|
231
|
+
# @return [self]
|
|
104
232
|
class Worksheet
|
|
105
233
|
# write(row, col, value, format = nil) or write("B2", value, format = nil)
|
|
106
234
|
# is native: the (row, col) form runs once per cell, so it skips a Ruby
|
|
@@ -112,11 +240,18 @@ module FastXlsx
|
|
|
112
240
|
end
|
|
113
241
|
private :_write_ref
|
|
114
242
|
|
|
243
|
+
# Appends a row after the last row written.
|
|
244
|
+
# @param values [Array] cell values, as for {#write}
|
|
245
|
+
# @param format [Format, Array<Format, nil>, nil] one for every cell, or
|
|
246
|
+
# one per cell
|
|
247
|
+
# @return [self]
|
|
115
248
|
def append(values, format: nil)
|
|
116
249
|
_append(values, format)
|
|
117
250
|
end
|
|
118
251
|
|
|
119
|
-
# columns
|
|
252
|
+
# @param columns [Integer, Range<Integer>]
|
|
253
|
+
# @param width [Numeric] characters, 0..255
|
|
254
|
+
# @return [self]
|
|
120
255
|
def column_width(columns, width)
|
|
121
256
|
range = CellRange.bounds(columns)
|
|
122
257
|
_column_width(*range, width)
|
|
@@ -126,89 +261,131 @@ module FastXlsx
|
|
|
126
261
|
self
|
|
127
262
|
end
|
|
128
263
|
|
|
129
|
-
# Sizes columns to the data written so far
|
|
130
|
-
# column_width are kept.
|
|
264
|
+
# Sizes columns to the data written so far (in :constant / :low mode, the
|
|
265
|
+
# rows still in memory). Widths set with {#column_width} are kept.
|
|
266
|
+
# @return [self]
|
|
131
267
|
def autofit
|
|
132
268
|
_autofit
|
|
133
269
|
@fixed_widths&.each { |bounds, width| _column_width(*bounds, width) }
|
|
134
270
|
self
|
|
135
271
|
end
|
|
136
272
|
|
|
137
|
-
# The methods below take a cell range in any of these styles:
|
|
138
|
-
# (first_row, first_col, last_row, last_col) four 0-based numbers
|
|
139
|
-
# ("A1:D10") or ("B2") an Excel reference
|
|
140
|
-
# (rows, cols) Integers or Ranges, e.g. (0..9, 0..3)
|
|
141
|
-
|
|
142
273
|
# Filter buttons on the range's first row.
|
|
274
|
+
# @param range a cell range (see {Worksheet})
|
|
275
|
+
# @return [self]
|
|
143
276
|
def autofilter(*range)
|
|
144
277
|
_autofilter(*CellRange.split(range).first)
|
|
145
278
|
end
|
|
146
279
|
|
|
147
280
|
# Merges the range and writes value (any cell type) into its first cell.
|
|
281
|
+
# @overload merge_range(*range, value, format = nil)
|
|
282
|
+
# @return [self]
|
|
283
|
+
# @raise [FastXlsx::Error] when it overlaps an earlier merge
|
|
148
284
|
def merge_range(*args)
|
|
149
285
|
range, (value, format) = CellRange.split(args, 1..2)
|
|
150
286
|
_merge_range(*range, value, format)
|
|
151
287
|
end
|
|
152
288
|
|
|
153
|
-
# Highlights cells in the range by rule
|
|
154
|
-
#
|
|
289
|
+
# Highlights cells in the range by rule; see the README for each type's
|
|
290
|
+
# options.
|
|
291
|
+
# @param range a cell range (see {Worksheet})
|
|
292
|
+
# @param type [Symbol] :cell, :text, :formula, :data_bar or :color_scale
|
|
293
|
+
# @option options [Symbol] :criteria e.g. :>, :between, :contains
|
|
294
|
+
# @option options [Numeric, String, Array] :value
|
|
295
|
+
# @option options [Format] :format
|
|
296
|
+
# @option options [Integer] :colors 2 or 3 (:color_scale)
|
|
297
|
+
# @return [self]
|
|
155
298
|
def conditional_format(*range, type:, **)
|
|
156
299
|
_conditional_format(*CellRange.split(range).first, { type: type, ** })
|
|
157
300
|
end
|
|
158
301
|
|
|
159
|
-
# Restricts what can be entered in the range
|
|
160
|
-
#
|
|
302
|
+
# Restricts what can be entered in the range; see the README.
|
|
303
|
+
# @param range a cell range (see {Worksheet})
|
|
304
|
+
# @param type [Symbol] :list, :whole_number, :decimal or :text_length
|
|
305
|
+
# @option options [Symbol] :criteria e.g. :>, :between
|
|
306
|
+
# @option options [Numeric, String, Array] :value
|
|
307
|
+
# @option options [String] :input_title, :input_message, :error_title, :error_message
|
|
308
|
+
# @return [self]
|
|
161
309
|
def data_validation(*range, type:, **)
|
|
162
310
|
_data_validation(*CellRange.split(range).first, { type: type, ** })
|
|
163
311
|
end
|
|
164
312
|
|
|
165
|
-
# Adds a comment (Excel "note") to a cell.
|
|
313
|
+
# Adds a comment (an Excel "note") to a cell.
|
|
314
|
+
# @overload write_comment(*cell, text, author: nil)
|
|
315
|
+
# @return [self]
|
|
166
316
|
def write_comment(*args, author: nil)
|
|
167
317
|
row, col, (text, *) = CellRange.cell(args, 1..1)
|
|
168
318
|
_write_comment(row, col, text, author)
|
|
169
319
|
end
|
|
170
320
|
|
|
171
|
-
# Inserts a PNG, JPEG, GIF or BMP image with its top-left corner in the
|
|
172
|
-
# cell
|
|
173
|
-
#
|
|
321
|
+
# Inserts a PNG, JPEG, GIF or BMP image with its top-left corner in the cell.
|
|
322
|
+
# @overload insert_image(*cell, source, **options)
|
|
323
|
+
# @param source [String, #read] a file path or an IO
|
|
324
|
+
# @option options [Numeric] :scale
|
|
325
|
+
# @option options [Numeric] :width, :height pixels (the other keeps the ratio)
|
|
326
|
+
# @option options [Integer] :x_offset, :y_offset pixels
|
|
327
|
+
# @option options [String] :alt_text
|
|
328
|
+
# @return [self]
|
|
329
|
+
# @raise [FastXlsx::Error] for data that isn't a supported image
|
|
174
330
|
def insert_image(*args, **)
|
|
175
331
|
row, col, (source, *) = CellRange.cell(args, 1..1)
|
|
176
332
|
bytes = source.respond_to?(:read) ? source.read : File.binread(source)
|
|
177
333
|
_insert_image(row, col, bytes, { ** })
|
|
178
334
|
end
|
|
179
335
|
|
|
180
|
-
# Inserts a chart with its top-left corner in the cell.
|
|
181
|
-
#
|
|
182
|
-
#
|
|
336
|
+
# Inserts a chart with its top-left corner in the cell.
|
|
337
|
+
# @param cell (row, col) or "B2"
|
|
338
|
+
# @param type [Symbol] :area, :bar, :column, :line, :pie, :doughnut,
|
|
339
|
+
# :radar, :scatter, and the stacked variants
|
|
340
|
+
# @param series [Array<Hash>] { values:, categories:, name: } with ranges
|
|
341
|
+
# such as "Sheet1!$B$2:$B$13"
|
|
342
|
+
# @option options [String] :title, :x_axis, :y_axis
|
|
343
|
+
# @option options [Integer] :width, :height pixels
|
|
344
|
+
# @return [self]
|
|
183
345
|
def insert_chart(*cell, type:, series:, **)
|
|
184
346
|
row, col, = CellRange.cell(cell)
|
|
185
347
|
_insert_chart(row, col, { type: type, series: series, ** })
|
|
186
348
|
end
|
|
187
349
|
|
|
188
350
|
# Turns the range (header row included, total row too when total_row: true)
|
|
189
|
-
# into an Excel table.
|
|
190
|
-
#
|
|
191
|
-
#
|
|
351
|
+
# into an Excel table. Rows appended later under the header fill it.
|
|
352
|
+
# @param range a cell range (see {Worksheet})
|
|
353
|
+
# @option options [Array<String, Hash>] :columns header Strings or
|
|
354
|
+
# { header:, total:, total_label:, format: }
|
|
355
|
+
# @option options [Symbol] :style e.g. :medium2
|
|
356
|
+
# @option options [String] :name
|
|
357
|
+
# @option options [Boolean] :total_row, :banded_rows, :autofilter
|
|
358
|
+
# @return [self]
|
|
192
359
|
def add_table(*range, **)
|
|
193
360
|
_add_table(*CellRange.split(range).first, { ** })
|
|
194
361
|
end
|
|
195
362
|
|
|
196
|
-
# Printed page header
|
|
197
|
-
# margin
|
|
363
|
+
# Printed page header, using Excel codes such as "&CPage &P of &N".
|
|
364
|
+
# @param margin [Numeric, nil] inches
|
|
365
|
+
# @return [self]
|
|
198
366
|
def page_header(text, margin: nil)
|
|
199
367
|
_page_header(text)
|
|
200
368
|
margin ? margins(header: margin) : self
|
|
201
369
|
end
|
|
202
370
|
|
|
371
|
+
# Printed page footer; see {#page_header}.
|
|
372
|
+
# @return [self]
|
|
203
373
|
def page_footer(text, margin: nil)
|
|
204
374
|
_page_footer(text)
|
|
205
375
|
margin ? margins(footer: margin) : self
|
|
206
376
|
end
|
|
207
377
|
|
|
208
|
-
# Printing
|
|
209
|
-
#
|
|
210
|
-
#
|
|
211
|
-
#
|
|
378
|
+
# Printing options.
|
|
379
|
+
# @option options [Boolean] :landscape
|
|
380
|
+
# @option options [Symbol, Integer] :paper :letter, :legal, :tabloid, :a3,
|
|
381
|
+
# :a4, :a5 or Excel's paper number (0: the printer's default)
|
|
382
|
+
# @option options [Integer] :fit_width, :fit_height pages (0 or left out:
|
|
383
|
+
# as many as needed)
|
|
384
|
+
# @param repeat_rows [Integer, Range, nil] printed on every page
|
|
385
|
+
# @param repeat_columns [Integer, Range, nil] printed on every page
|
|
386
|
+
# @param print_area a cell range: "A1:D100" or [first_row, first_col, last_row, last_col]
|
|
387
|
+
# @option options [Boolean] :gridlines print the gridlines
|
|
388
|
+
# @return [self]
|
|
212
389
|
def page_setup(repeat_rows: nil, repeat_columns: nil, print_area: nil, **options)
|
|
213
390
|
options[:repeat_rows] = CellRange.bounds(repeat_rows) if repeat_rows
|
|
214
391
|
options[:repeat_columns] = CellRange.bounds(repeat_columns) if repeat_columns
|
|
@@ -218,39 +395,56 @@ module FastXlsx
|
|
|
218
395
|
end
|
|
219
396
|
|
|
220
397
|
# Print margins in inches; margins not given keep their current value.
|
|
398
|
+
# @return [self]
|
|
399
|
+
# @raise [ArgumentError] for a negative or NaN margin
|
|
221
400
|
def margins(left: nil, right: nil, top: nil, bottom: nil, header: nil, footer: nil)
|
|
222
|
-
_margins(
|
|
401
|
+
_margins(left, right, top, bottom, header, footer)
|
|
223
402
|
self
|
|
224
403
|
end
|
|
225
404
|
|
|
226
|
-
# Outline group with an expand/collapse button. rows
|
|
227
|
-
#
|
|
228
|
-
#
|
|
405
|
+
# Outline group with an expand/collapse button. Grouping rows already
|
|
406
|
+
# grouped nests them (up to 7 levels).
|
|
407
|
+
# @param rows [Integer, Range<Integer>]
|
|
408
|
+
# @param collapsed [Boolean] hidden until expanded
|
|
409
|
+
# @return [self]
|
|
410
|
+
# @raise [FastXlsx::Error] in :constant / :low memory mode, which can't
|
|
411
|
+
# write outline levels for rows
|
|
229
412
|
def group_rows(rows, collapsed: false)
|
|
230
413
|
_group_rows(*CellRange.bounds(rows), collapsed)
|
|
231
414
|
end
|
|
232
415
|
|
|
416
|
+
# Outline group of columns; see {#group_rows}. Works in every memory mode.
|
|
417
|
+
# @param columns [Integer, Range<Integer>]
|
|
418
|
+
# @return [self]
|
|
233
419
|
def group_columns(columns, collapsed: false)
|
|
234
420
|
_group_columns(*CellRange.bounds(columns), collapsed)
|
|
235
421
|
end
|
|
236
422
|
|
|
237
423
|
# Keeps the rows above and the columns left of the cell visible while
|
|
238
424
|
# scrolling: (1, 0) or "A2" freezes the first row.
|
|
425
|
+
# @return [self]
|
|
239
426
|
def freeze_panes(*cell)
|
|
240
427
|
_freeze_panes(*CellRange.cell(cell).first(2))
|
|
241
428
|
self
|
|
242
429
|
end
|
|
243
430
|
|
|
244
431
|
# Locks the sheet against editing. Cells whose format has locked: false
|
|
245
|
-
# stay editable.
|
|
246
|
-
#
|
|
247
|
-
#
|
|
248
|
-
#
|
|
432
|
+
# stay editable. Calling it again replaces the password and actions.
|
|
433
|
+
# @param password [String, nil] stops editing in Excel; it doesn't
|
|
434
|
+
# encrypt the file
|
|
435
|
+
# @param allow [Symbol, Array<Symbol>] actions users may still take:
|
|
436
|
+
# :format_cells, :format_columns, :format_rows, :insert_columns,
|
|
437
|
+
# :insert_rows, :insert_links, :delete_columns, :delete_rows, :sort,
|
|
438
|
+
# :use_autofilter, :use_pivot_tables, :edit_scenarios, :edit_objects
|
|
439
|
+
# @return [self]
|
|
249
440
|
def protect(password: nil, allow: [])
|
|
250
441
|
_protect(password, Array(allow))
|
|
251
442
|
end
|
|
252
443
|
|
|
253
444
|
# Default format for cells in these columns that are written without one.
|
|
445
|
+
# @param columns [Integer, Range<Integer>]
|
|
446
|
+
# @param format [Format]
|
|
447
|
+
# @return [self]
|
|
254
448
|
def column_format(columns, format)
|
|
255
449
|
_column_format(*CellRange.bounds(columns), format)
|
|
256
450
|
self
|
|
@@ -260,6 +454,7 @@ module FastXlsx
|
|
|
260
454
|
# Cell ranges in the styles Worksheet methods accept: four 0-based numbers,
|
|
261
455
|
# an Excel reference ("A1:D10", "B2"), or rows and columns as Integers or
|
|
262
456
|
# Ranges.
|
|
457
|
+
# @api private
|
|
263
458
|
module CellRange
|
|
264
459
|
REF = /\A\$?([A-Za-z]{1,3})\$?([1-9]\d*)\z/ # ASCII only: /i also matches the Kelvin sign
|
|
265
460
|
FORMS = 'a range is (first_row, first_col, last_row, last_col), "A1:D10" or (rows, cols)'
|
|
@@ -279,8 +474,8 @@ module FastXlsx
|
|
|
279
474
|
case args
|
|
280
475
|
in [Numeric, Numeric, Numeric, Numeric, *rest] then [args.first(4), rest]
|
|
281
476
|
in [String => ref, *rest] then [excel(ref), rest]
|
|
282
|
-
in [Integer | Range
|
|
283
|
-
[rows_and_cols(
|
|
477
|
+
in [Integer | Range, Integer | Range, *rest] # (no "=> name" here: YARD can't parse it)
|
|
478
|
+
[rows_and_cols(args[0], args[1]), rest]
|
|
284
479
|
else
|
|
285
480
|
raise ArgumentError, "expected a cell range, got #{args.inspect}; #{FORMS}"
|
|
286
481
|
end
|
|
@@ -351,8 +546,19 @@ module FastXlsx
|
|
|
351
546
|
end
|
|
352
547
|
private_constant :CellRange
|
|
353
548
|
|
|
354
|
-
#
|
|
549
|
+
# A cell style; pass it to {Worksheet#write}, {Worksheet#append} and the
|
|
550
|
+
# other methods that take a format. See the README for every option.
|
|
551
|
+
#
|
|
552
|
+
# @example
|
|
553
|
+
# header = FastXlsx::Format.new(bold: true, bg_color: "#DDEBF7", border_bottom: :thin)
|
|
554
|
+
# money = FastXlsx::Format.new(num_format: "#,##0.00")
|
|
355
555
|
class Format
|
|
556
|
+
# @param options [Hash] bold:, italic:, underline:, strikeout:,
|
|
557
|
+
# font_script:, font_size:, font_name:, font_color:, bg_color:,
|
|
558
|
+
# num_format:, align:, valign:, text_wrap:, rotation:, indent:, shrink:,
|
|
559
|
+
# border:, border_left:, border_right:, border_top:, border_bottom:,
|
|
560
|
+
# border_color:, locked:, hidden:
|
|
561
|
+
# @raise [ArgumentError] for an unknown option or an invalid value
|
|
356
562
|
def self.new(**options)
|
|
357
563
|
# Apply border: first so border_left: etc. override it whatever the order.
|
|
358
564
|
options = { border: options[:border], **options.except(:border) } if options.key?(:border)
|
data/sig/fast_xlsx.rbs
CHANGED
|
@@ -81,7 +81,7 @@ module FastXlsx
|
|
|
81
81
|
def page_footer: (String text, ?margin: Numeric?) -> self
|
|
82
82
|
def activate: () -> self
|
|
83
83
|
def hide: () -> self
|
|
84
|
-
def zoom: (
|
|
84
|
+
def zoom: (int percent) -> self
|
|
85
85
|
def tab_color: (String | Integer color) -> self
|
|
86
86
|
def hide_gridlines: () -> self
|
|
87
87
|
def page_setup: (?landscape: bool, ?paper: :letter | :legal | :tabloid | :a3 | :a4 | :a5 | Integer,
|
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.
|
|
4
|
+
version: 0.5.0
|
|
5
5
|
platform: aarch64-linux
|
|
6
6
|
authors:
|
|
7
7
|
- Zac
|
|
@@ -18,6 +18,7 @@ executables: []
|
|
|
18
18
|
extensions: []
|
|
19
19
|
extra_rdoc_files: []
|
|
20
20
|
files:
|
|
21
|
+
- ".yardopts"
|
|
21
22
|
- CHANGELOG.md
|
|
22
23
|
- LICENSE.txt
|
|
23
24
|
- README.md
|