ironcalc 0.7.1.5-aarch64-linux → 0.9.0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 5177539e077b9d4196fd325f976d094fa9a20751bcb7cb19e726a2a445c92a54
4
- data.tar.gz: 523073235219e2ed26d5b7786f766d98da47bed86c164ed2f21dcf9bdd2c5191
3
+ metadata.gz: 7b80f81c56f14d749ea6119e371a0258dd38382115be8dc472832eabe0d692ae
4
+ data.tar.gz: 99ea756ee63c1c109ffecf1d808c6e4f3af5ce1a3b3c2652dd971affbefe1843
5
5
  SHA512:
6
- metadata.gz: c8f9467254059301c04b07115243b6ac0f18101e3c989ca48fd4e06adaa3acca5a7d5c66ff7ec2082694a5cc065b444b21bd64c42bf4461b669ac3eddb680879
7
- data.tar.gz: 5911ee0ec8bc25830549d7318b6579d801b31af321a2fcc61c240af5f295f2c97a542f52693be0d1c00e5bc6ffc8f3388c1be9ee71afb6575541df2e76be7bf6
6
+ metadata.gz: fd841fbe829ceda5c4ae5ff48a13385e8ae12b78e3bdecc0d02483f141e06ad8c9f98c7b305772ddca9925c6bd22d2f4973a702c6d99c8d18f32c1d08eb86740
7
+ data.tar.gz: d6687d1ff288c153b46015d00158a5d3d030476ccb9d312ffa144d5a68d3a01517dcb75d6118b4dc9411faab985b6be73c25fe525fc460e74f8608537e4f68bc
data/.yardopts CHANGED
@@ -3,6 +3,7 @@
3
3
  --readme README.md
4
4
  --output-dir doc
5
5
  --no-private
6
+ --hide-api private
6
7
  lib/**/*.rb
7
8
  -
8
9
  README.md
data/CHANGELOG.md CHANGED
@@ -1,3 +1,56 @@
1
+ ## 0.9.0.0
2
+
3
+ - update the IronCalc engine to 0.9.0
4
+
5
+ ## 0.8.3.0
6
+
7
+ - update the IronCalc engine to 0.8.3
8
+ - **breaking**: `fill` styles use a single `color` key; `fg_color` and
9
+ `bg_color` are gone
10
+ - **breaking**: the default font is now Inter 12, was Calibri 13
11
+ - **breaking**: `UserModel#update_range_style` takes the engine's area as a
12
+ Hash, `update_range_style({sheet:, row:, column:, width:, height:}, path,
13
+ value)`, and styles the whole range; it took a single cell before
14
+ - **breaking**: every native method has the engine's name and signature, with
15
+ `nil` for an optional parameter and Hashes for engine structs. Renamed:
16
+ - `Model`: `clear_cell_contents(sheet, row, column)` →
17
+ `range_clear_contents(range)`, `get_cell_content` →
18
+ `get_localized_cell_content`, `get_cell_style` → `get_style_for_cell`,
19
+ `set_frozen_rows_count` / `set_frozen_columns_count` → `set_frozen_rows` /
20
+ `set_frozen_columns`, `rename_sheet(sheet, name)` →
21
+ `rename_sheet_by_index`; `rename_sheet(old_name, new_name)` renames by name
22
+ - `UserModel`: `clear_cell_contents(sheet, row, column)` →
23
+ `range_clear_contents(range)`, `set_column_width(sheet, column, width)` →
24
+ `set_columns_width(sheet, column_start, column_end, width)`, and likewise
25
+ `set_rows_height`
26
+ - **breaking**: style Hashes have Symbol keys (`style[:font][:b]`); setters
27
+ accept Symbol or String keys, but no longer a JSON String
28
+ - **breaking**: `UserModel#set_cell_style` is removed; style a `UserModel` per
29
+ property with `update_range_style`. It could not write back a style read with
30
+ `get_cell_style`, and failed part-way through.
31
+ - `set_sheet_color` accepts nil to clear a sheet's color
32
+ - sheet colors read back as nil rather than absent when unset
33
+ - defined names on `Model` and `UserModel`: `defined_names`,
34
+ `new_defined_name`, `update_defined_name`, `delete_defined_name`,
35
+ `is_valid_defined_name` (raises with the reason) and `valid_defined_name?`
36
+ - typed cell setters on `Model`: `update_cell_with_text`, `_number`, `_bool`,
37
+ `_formula`
38
+ - typed cell readers on `Model`: `get_cell_value_by_index`,
39
+ `get_cell_value_by_ref`, `get_cell_formula`, `is_empty_cell`, `get_all_cells`
40
+ - row and column default styles on `Model`: `get`/`set`/`delete_column_style`,
41
+ `get`/`set`/`delete_row_style`, plus `copy_cell_style`
42
+ - `range_clear_all` on both APIs, `range_clear_formatting` on `UserModel`
43
+ - `insert_sheet` and `set_sheet_state` on `Model`
44
+ - `pause_evaluation` / `resume_evaluation` on `UserModel`, and `batch` to
45
+ recalculate once after a block
46
+ - hidden rows and columns: `is_column_hidden` / `is_row_hidden` on both APIs,
47
+ `set_column_hidden` / `set_row_hidden` on `Model`, `set_columns_hidden` /
48
+ `set_rows_hidden` on `UserModel`
49
+ - xlsx in memory: `to_xlsx_bytes` on both APIs, `load_from_xlsx_bytes` and
50
+ `create_user_model_from_xlsx_bytes`
51
+ - fix a memory leak: every constructor leaked its string arguments on each call
52
+ - package only README, CHANGELOG and licenses instead of every `*.md`
53
+
1
54
  ## 0.7.1.5
2
55
 
3
56
  - link to changelog and documentation in gemspec
data/README.md CHANGED
@@ -39,24 +39,166 @@ um.get_formatted_cell_value(0, 1, 1) # => "3"
39
39
  diffs = um.flush_send_queue # binary diff to send to peers
40
40
  ```
41
41
 
42
- Coordinates: `sheet` is a 0-based index; `row` and `column` are 1-based. Styles
43
- are exchanged as plain Ruby hashes via `get_cell_style` / `set_cell_style`.
42
+ Coordinates: `sheet` is a 0-based index; `row` and `column` are 1-based. Method
43
+ names and signatures are the engine's own. Engine structs, such as styles and
44
+ cell ranges, are plain Ruby Hashes keyed by their field names.
44
45
 
45
- ### Top-level methods
46
+ ### API overview
46
47
 
47
- `create`, `load_from_xlsx`, `load_from_icalc`, `load_from_bytes`,
48
- `create_user_model`, `create_user_model_from_xlsx`,
49
- `create_user_model_from_icalc`, `create_user_model_from_bytes`.
48
+ The [API reference](https://jvdp.github.io/IronCalc-Ruby/) documents every method; it shows the latest
49
+ release, and [older versions](https://jvdp.github.io/IronCalc-Ruby/versions.html) are kept too.
50
+
51
+ - [`IronCalc`](https://jvdp.github.io/IronCalc-Ruby/IronCalc.html) — module functions: the constructors (see
52
+ [Loading and saving](#loading-and-saving)) and utilities for cell references,
53
+ such as [`number_to_column`](https://jvdp.github.io/IronCalc-Ruby/IronCalc.html#number_to_column-class_method)
54
+ and [`parse_reference_a1`](https://jvdp.github.io/IronCalc-Ruby/IronCalc.html#parse_reference_a1-class_method).
55
+ - [`IronCalc::UserModel`](https://jvdp.github.io/IronCalc-Ruby/IronCalc/UserModel.html) — the recommended API.
56
+ It recalculates after every change, supports `undo` / `redo`, and records
57
+ diffs for collaboration
58
+ ([`flush_send_queue`](https://jvdp.github.io/IronCalc-Ruby/IronCalc/UserModel.html#flush_send_queue-instance_method)).
59
+ Styles are set per property with
60
+ [`update_range_style`](https://jvdp.github.io/IronCalc-Ruby/IronCalc/UserModel.html#update_range_style-instance_method).
61
+ - [`IronCalc::Model`](https://jvdp.github.io/IronCalc-Ruby/IronCalc/Model.html) — the raw API. You call
62
+ `evaluate` yourself; in return it offers typed cell access, whole-style
63
+ reads and writes, and row and column default styles.
64
+
65
+ ### Typed cell access
66
+
67
+ `set_user_input` parses what you give it, the way typing into a cell does — so
68
+ `"007"` becomes the number 7 and `"=1+1"` becomes a formula. The typed setters
69
+ skip that, and the typed reader gives you a Ruby object instead of a String:
70
+
71
+ ```ruby
72
+ model.update_cell_with_text(0, 1, 1, "007") # stays the string "007"
73
+ model.update_cell_with_number(0, 1, 2, 42.5)
74
+ model.update_cell_with_bool(0, 1, 3, true)
75
+ model.update_cell_with_formula(0, 1, 4, "=B1*2")
76
+ model.evaluate
77
+
78
+ model.get_cell_value_by_index(0, 1, 2) # => 42.5 (Float, not "42.5")
79
+ model.get_cell_value_by_ref("Sheet1!D1") # => 85.0
80
+ model.get_cell_formula(0, 1, 4) # => "=B1*2", or nil if not a formula
81
+ model.is_empty_cell(0, 9, 9) # => true
82
+ model.get_all_cells # => [{ index:, row:, column: }, ...]
83
+ ```
84
+
85
+ `get_all_cells` lists every cell the workbook has a record for (`index` is the
86
+ sheet index, the engine's field name). Clearing a
87
+ cell's contents keeps its record, so filter with `is_empty_cell` if you want
88
+ only cells that still hold a value.
89
+
90
+ Clearing works on a range, given as the engine's `Area`:
91
+
92
+ ```ruby
93
+ b2_c10 = {sheet: 0, row: 2, column: 2, width: 2, height: 9}
94
+ model.range_clear_contents(b2_c10) # keeps the style
95
+ model.range_clear_all(b2_c10) # contents and style
96
+ ```
97
+
98
+ On `UserModel`, `range_clear_formatting` does the opposite — style only.
99
+
100
+ ### Rows, columns and sheets
101
+
102
+ Rows and columns can carry a default style. As with `set_cell_style`, a style is
103
+ a complete structure, so read one, change a field, and pass it back:
104
+
105
+ ```ruby
106
+ style = model.get_style_for_cell(0, 1, 1)
107
+ style[:num_fmt] = "0.00"
108
+ model.set_column_style(0, 2, style)
109
+ model.get_column_style(0, 2) # => Hash, or nil if the column has no style
110
+ model.delete_column_style(0, 2)
111
+
112
+ model.copy_cell_style([0, 1, 1], [0, 5, 5]) # style only, works across sheets
113
+
114
+ model.insert_sheet("Summary", 0, nil) # position, rather than appending
115
+ model.set_sheet_state(1, "hidden") # or "visible" / "veryHidden"
116
+ ```
117
+
118
+ ### Bulk loading
119
+
120
+ `UserModel` recalculates after every action. When writing many cells, suspend
121
+ that and evaluate once:
122
+
123
+ ```ruby
124
+ um.batch do |m|
125
+ rows.each { |r, c, v| m.set_user_input(0, r, c, v) }
126
+ end # recalculated once, here
127
+ ```
128
+
129
+ `batch` nests, and recalculates even if the block raises. The underlying
130
+ `pause_evaluation` / `resume_evaluation` pair is still available if you need to
131
+ manage it yourself.
132
+
133
+ ### Defined names
134
+
135
+ Named ranges, on both APIs. `scope` is a 0-based sheet index, or `nil` for a
136
+ workbook-scoped name. They survive both an xlsx round trip and
137
+ editing in Excel/LibreOffice, so they are also a place to keep your own
138
+ metadata about a sheet.
139
+
140
+ ```ruby
141
+ model.new_defined_name("answer", nil, "Sheet1!$C$1")
142
+ model.set_user_input(0, 1, 1, "=answer")
143
+ model.evaluate
144
+ model.get_formatted_cell_value(0, 1, 1) # => the value of C1
145
+
146
+ model.defined_names
147
+ # => [{ name: "answer", scope: nil, formula: "Sheet1!$C$1" }]
148
+
149
+ model.update_defined_name("answer", nil, "result", nil, "Sheet1!$D$1")
150
+ model.delete_defined_name("result", nil)
151
+ ```
152
+
153
+ `valid_defined_name?(name, scope, formula)` reports whether
154
+ `new_defined_name` would succeed; the name must be an identifier (`"A1"` is
155
+ rejected — it parses as a cell reference), unused in that scope, and the formula
156
+ must parse. `is_valid_defined_name` runs the same check but raises
157
+ `IronCalc::Error` with the reason. On `UserModel` all three mutations are
158
+ undoable.
159
+
160
+ ### Loading and saving
161
+
162
+ | | `Model` | `UserModel` | save with |
163
+ |---|---|---|---|
164
+ | new workbook | `create` | `create_user_model` | |
165
+ | xlsx file | `load_from_xlsx` | `create_user_model_from_xlsx` | `save_to_xlsx` |
166
+ | xlsx in memory | `load_from_xlsx_bytes` | `create_user_model_from_xlsx_bytes` | `to_xlsx_bytes` |
167
+ | icalc file | `load_from_icalc` | `create_user_model_from_icalc` | `save_to_icalc` |
168
+ | icalc in memory | `load_from_bytes` | `create_user_model_from_bytes` | `to_bytes` |
169
+
170
+ icalc is IronCalc's own compact format; use xlsx for anything another
171
+ spreadsheet application should open. The constructors take
172
+ `(name_or_path, locale, tz, language_id)`, except that the bytes variants take
173
+ the bytes first, and the icalc ones need only the language.
174
+
175
+ ### Utilities
176
+
177
+ ```ruby
178
+ IronCalc.number_to_column(28) # => "AB"
179
+ IronCalc.column_to_number("AB") # => 28
180
+ IronCalc.parse_reference_a1("$B3") # => {row: 3, column: 2, absolute_row: false, absolute_column: true}
181
+ IronCalc.quote_name("My Sheet") # => "'My Sheet'"
182
+ ```
183
+
184
+ Also `parse_reference_r1c1`, the `is_valid_*` checks, `get_supported_locales`
185
+ and `get_all_timezones`; see the [`IronCalc` module](https://jvdp.github.io/IronCalc-Ruby/IronCalc.html).
50
186
 
51
187
  Errors raised by the engine surface as `IronCalc::Error`.
52
188
 
53
189
  ## Relationship to the Python bindings
54
190
 
55
191
  `ironcalc-ruby` is a thin binding over the same Rust engine as the
56
- [IronCalc Python bindings](https://github.com/ironcalc/ironcalc/tree/main/bindings/python),
57
- and deliberately mirrors their API. Both are compiled native extensions (Python
58
- via **pyo3**, Ruby via **magnus** / **rb-sys**) exposing a module named
59
- `ironcalc` backed by the IronCalc engine.
192
+ [IronCalc Python bindings](https://github.com/ironcalc/ironcalc/tree/main/bindings/python).
193
+ Both are compiled native extensions (Python via **pyo3**, Ruby via **magnus** /
194
+ **rb-sys**) exposing a module named `ironcalc` backed by the IronCalc engine.
195
+
196
+ Both follow the shape of the engine, so the two APIs line up closely and most
197
+ Python examples translate directly. Where Python renamed an engine method, Ruby
198
+ keeps the engine's name: Python's `clear_cell_contents(sheet, row, column)` is
199
+ `range_clear_contents(range)` here, and `Model.get_cell_style` is
200
+ `get_style_for_cell`. They do not cover the same amount of it —
201
+ see [Coverage compared to the Python bindings](#coverage-compared-to-the-python-bindings).
60
202
 
61
203
  ### What's identical
62
204
 
@@ -67,10 +209,10 @@ via **pyo3**, Ruby via **magnus** / **rb-sys**) exposing a module named
67
209
  `load_from_icalc`, `load_from_bytes`, `create_user_model`,
68
210
  `create_user_model_from_xlsx`, `create_user_model_from_icalc`,
69
211
  `create_user_model_from_bytes`.
70
- - **Method names and signatures** on `Model` / `UserModel` — `set_user_input`,
71
- `get_formatted_cell_value`, `evaluate`, `insert_rows`, `set_column_width`,
72
- `new_sheet`, `save_to_xlsx`, `to_bytes`, … (Python's `snake_case` is also
73
- Ruby's convention, so they match exactly).
212
+ - **Method names and signatures** for everything both take from the engine
213
+ unchanged — `set_user_input`, `get_formatted_cell_value`, `evaluate`,
214
+ `insert_rows`, `set_column_width`, `new_sheet`, `save_to_xlsx`, `to_bytes`, …
215
+ (Python's `snake_case` is also Ruby's convention).
74
216
  - **Coordinates**: `sheet` is a 0-based index; `row` and `column` are 1-based.
75
217
  - **Semantics**: the same engine, so the same inputs produce the same results.
76
218
 
@@ -101,16 +243,57 @@ ports:
101
243
  |---|---|---|
102
244
  | Module access | `ic.create(...)` | `IronCalc.create(...)` |
103
245
  | Error type | `WorkbookError` | `IronCalc::Error` |
104
- | Cell style | typed `Style` / `Font` / … objects | plain `Hash` (`get_cell_style` / `set_cell_style`) |
246
+ | Cell style | typed `Style` / `Font` / … objects | `Hash` with Symbol keys (`get_style_for_cell` / `set_cell_style`) |
105
247
  | Cell type | `CellType` enum | `Symbol` (`:number`, `:text`, …) |
106
248
  | Worksheet properties | list of `SheetProperty` objects | array of `Hash`es (`:name`, `:state`, `:sheet_id`, `:color`) |
107
249
  | Sheet dimensions | tuple `(min_row, max_row, min_col, max_col)` | 4-element `Array` |
250
+ | Engine structs (`Area`, `CellIndex`) | spread into separate arguments | `Hash` keyed by the struct's field names |
251
+ | Engine tuples | tuple | `Array` |
108
252
  | Binary data | `bytes` | binary `String` |
109
253
  | Version | `ironcalc.__version__` | `IronCalc::VERSION` |
110
254
 
111
255
  Rather than reconstruct Python's per-field style classes, Ruby exchanges styles
112
- as plain hashes (serialized as JSON across the boundary). Everything else is kept
113
- as close to the Python bindings as the two languages allow.
256
+ as plain Hashes keyed by the engine's field names. A method that shares a
257
+ name with an engine method takes the engine's parameters in the engine's order,
258
+ with `nil` for an `Option`; conveniences get names of their own. So a range is
259
+ one argument, `update_range_style({sheet: 0, row: 2, column: 2, width: 2,
260
+ height: 9}, "font.b", "true")`, where Python spreads it into start and end
261
+ corners.
262
+
263
+ ### Coverage compared to the Python bindings
264
+
265
+ Both bindings wrap the same engine, so anything both expose behaves the same.
266
+ They do not expose the same amount of it. Counted against **IronCalc 0.9.0**,
267
+ the version this gem tracks, and accurate at the time of writing:
268
+
269
+ | | Python | Ruby |
270
+ |---|---|---|
271
+ | `Model` | 81 | 62 |
272
+ | `UserModel` | 119 | 52 |
273
+
274
+ Most of the difference is deliberate. Selection, scrolling, clipboard and
275
+ keyboard state belong to a UI rather than to a library, and are not exposed
276
+ here. Conditional formatting, named styles, themes, merged cells and
277
+ hyperlinks are a known backlog, listed explicitly in `rake parity`'s
278
+ `ENGINE_DEFERRED` so they stay visible.
279
+
280
+ What Ruby adds is mostly layering rather than extra engine coverage: Hash-based
281
+ styles, `batch`, and xlsx in memory (`to_xlsx_bytes` / `load_from_xlsx_bytes`).
282
+
283
+ These numbers move with every engine release; `rake parity` reports the
284
+ current picture.
285
+
286
+ ## AI-assisted development
287
+
288
+ These bindings are written and maintained with substantial help from
289
+ [Claude Code](https://claude.com/claude-code), Anthropic's coding agent. A
290
+ human maintainer directs the work, reviews every change and makes the releases.
291
+
292
+ Correctness doesn't rest on review alone. The test suite, run in CI on every
293
+ push, re-runs the engine's own formula regression fixtures through the binding.
294
+ `rake parity` checks the API surface and method signatures against the engine
295
+ and the Python bindings. The conventions agents follow here are in
296
+ [AGENTS.md](https://github.com/jvdp/IronCalc-Ruby/blob/main/AGENTS.md).
114
297
 
115
298
  ## License
116
299
 
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -1,81 +1,64 @@
1
- require "json"
2
-
3
- # Ruby-side conveniences layered on top of the native classes. Styles cross the
4
- # native boundary as JSON; here we expose them as plain Ruby hashes, mirroring
5
- # the Node binding's serde-based approach.
1
+ # Ruby-side helpers over the native classes, under names of their own: every
2
+ # method named after an engine method is native and takes the engine's
3
+ # signature.
6
4
  module IronCalc
7
- class Model
8
- # Returns the cell style as a Hash with string keys (snake_case, matching the
9
- # engine's serde field names), e.g.
10
- # { "num_fmt" => "general", "font" => { "b" => false, ... }, ... }
5
+ # Prepended to {Model} and {UserModel}, so these helpers count as part of the
6
+ # class surface.
7
+ module DefinedNames
8
+ # Same as `get_defined_name_list`: defined names as an Array of Hashes with
9
+ # Symbol keys:
10
+ # [{ name: "_key", scope: nil, formula: "Sheet1!$C$1" }, ...]
11
11
  #
12
- # @param sheet [Integer] 0-based sheet index
13
- # @param row [Integer] 1-based row
14
- # @param column [Integer] 1-based column
15
- # @return [Hash]
16
- # @raise [IronCalc::Error]
17
- def get_cell_style(sheet, row, column)
18
- JSON.parse(get_cell_style_json(sheet, row, column))
12
+ # @return [Array<Hash>]
13
+ def defined_names
14
+ get_defined_name_list
19
15
  end
20
16
 
21
- # Sets the cell style from a Hash (snake_case keys) or a JSON string.
17
+ # Whether {#new_defined_name} would succeed for these arguments: the boolean
18
+ # form of `is_valid_defined_name`, which raises with the reason instead.
22
19
  #
23
- # @param sheet [Integer] 0-based sheet index
24
- # @param row [Integer] 1-based row
25
- # @param column [Integer] 1-based column
26
- # @param style [Hash, String] the full style as a Hash or JSON string
27
- # @return [void]
28
- # @raise [IronCalc::Error]
29
- def set_cell_style(sheet, row, column, style)
30
- json = style.is_a?(String) ? style : JSON.generate(style)
31
- set_cell_style_json(sheet, row, column, json)
20
+ # @param name [String]
21
+ # @param scope [Integer, nil] 0-based sheet index, or nil for workbook scope
22
+ # @param formula [String]
23
+ # @return [Boolean]
24
+ def valid_defined_name?(name, scope, formula)
25
+ is_valid_defined_name(name, scope, formula)
26
+ true
27
+ rescue Error
28
+ false
32
29
  end
33
30
  end
34
31
 
35
- class UserModel
36
- # Returns the cell style as a Hash with string keys, like {Model#get_cell_style}.
32
+ # Prepended rather than included, so `batch` counts as part of the class
33
+ # surface.
34
+ module Batch
35
+ # Suspends automatic recalculation, recalculating once when the block exits.
36
+ # Nested calls resume only when the outermost block returns, and the
37
+ # recalculation runs even if the block raises — a resumed model that was
38
+ # never recalculated would report stale values indefinitely.
37
39
  #
38
- # @param sheet [Integer] 0-based sheet index
39
- # @param row [Integer] 1-based row
40
- # @param column [Integer] 1-based column
41
- # @return [Hash]
42
- # @raise [IronCalc::Error]
43
- def get_cell_style(sheet, row, column)
44
- JSON.parse(get_cell_style_json(sheet, row, column))
45
- end
46
-
47
- # Sets the cell style from a Hash (or JSON string). The user model has no
48
- # whole-style setter; styling is per-property via the engine's
49
- # {#update_range_style} (mirroring the WASM binding). This convenience
50
- # flattens the Hash and applies each leaf with {UserModel#update_range_style}.
40
+ # user_model.batch do |m|
41
+ # rows.each { |row, column, value| m.set_user_input(0, row, column, value) }
42
+ # end
51
43
  #
52
- # @param sheet [Integer] 0-based sheet index
53
- # @param row [Integer] 1-based row
54
- # @param column [Integer] 1-based column
55
- # @param style [Hash, String] the style as a Hash or JSON string
56
- # @return [void]
57
- # @raise [IronCalc::Error]
58
- def set_cell_style(sheet, row, column, style)
59
- desired = style.is_a?(String) ? JSON.parse(style) : style
60
- flatten_style(desired).each do |path, value|
61
- update_range_style(sheet, row, column, path, value.to_s)
62
- end
63
- end
64
-
65
- private
66
-
67
- # Flattens a nested style Hash to engine style paths, e.g.
68
- # { "font" => { "b" => true } } => { "font.b" => true }
69
- # @api private
70
- def flatten_style(hash, prefix = nil)
71
- hash.each_with_object({}) do |(key, value), out|
72
- path = prefix ? "#{prefix}.#{key}" : key.to_s
73
- if value.is_a?(Hash)
74
- out.merge!(flatten_style(value, path))
75
- else
76
- out[path] = value
44
+ # @yieldparam model [UserModel] self
45
+ # @return [Object] the block's value
46
+ def batch
47
+ @batch_depth = (@batch_depth || 0) + 1
48
+ pause_evaluation if @batch_depth == 1
49
+ begin
50
+ yield self
51
+ ensure
52
+ @batch_depth -= 1
53
+ if @batch_depth.zero?
54
+ resume_evaluation
55
+ evaluate
77
56
  end
78
57
  end
79
58
  end
80
59
  end
60
+
61
+ Model.prepend(DefinedNames)
62
+ UserModel.prepend(DefinedNames)
63
+ UserModel.prepend(Batch)
81
64
  end
@@ -28,6 +28,18 @@ module IronCalc
28
28
  # @return [IronCalc::Model]
29
29
  # @raise [IronCalc::Error]
30
30
 
31
+ # @!method load_from_xlsx_bytes(bytes, name, locale, tz, language_id)
32
+ # @!scope class
33
+ # Loads a workbook from the bytes of an xlsx file into the raw {Model} API
34
+ # (as produced by {Model#to_xlsx_bytes}).
35
+ # @param bytes [String] binary xlsx bytes
36
+ # @param name [String] workbook name
37
+ # @param locale [String]
38
+ # @param tz [String]
39
+ # @param language_id [String]
40
+ # @return [IronCalc::Model]
41
+ # @raise [IronCalc::Error]
42
+
31
43
  # @!method load_from_icalc(file_name, language_id)
32
44
  # @!scope class
33
45
  # Loads a workbook from the internal binary icalc format.
@@ -64,6 +76,17 @@ module IronCalc
64
76
  # @return [IronCalc::UserModel]
65
77
  # @raise [IronCalc::Error]
66
78
 
79
+ # @!method create_user_model_from_xlsx_bytes(bytes, name, locale, tz, language_id)
80
+ # @!scope class
81
+ # Loads the bytes of an xlsx file into the {UserModel} API.
82
+ # @param bytes [String] binary xlsx bytes
83
+ # @param name [String] workbook name
84
+ # @param locale [String]
85
+ # @param tz [String]
86
+ # @param language_id [String]
87
+ # @return [IronCalc::UserModel]
88
+ # @raise [IronCalc::Error]
89
+
67
90
  # @!method create_user_model_from_icalc(file_name, language_id)
68
91
  # @!scope class
69
92
  # Loads an icalc file into the {UserModel} API.
@@ -80,6 +103,93 @@ module IronCalc
80
103
  # @return [IronCalc::UserModel]
81
104
  # @raise [IronCalc::Error]
82
105
 
106
+ # @!method column_to_number(column)
107
+ # @!scope class
108
+ # Column identifier to 1-based number: +"AA"+ becomes 27.
109
+ # @param column [String] uppercase A-Z letters
110
+ # @return [Integer]
111
+ # @raise [IronCalc::Error] if it is not a valid column identifier
112
+
113
+ # @!method number_to_column(column)
114
+ # @!scope class
115
+ # 1-based number to column identifier: 27 becomes +"AA"+.
116
+ # @param column [Integer]
117
+ # @return [String, nil] nil when outside the sheet's columns
118
+
119
+ # @!method is_valid_column(column)
120
+ # @!scope class
121
+ # Whether +column+ is a column identifier within the sheet, e.g. +"AA"+.
122
+ # @param column [String]
123
+ # @return [Boolean]
124
+
125
+ # @!method is_valid_column_number(column)
126
+ # @!scope class
127
+ # Whether +column+ is a 1-based column number within the sheet.
128
+ # @param column [Integer]
129
+ # @return [Boolean]
130
+
131
+ # @!method is_valid_row(row)
132
+ # @!scope class
133
+ # Whether +row+ is a 1-based row number within the sheet.
134
+ # @param row [Integer]
135
+ # @return [Boolean]
136
+
137
+ # @!method is_valid_identifier(name)
138
+ # Whether +name+ can be a defined name. This is {is_valid_a1_identifier}
139
+ # minus the four single letters +"R"+, +"r"+, +"C"+ and +"c"+, which
140
+ # spreadsheets reserve for R1C1 notation — they stay usable as LAMBDA
141
+ # parameters and LET variables, so the A1 form accepts them.
142
+ #
143
+ # IronCalc.is_valid_identifier("total") # => true
144
+ # IronCalc.is_valid_identifier("R") # => false, the only difference
145
+ # IronCalc.is_valid_identifier("A1") # => false, a cell reference
146
+ #
147
+ # @!scope class
148
+ # @param name [String]
149
+ # @return [Boolean]
150
+
151
+ # @!method is_valid_a1_identifier(name)
152
+ # @!scope class
153
+ # Whether +name+ can be a name in an A1-style formula. Anything that reads
154
+ # as a cell reference is not one.
155
+ #
156
+ # IronCalc.is_valid_a1_identifier("total") # => true
157
+ # IronCalc.is_valid_a1_identifier("R") # => true
158
+ # IronCalc.is_valid_a1_identifier("A1") # => false, a cell reference
159
+ #
160
+ # @param name [String]
161
+ # @return [Boolean]
162
+
163
+ # @!method quote_name(name)
164
+ # @!scope class
165
+ # Quotes a sheet name if a formula reference would need it:
166
+ # +"My Sheet"+ becomes +"'My Sheet'"+, +"Sheet1"+ is returned unchanged.
167
+ # @param name [String]
168
+ # @return [String]
169
+
170
+ # @!method parse_reference_a1(reference)
171
+ # @!scope class
172
+ # Parses A1 notation into +{ row:, column:, absolute_row:, absolute_column: }+,
173
+ # with 1-based coordinates. +"$B$2"+ reports both absolute flags.
174
+ # @param reference [String]
175
+ # @return [Hash, nil] nil if it does not parse
176
+
177
+ # @!method parse_reference_r1c1(reference)
178
+ # @!scope class
179
+ # As {parse_reference_a1}, for R1C1 notation such as +"R2C3"+.
180
+ # @param reference [String]
181
+ # @return [Hash, nil] nil if it does not parse
182
+
183
+ # @!method get_supported_locales
184
+ # @!scope class
185
+ # Locale identifiers accepted by the constructors.
186
+ # @return [Array<String>]
187
+
188
+ # @!method get_all_timezones
189
+ # @!scope class
190
+ # Timezone names accepted by the constructors.
191
+ # @return [Array<String>]
192
+
83
193
  # The raw IronCalc API. You must call {#evaluate} yourself after changing
84
194
  # inputs; misuse can leave the workbook in an inconsistent state. This mirrors
85
195
  # the Python binding's `Model`. For most uses prefer {UserModel}, which
@@ -91,6 +201,11 @@ module IronCalc
91
201
  # @return [void]
92
202
  # @raise [IronCalc::Error]
93
203
 
204
+ # @!method to_xlsx_bytes
205
+ # Serializes the workbook to xlsx bytes (load with {IronCalc.load_from_xlsx_bytes}).
206
+ # @return [String] binary string
207
+ # @raise [IronCalc::Error]
208
+
94
209
  # @!method save_to_icalc(file)
95
210
  # Saves the workbook to the internal binary icalc format.
96
211
  # @param file [String]
@@ -99,6 +214,7 @@ module IronCalc
99
214
 
100
215
  # @!method to_bytes
101
216
  # Serializes the workbook to icalc bytes (load with {IronCalc.load_from_bytes}).
217
+ # This is IronCalc's internal format, not xlsx; see {#to_xlsx_bytes}.
102
218
  # @return [String] binary string
103
219
 
104
220
  # @!method evaluate
@@ -106,7 +222,8 @@ module IronCalc
106
222
  # @return [void]
107
223
 
108
224
  # @!method set_user_input(sheet, row, column, value)
109
- # Sets a cell's raw input (a literal or a formula like "=A1+1").
225
+ # Sets a cell's input, parsed as a user typing it would be: +"3.5"+ is a
226
+ # number, +"Hello"+ a string, +"=A1*2"+ a formula.
110
227
  # @param sheet [Integer]
111
228
  # @param row [Integer]
112
229
  # @param column [Integer]
@@ -114,16 +231,16 @@ module IronCalc
114
231
  # @return [void]
115
232
  # @raise [IronCalc::Error]
116
233
 
117
- # @!method clear_cell_contents(sheet, row, column)
118
- # Clears a cell's contents (not its style).
119
- # @param sheet [Integer]
120
- # @param row [Integer]
121
- # @param column [Integer]
234
+ # @!method range_clear_contents(range)
235
+ # Clears the contents (not the style) of every cell in a range.
236
+ # @param range [Hash] the engine's +Area+: +{sheet:, row:, column:, width:,
237
+ # height:}+
122
238
  # @return [void]
123
239
  # @raise [IronCalc::Error]
124
240
 
125
- # @!method get_cell_content(sheet, row, column)
126
- # Returns the cell's content: the formula (e.g. "=A1+1") or literal text.
241
+ # @!method get_localized_cell_content(sheet, row, column)
242
+ # Returns the cell's content in the model's locale: the formula (e.g.
243
+ # "=A1+1") or literal text.
127
244
  # @param sheet [Integer]
128
245
  # @param row [Integer]
129
246
  # @param column [Integer]
@@ -140,22 +257,89 @@ module IronCalc
140
257
  # @raise [IronCalc::Error]
141
258
 
142
259
  # @!method get_formatted_cell_value(sheet, row, column)
143
- # Returns the cell's value formatted as displayed (number format applied).
260
+ # The cell's value with its number format applied, as displayed — e.g.
261
+ # +"$ 5.75"+.
144
262
  # @param sheet [Integer]
145
263
  # @param row [Integer]
146
264
  # @param column [Integer]
147
265
  # @return [String]
148
266
  # @raise [IronCalc::Error]
149
267
 
150
- # @!method get_cell_style_json(sheet, row, column)
151
- # @api private
152
- # JSON backing for `get_cell_style`. Prefer the Hash-returning wrapper.
153
- # @return [String]
268
+ # @!method get_style_for_cell(sheet, row, column)
269
+ # Returns the cell style as a Hash with Symbol keys, e.g.
270
+ # +{num_fmt: "general", font: {b: false, ...}, ...}+.
271
+ # @param sheet [Integer]
272
+ # @param row [Integer]
273
+ # @param column [Integer]
274
+ # @return [Hash]
275
+ # @raise [IronCalc::Error]
154
276
 
155
- # @!method set_cell_style_json(sheet, row, column, style_json)
156
- # @api private
157
- # JSON backing for `set_cell_style`. Prefer the Hash-accepting wrapper.
277
+ # @!method set_cell_style(sheet, row, column, style)
278
+ # Sets the cell style. Takes a *complete* style, as returned by
279
+ # {#get_style_for_cell}: read one, change it, pass it back. Keys may be
280
+ # Symbols or Strings.
281
+ # @param sheet [Integer]
282
+ # @param row [Integer]
283
+ # @param column [Integer]
284
+ # @param style [Hash]
158
285
  # @return [void]
286
+ # @raise [IronCalc::Error] also if the style is incomplete
287
+
288
+ # @!method get_column_style(sheet, column)
289
+ # The default style for a whole column, as a Hash, or nil if the column
290
+ # carries no style of its own.
291
+ # @param sheet [Integer]
292
+ # @param column [Integer]
293
+ # @return [Hash, nil]
294
+ # @raise [IronCalc::Error]
295
+
296
+ # @!method get_row_style(sheet, row)
297
+ # The default style for a whole row, as a Hash, or nil if the sheet holds
298
+ # no record for that row. A row whose style was deleted reads back as the
299
+ # default style rather than nil; the column equivalent returns nil.
300
+ # @param sheet [Integer]
301
+ # @param row [Integer]
302
+ # @return [Hash, nil]
303
+ # @raise [IronCalc::Error]
304
+
305
+ # @!method set_column_style(sheet, column, style)
306
+ # Sets the default style for a whole column. Takes a complete style, as
307
+ # {#set_cell_style} does.
308
+ # @param sheet [Integer]
309
+ # @param column [Integer]
310
+ # @param style [Hash]
311
+ # @return [void]
312
+ # @raise [IronCalc::Error]
313
+
314
+ # @!method set_row_style(sheet, row, style)
315
+ # Sets the default style for a whole row. Takes a complete style, as
316
+ # {#set_cell_style} does.
317
+ # @param sheet [Integer]
318
+ # @param row [Integer]
319
+ # @param style [Hash]
320
+ # @return [void]
321
+ # @raise [IronCalc::Error]
322
+
323
+ # @!method copy_cell_style(source_cell, destination_cell)
324
+ # Copies one cell's style (and nothing else) onto another cell, in any sheet.
325
+ # @param source_cell [Array(Integer, Integer, Integer)] +[sheet, row, column]+
326
+ # @param destination_cell [Array(Integer, Integer, Integer)] +[sheet, row, column]+
327
+ # @return [void]
328
+ # @raise [IronCalc::Error]
329
+
330
+ # @!method delete_column_style(sheet, column)
331
+ # Removes a column's default style.
332
+ # @param sheet [Integer]
333
+ # @param column [Integer]
334
+ # @return [void]
335
+ # @raise [IronCalc::Error]
336
+
337
+ # @!method delete_row_style(sheet, row)
338
+ # Removes a row's default style.
339
+ # @param sheet [Integer]
340
+ # @param row [Integer]
341
+ # @return [void]
342
+ # @raise [IronCalc::Error]
159
343
 
160
344
  # @!method insert_rows(sheet, row, row_count)
161
345
  # Inserts +row_count+ rows before +row+.
@@ -215,6 +399,32 @@ module IronCalc
215
399
  # @return [void]
216
400
  # @raise [IronCalc::Error]
217
401
 
402
+ # @!method is_column_hidden(sheet, column)
403
+ # @param sheet [Integer]
404
+ # @param column [Integer]
405
+ # @return [Boolean]
406
+ # @raise [IronCalc::Error]
407
+
408
+ # @!method set_column_hidden(sheet, column, hidden)
409
+ # @param sheet [Integer]
410
+ # @param column [Integer]
411
+ # @param hidden [Boolean]
412
+ # @return [void]
413
+ # @raise [IronCalc::Error]
414
+
415
+ # @!method is_row_hidden(sheet, row)
416
+ # @param sheet [Integer]
417
+ # @param row [Integer]
418
+ # @return [Boolean]
419
+ # @raise [IronCalc::Error]
420
+
421
+ # @!method set_row_hidden(sheet, row, hidden)
422
+ # @param sheet [Integer]
423
+ # @param row [Integer]
424
+ # @param hidden [Boolean]
425
+ # @return [void]
426
+ # @raise [IronCalc::Error]
427
+
218
428
  # @!method get_frozen_columns_count(sheet)
219
429
  # @param sheet [Integer]
220
430
  # @return [Integer]
@@ -225,15 +435,15 @@ module IronCalc
225
435
  # @return [Integer]
226
436
  # @raise [IronCalc::Error]
227
437
 
228
- # @!method set_frozen_columns_count(sheet, count)
438
+ # @!method set_frozen_columns(sheet, frozen_columns)
229
439
  # @param sheet [Integer]
230
- # @param count [Integer]
440
+ # @param frozen_columns [Integer]
231
441
  # @return [void]
232
442
  # @raise [IronCalc::Error]
233
443
 
234
- # @!method set_frozen_rows_count(sheet, count)
444
+ # @!method set_frozen_rows(sheet, frozen_rows)
235
445
  # @param sheet [Integer]
236
- # @param count [Integer]
446
+ # @param frozen_rows [Integer]
237
447
  # @return [void]
238
448
  # @raise [IronCalc::Error]
239
449
 
@@ -243,8 +453,10 @@ module IronCalc
243
453
  # @return [Array<Hash>]
244
454
 
245
455
  # @!method set_sheet_color(sheet, color)
456
+ # Sets the sheet tab color.
246
457
  # @param sheet [Integer]
247
- # @param color [String] hex color, e.g. "#FF0000"
458
+ # @param color [String, Array, nil] +"#RRGGBB"+, a +[theme, tint]+ pair,
459
+ # or nil to clear
248
460
  # @return [void]
249
461
  # @raise [IronCalc::Error]
250
462
 
@@ -263,8 +475,15 @@ module IronCalc
263
475
  # @return [void]
264
476
  # @raise [IronCalc::Error]
265
477
 
266
- # @!method rename_sheet(sheet, new_name)
267
- # @param sheet [Integer]
478
+ # @!method rename_sheet(old_name, new_name)
479
+ # Renames the sheet called +old_name+.
480
+ # @param old_name [String]
481
+ # @param new_name [String]
482
+ # @return [void]
483
+ # @raise [IronCalc::Error]
484
+
485
+ # @!method rename_sheet_by_index(sheet_index, new_name)
486
+ # @param sheet_index [Integer]
268
487
  # @param new_name [String]
269
488
  # @return [void]
270
489
  # @raise [IronCalc::Error]
@@ -277,17 +496,150 @@ module IronCalc
277
496
  # @raise [IronCalc::Error]
278
497
 
279
498
  # Without a real def, the @!method stubs above leak to the IronCalc module
499
+ # @!method get_defined_name_list
500
+ # Defined names as one Hash per name, with symbol keys +:name+, +:scope+
501
+ # (0-based sheet index, or nil for workbook scope) and +:formula+.
502
+ # Also available as {DefinedNames#defined_names}.
503
+ # @return [Array<Hash>]
504
+
505
+ # @!method new_defined_name(name, scope, formula)
506
+ # Adds a defined name. Fails if the name is not a valid identifier (+"A1"+
507
+ # is not: it parses as a cell reference), if it is already taken in that
508
+ # scope, or if the formula does not parse.
509
+ # @param name [String]
510
+ # @param scope [Integer, nil] 0-based sheet index, or nil for workbook scope
511
+ # @param formula [String] e.g. +"Sheet1!$C$1"+
512
+ # @return [void]
513
+ # @raise [IronCalc::Error]
514
+
515
+ # @!method update_defined_name(name, scope, new_name, new_scope, new_formula)
516
+ # Renames, re-scopes and/or repoints an existing defined name.
517
+ # @param name [String] the current name
518
+ # @param scope [Integer, nil] the current scope
519
+ # @param new_name [String]
520
+ # @param new_scope [Integer, nil]
521
+ # @param new_formula [String]
522
+ # @return [void]
523
+ # @raise [IronCalc::Error]
524
+
525
+ # @!method delete_defined_name(name, scope)
526
+ # Deletes a defined name. Fails if no name matches in that scope.
527
+ # @param name [String]
528
+ # @param scope [Integer, nil]
529
+ # @return [void]
530
+ # @raise [IronCalc::Error]
531
+
532
+ # @!method is_valid_defined_name(name, scope, formula)
533
+ # Checks whether {#new_defined_name} would succeed for these arguments,
534
+ # raising with the reason if not. {DefinedNames#valid_defined_name?}
535
+ # answers the same question as a boolean.
536
+ # @param name [String]
537
+ # @param scope [Integer, nil]
538
+ # @param formula [String]
539
+ # @return [Integer, nil] the +sheet_id+ of the scope's sheet (as in
540
+ # +get_worksheets_properties+), or nil for workbook scope
541
+ # @raise [IronCalc::Error] with the reason, e.g. the name is already taken
542
+ # in that scope
543
+
544
+ # @!method range_clear_all(area)
545
+ # Clears the contents *and* style of every cell in a range, removing the
546
+ # cells entirely. Compare +range_clear_contents+, which keeps the style.
547
+ # @param area [Hash] the engine's +Area+: +{sheet:, row:, column:, width:,
548
+ # height:}+
549
+ # @return [void]
550
+ # @raise [IronCalc::Error]
551
+
552
+ # @!method update_cell_with_text(sheet, row, column, value)
553
+ # Stores +value+ as text without parsing it, so +"007"+ stays +"007"+ and
554
+ # +"=1+1"+ stays a string. Compare +set_user_input+, which parses.
555
+ # @param value [String]
556
+ # @return [void]
557
+ # @raise [IronCalc::Error]
558
+
559
+ # @!method update_cell_with_number(sheet, row, column, value)
560
+ # Sets a number without input parsing.
561
+ # @param value [Float]
562
+ # @return [void]
563
+ # @raise [IronCalc::Error]
564
+
565
+ # @!method update_cell_with_bool(sheet, row, column, value)
566
+ # Sets a boolean without input parsing.
567
+ # @param value [Boolean]
568
+ # @return [void]
569
+ # @raise [IronCalc::Error]
570
+
571
+ # @!method update_cell_with_formula(sheet, row, column, formula)
572
+ # Stores a formula directly. Call +evaluate+ afterwards.
573
+ # @param formula [String] including the leading +=+
574
+ # @return [void]
575
+ # @raise [IronCalc::Error]
576
+
577
+ # @!method get_cell_value_by_index(sheet, row, column)
578
+ # The cell's value as a Ruby object — nil, String, Float or true/false —
579
+ # unformatted. Compare +get_formatted_cell_value+, which always returns a
580
+ # String, and +get_localized_cell_content+, which returns what the user typed.
581
+ #
582
+ # The engine has no error variant here, so an error cell comes back as the
583
+ # String +"#DIV/0!"+ and is indistinguishable from that literal text. Use
584
+ # +get_cell_type+, which reports +:error_value+, to tell them apart.
585
+ # @return [nil, String, Float, Boolean]
586
+ # @raise [IronCalc::Error]
587
+
588
+ # @!method get_cell_value_by_ref(cell_ref)
589
+ # Like +get_cell_value_by_index+, addressed by an A1-style reference that
590
+ # includes the sheet, e.g. +"Sheet1!C4"+.
591
+ # @param cell_ref [String]
592
+ # @return [nil, String, Float, Boolean]
593
+ # @raise [IronCalc::Error]
594
+
595
+ # @!method get_cell_formula(sheet, row, column)
596
+ # The cell's formula including the leading +=+, or nil if it is not a
597
+ # formula cell.
598
+ # @return [String, nil]
599
+ # @raise [IronCalc::Error]
600
+
601
+ # @!method is_empty_cell(sheet, row, column)
602
+ # Whether the cell holds no content.
603
+ # @return [Boolean]
604
+ # @raise [IronCalc::Error]
605
+
606
+ # @!method get_all_cells
607
+ # Every cell the workbook holds a record for, as +{ index:, row:, column: }+
608
+ # hashes (+index+ is the 0-based sheet index), ordered by sheet, then row,
609
+ # then column. A cell emptied with +range_clear_contents+ keeps its record
610
+ # and is still listed; combine with +is_empty_cell+ if you only want cells
611
+ # that have a value.
612
+ # @return [Array<Hash>]
613
+
614
+ # @!method insert_sheet(sheet_name, sheet_index, sheet_id)
615
+ # Adds a sheet at +sheet_index+ rather than appending it.
616
+ # @param sheet_name [String]
617
+ # @param sheet_index [Integer] 0-based position to insert at
618
+ # @param sheet_id [Integer, nil] normally nil, so the engine allocates one
619
+ # @return [void]
620
+ # @raise [IronCalc::Error] also if +sheet_id+ is already in use, which the
621
+ # engine itself does not check
622
+
623
+ # @!method set_sheet_state(sheet, state)
624
+ # Sets a sheet's visibility. Matches the +:state+ value reported by
625
+ # +get_worksheets_properties+.
626
+ # @param sheet [Integer]
627
+ # @param state [String] +"visible"+, +"hidden"+ or +"veryHidden"+
628
+ # (+"very_hidden"+ is also accepted)
629
+ # @return [void]
630
+ # @raise [IronCalc::Error]
631
+
280
632
  # (yardoc bug lsegal/yard#1207). Doc-only file, never loaded at runtime.
281
633
  # @!visibility private
282
- def __yard_anchor__; end
634
+ def __yard_anchor__
635
+ end
283
636
  end
284
637
 
285
638
  # The recommended, higher-level IronCalc API. Auto-evaluates after every action
286
639
  # and records diffs for collaboration ({#flush_send_queue} /
287
640
  # {#apply_external_diffs}). Mirrors IronCalc's WebAssembly binding and is a
288
641
  # superset of the Python binding's `UserModel`. Styling is per-property via
289
- # {UserModel#update_range_style} (the Hash convenience {UserModel#set_cell_style}
290
- # is layered on top).
642
+ # {UserModel#update_range_style}.
291
643
  class UserModel
292
644
  # @!method save_to_xlsx(file)
293
645
  # Saves the workbook to an xlsx file. Fails if the file already exists.
@@ -295,6 +647,12 @@ module IronCalc
295
647
  # @return [void]
296
648
  # @raise [IronCalc::Error]
297
649
 
650
+ # @!method to_xlsx_bytes
651
+ # Serializes the workbook to xlsx bytes (load with
652
+ # {IronCalc.create_user_model_from_xlsx_bytes}).
653
+ # @return [String] binary string
654
+ # @raise [IronCalc::Error]
655
+
298
656
  # @!method save_to_icalc(file)
299
657
  # Saves the workbook to the internal binary icalc format.
300
658
  # @param file [String]
@@ -303,6 +661,7 @@ module IronCalc
303
661
 
304
662
  # @!method to_bytes
305
663
  # Serializes the workbook to icalc bytes.
664
+ # This is IronCalc's internal format, not xlsx; see {#to_xlsx_bytes}.
306
665
  # @return [String] binary string
307
666
 
308
667
  # @!method apply_external_diffs(diffs)
@@ -337,7 +696,8 @@ module IronCalc
337
696
  # @return [Boolean]
338
697
 
339
698
  # @!method set_user_input(sheet, row, column, value)
340
- # Sets a cell's raw input (literal or formula). Triggers recalculation.
699
+ # Sets a cell's input, parsed as a user typing it would be: +"3.5"+ is a
700
+ # number, +"Hello"+ a string, +"=A1*2"+ a formula. Triggers recalculation.
341
701
  # @param sheet [Integer]
342
702
  # @param row [Integer]
343
703
  # @param column [Integer]
@@ -345,11 +705,10 @@ module IronCalc
345
705
  # @return [void]
346
706
  # @raise [IronCalc::Error]
347
707
 
348
- # @!method clear_cell_contents(sheet, row, column)
349
- # Clears a cell's contents (not its style).
350
- # @param sheet [Integer]
351
- # @param row [Integer]
352
- # @param column [Integer]
708
+ # @!method range_clear_contents(range)
709
+ # Clears the contents (not the style) of every cell in a range. Undoable.
710
+ # @param range [Hash] the engine's +Area+: +{sheet:, row:, column:, width:,
711
+ # height:}+
353
712
  # @return [void]
354
713
  # @raise [IronCalc::Error]
355
714
 
@@ -370,29 +729,34 @@ module IronCalc
370
729
  # @raise [IronCalc::Error]
371
730
 
372
731
  # @!method get_formatted_cell_value(sheet, row, column)
373
- # Returns the cell's value formatted as displayed.
732
+ # The cell's value with its number format applied, as displayed — e.g.
733
+ # +"$ 5.75"+.
374
734
  # @param sheet [Integer]
375
735
  # @param row [Integer]
376
736
  # @param column [Integer]
377
737
  # @return [String]
378
738
  # @raise [IronCalc::Error]
379
739
 
380
- # @!method get_cell_style_json(sheet, row, column)
381
- # @api private
382
- # JSON backing for `get_cell_style`. Prefer the Hash-returning wrapper.
383
- # @return [String]
384
-
385
- # @!method update_range_style(sheet, row, column, style_path, value)
386
- # Sets a single style property on a cell, e.g. +update_range_style(0, 1, 1,
387
- # "font.b", "true")+. This is the user model's styling primitive (mirrors
388
- # the WASM binding); `set_cell_style` wraps it for whole-Hash convenience.
740
+ # @!method get_cell_style(sheet, row, column)
741
+ # Returns the cell style as a Hash with Symbol keys, like
742
+ # {Model#get_style_for_cell}.
389
743
  # @param sheet [Integer]
390
744
  # @param row [Integer]
391
745
  # @param column [Integer]
392
- # @param style_path [String] dotted path, e.g. "font.b", "fill.fg_color"
746
+ # @return [Hash]
747
+ # @raise [IronCalc::Error]
748
+
749
+ # @!method update_range_style(range, style_path, value)
750
+ # Sets a single style property on every cell of a range, e.g. bold for
751
+ # B2:C10: +update_range_style({sheet: 0, row: 2, column: 2, width: 2,
752
+ # height: 9}, "font.b", "true")+. This is the user model's styling
753
+ # primitive: the engine's UserModel has no whole-style setter.
754
+ # @param range [Hash] the engine's +Area+: +{sheet:, row:, column:, width:,
755
+ # height:}+
756
+ # @param style_path [String] dotted path, e.g. "font.b", "fill.color"
393
757
  # @param value [String]
394
758
  # @return [void]
395
- # @raise [IronCalc::Error]
759
+ # @raise [IronCalc::Error] also if +range+ is missing a key
396
760
 
397
761
  # @!method insert_rows(sheet, row, row_count)
398
762
  # @param sheet [Integer]
@@ -434,20 +798,54 @@ module IronCalc
434
798
  # @return [Float] height in pixels
435
799
  # @raise [IronCalc::Error]
436
800
 
437
- # @!method set_column_width(sheet, column, width)
801
+ # @!method set_columns_width(sheet, column_start, column_end, width)
802
+ # Sets the width of columns +column_start+ to +column_end+, inclusive.
438
803
  # @param sheet [Integer]
439
- # @param column [Integer]
804
+ # @param column_start [Integer]
805
+ # @param column_end [Integer]
440
806
  # @param width [Float]
441
807
  # @return [void]
442
808
  # @raise [IronCalc::Error]
443
809
 
444
- # @!method set_row_height(sheet, row, height)
810
+ # @!method set_rows_height(sheet, row_start, row_end, height)
811
+ # Sets the height of rows +row_start+ to +row_end+, inclusive.
445
812
  # @param sheet [Integer]
446
- # @param row [Integer]
813
+ # @param row_start [Integer]
814
+ # @param row_end [Integer]
447
815
  # @param height [Float]
448
816
  # @return [void]
449
817
  # @raise [IronCalc::Error]
450
818
 
819
+ # @!method is_column_hidden(sheet, column)
820
+ # @param sheet [Integer]
821
+ # @param column [Integer]
822
+ # @return [Boolean]
823
+ # @raise [IronCalc::Error]
824
+
825
+ # @!method set_columns_hidden(sheet, column_start, column_end, hidden)
826
+ # Hides or shows columns +column_start+ to +column_end+, inclusive. Undoable.
827
+ # @param sheet [Integer]
828
+ # @param column_start [Integer]
829
+ # @param column_end [Integer]
830
+ # @param hidden [Boolean]
831
+ # @return [void]
832
+ # @raise [IronCalc::Error]
833
+
834
+ # @!method is_row_hidden(sheet, row)
835
+ # @param sheet [Integer]
836
+ # @param row [Integer]
837
+ # @return [Boolean]
838
+ # @raise [IronCalc::Error]
839
+
840
+ # @!method set_rows_hidden(sheet, row_start, row_end, hidden)
841
+ # Hides or shows rows +row_start+ to +row_end+, inclusive. Undoable.
842
+ # @param sheet [Integer]
843
+ # @param row_start [Integer]
844
+ # @param row_end [Integer]
845
+ # @param hidden [Boolean]
846
+ # @return [void]
847
+ # @raise [IronCalc::Error]
848
+
451
849
  # @!method get_frozen_columns_count(sheet)
452
850
  # @param sheet [Integer]
453
851
  # @return [Integer]
@@ -476,8 +874,10 @@ module IronCalc
476
874
  # @return [Array<Hash>]
477
875
 
478
876
  # @!method set_sheet_color(sheet, color)
877
+ # Sets the sheet tab color.
479
878
  # @param sheet [Integer]
480
- # @param color [String] hex color, e.g. "#FF0000"
879
+ # @param color [String, Array, nil] +"#RRGGBB"+, a +[theme, tint]+ pair,
880
+ # or nil to clear
481
881
  # @return [void]
482
882
  # @raise [IronCalc::Error]
483
883
 
@@ -503,8 +903,79 @@ module IronCalc
503
903
  # @return [Array(Integer, Integer, Integer, Integer)]
504
904
  # @raise [IronCalc::Error]
505
905
 
906
+ # @!method get_defined_name_list
907
+ # Defined names as one Hash per name, with symbol keys +:name+, +:scope+
908
+ # (0-based sheet index, or nil for workbook scope) and +:formula+.
909
+ # Also available as {DefinedNames#defined_names}.
910
+ # @return [Array<Hash>]
911
+
912
+ # @!method new_defined_name(name, scope, formula)
913
+ # Adds a defined name. Fails if the name is not a valid identifier (+"A1"+
914
+ # is not: it parses as a cell reference), if it is already taken in that
915
+ # scope, or if the formula does not parse.
916
+ # @param name [String]
917
+ # @param scope [Integer, nil] 0-based sheet index, or nil for workbook scope
918
+ # @param formula [String] e.g. +"Sheet1!$C$1"+
919
+ # @return [void]
920
+ # @raise [IronCalc::Error]
921
+
922
+ # @!method update_defined_name(name, scope, new_name, new_scope, new_formula)
923
+ # Renames, re-scopes and/or repoints an existing defined name.
924
+ # @param name [String] the current name
925
+ # @param scope [Integer, nil] the current scope
926
+ # @param new_name [String]
927
+ # @param new_scope [Integer, nil]
928
+ # @param new_formula [String]
929
+ # @return [void]
930
+ # @raise [IronCalc::Error]
931
+
932
+ # @!method delete_defined_name(name, scope)
933
+ # Deletes a defined name. Fails if no name matches in that scope.
934
+ # @param name [String]
935
+ # @param scope [Integer, nil]
936
+ # @return [void]
937
+ # @raise [IronCalc::Error]
938
+
939
+ # @!method is_valid_defined_name(name, scope, formula)
940
+ # Checks whether {#new_defined_name} would succeed for these arguments,
941
+ # raising with the reason if not. {DefinedNames#valid_defined_name?}
942
+ # answers the same question as a boolean.
943
+ # @param name [String]
944
+ # @param scope [Integer, nil]
945
+ # @param formula [String]
946
+ # @return [Integer, nil] the +sheet_id+ of the scope's sheet (as in
947
+ # +get_worksheets_properties+), or nil for workbook scope
948
+ # @raise [IronCalc::Error] with the reason, e.g. the name is already taken
949
+ # in that scope
950
+
951
+ # @!method range_clear_all(range)
952
+ # Clears the contents *and* style of every cell in a range. Undoable.
953
+ # @param range [Hash] the engine's +Area+: +{sheet:, row:, column:, width:,
954
+ # height:}+
955
+ # @return [void]
956
+ # @raise [IronCalc::Error]
957
+
958
+ # @!method range_clear_formatting(range)
959
+ # Clears the style of every cell in a range, keeping the contents. Undoable.
960
+ # @param range [Hash] the engine's +Area+: +{sheet:, row:, column:, width:,
961
+ # height:}+
962
+ # @return [void]
963
+ # @raise [IronCalc::Error]
964
+
965
+ # @!method pause_evaluation
966
+ # Suspends the automatic recalculation this API does after every action —
967
+ # useful when writing many cells at once. While paused, formula cells read
968
+ # back as +#ERROR!+ until evaluated.
969
+ # @return [void]
970
+
971
+ # @!method resume_evaluation
972
+ # Re-enables automatic recalculation. Does not recalculate by itself; call
973
+ # +evaluate+ afterwards to bring the workbook up to date.
974
+ # @return [void]
975
+
506
976
  # Anchors the @!method stubs above — see {Model}.
507
977
  # @!visibility private
508
- def __yard_anchor__; end
978
+ def __yard_anchor__
979
+ end
509
980
  end
510
981
  end
@@ -1,3 +1,3 @@
1
1
  module IronCalc
2
- VERSION = "0.7.1.5"
2
+ VERSION = "0.9.0.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ironcalc
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.1.5
4
+ version: 0.9.0.0
5
5
  platform: aarch64-linux
6
6
  authors:
7
7
  - jvdp
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2026-06-17 00:00:00.000000000 Z
11
+ date: 2026-10-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |
14
14
  Ruby bindings for the IronCalc spreadsheet engine. Create, read and
@@ -34,15 +34,16 @@ files:
34
34
  - lib/ironcalc/model.rb
35
35
  - lib/ironcalc/native_methods.rb
36
36
  - lib/ironcalc/version.rb
37
- homepage: https://github.com/jvdp/IronCalc-Ruby
37
+ homepage: https://www.ironcalc.com/
38
38
  licenses:
39
- - MIT OR Apache-2.0
39
+ - MIT
40
+ - Apache-2.0
40
41
  metadata:
41
- homepage_uri: https://www.ironcalc.com/
42
42
  source_code_uri: https://github.com/jvdp/IronCalc-Ruby
43
43
  bug_tracker_uri: https://github.com/jvdp/IronCalc-Ruby/issues
44
- changelog_uri: https://raw.githubusercontent.com/jvdp/IronCalc-Ruby/refs/heads/main/CHANGELOG.md
45
- documentation_uri: https://www.rubydoc.info/gems/ironcalc/
44
+ changelog_uri: https://github.com/jvdp/IronCalc-Ruby/blob/main/CHANGELOG.md
45
+ documentation_uri: https://jvdp.github.io/IronCalc-Ruby/0.9.0/
46
+ rubygems_mfa_required: 'true'
46
47
  post_install_message:
47
48
  rdoc_options: []
48
49
  require_paths: