ironcalc 0.7.1.5 → 0.8.3.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 +4 -4
- data/.yardopts +1 -0
- data/CHANGELOG.md +49 -0
- data/Cargo.lock +31 -6
- data/README.md +199 -17
- data/ext/ironcalc/Cargo.toml +2 -2
- data/ext/ironcalc/src/lib.rs +227 -156
- data/ext/ironcalc/src/model.rs +443 -36
- data/ext/ironcalc/src/user_model.rs +163 -52
- data/lib/ironcalc/model.rb +49 -66
- data/lib/ironcalc/native_methods.rb +521 -50
- data/lib/ironcalc/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 99ad95c481d32e19c1ac19db71a37fac4b4c0239911d28909ba4e55aa1e3e28b
|
|
4
|
+
data.tar.gz: 3ee57b654e4633a521ef5e0f0e323437150d5a4c4663497c4a244b877f8e278d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ba91db3f951436ec7434c4f6439c216fbb6bd876dbb32ba1f30aa5dbd14d8be2503c955c98861b9a8cd9ecde2d98b744d60973ef7ce3fa180595a266a3dcbe5d
|
|
7
|
+
data.tar.gz: 13353e79cfac4675511ec1fd1bb1bb20912344ef5d1b8d395422b4012ae54d7f6daa4266c98251e3c2cf94c87be384535e0a0e26c303c6db99129cf22ef5b511
|
data/.yardopts
CHANGED
data/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,52 @@
|
|
|
1
|
+
## 0.8.3.0
|
|
2
|
+
|
|
3
|
+
- update the IronCalc engine to 0.8.3
|
|
4
|
+
- **breaking**: `fill` styles use a single `color` key; `fg_color` and
|
|
5
|
+
`bg_color` are gone
|
|
6
|
+
- **breaking**: the default font is now Inter 12, was Calibri 13
|
|
7
|
+
- **breaking**: `UserModel#update_range_style` takes the engine's area as a
|
|
8
|
+
Hash, `update_range_style({sheet:, row:, column:, width:, height:}, path,
|
|
9
|
+
value)`, and styles the whole range; it took a single cell before
|
|
10
|
+
- **breaking**: every native method has the engine's name and signature, with
|
|
11
|
+
`nil` for an optional parameter and Hashes for engine structs. Renamed:
|
|
12
|
+
- `Model`: `clear_cell_contents(sheet, row, column)` →
|
|
13
|
+
`range_clear_contents(range)`, `get_cell_content` →
|
|
14
|
+
`get_localized_cell_content`, `get_cell_style` → `get_style_for_cell`,
|
|
15
|
+
`set_frozen_rows_count` / `set_frozen_columns_count` → `set_frozen_rows` /
|
|
16
|
+
`set_frozen_columns`, `rename_sheet(sheet, name)` →
|
|
17
|
+
`rename_sheet_by_index`; `rename_sheet(old_name, new_name)` renames by name
|
|
18
|
+
- `UserModel`: `clear_cell_contents(sheet, row, column)` →
|
|
19
|
+
`range_clear_contents(range)`, `set_column_width(sheet, column, width)` →
|
|
20
|
+
`set_columns_width(sheet, column_start, column_end, width)`, and likewise
|
|
21
|
+
`set_rows_height`
|
|
22
|
+
- **breaking**: style Hashes have Symbol keys (`style[:font][:b]`); setters
|
|
23
|
+
accept Symbol or String keys, but no longer a JSON String
|
|
24
|
+
- **breaking**: `UserModel#set_cell_style` is removed; style a `UserModel` per
|
|
25
|
+
property with `update_range_style`. It could not write back a style read with
|
|
26
|
+
`get_cell_style`, and failed part-way through.
|
|
27
|
+
- `set_sheet_color` accepts nil to clear a sheet's color
|
|
28
|
+
- sheet colors read back as nil rather than absent when unset
|
|
29
|
+
- defined names on `Model` and `UserModel`: `defined_names`,
|
|
30
|
+
`new_defined_name`, `update_defined_name`, `delete_defined_name`,
|
|
31
|
+
`is_valid_defined_name` (raises with the reason) and `valid_defined_name?`
|
|
32
|
+
- typed cell setters on `Model`: `update_cell_with_text`, `_number`, `_bool`,
|
|
33
|
+
`_formula`
|
|
34
|
+
- typed cell readers on `Model`: `get_cell_value_by_index`,
|
|
35
|
+
`get_cell_value_by_ref`, `get_cell_formula`, `is_empty_cell`, `get_all_cells`
|
|
36
|
+
- row and column default styles on `Model`: `get`/`set`/`delete_column_style`,
|
|
37
|
+
`get`/`set`/`delete_row_style`, plus `copy_cell_style`
|
|
38
|
+
- `range_clear_all` on both APIs, `range_clear_formatting` on `UserModel`
|
|
39
|
+
- `insert_sheet` and `set_sheet_state` on `Model`
|
|
40
|
+
- `pause_evaluation` / `resume_evaluation` on `UserModel`, and `batch` to
|
|
41
|
+
recalculate once after a block
|
|
42
|
+
- hidden rows and columns: `is_column_hidden` / `is_row_hidden` on both APIs,
|
|
43
|
+
`set_column_hidden` / `set_row_hidden` on `Model`, `set_columns_hidden` /
|
|
44
|
+
`set_rows_hidden` on `UserModel`
|
|
45
|
+
- xlsx in memory: `to_xlsx_bytes` on both APIs, `load_from_xlsx_bytes` and
|
|
46
|
+
`create_user_model_from_xlsx_bytes`
|
|
47
|
+
- fix a memory leak: every constructor leaked its string arguments on each call
|
|
48
|
+
- package only README, CHANGELOG and licenses instead of every `*.md`
|
|
49
|
+
|
|
1
50
|
## 0.7.1.5
|
|
2
51
|
|
|
3
52
|
- link to changelog and documentation in gemspec
|
data/Cargo.lock
CHANGED
|
@@ -449,9 +449,9 @@ dependencies = [
|
|
|
449
449
|
|
|
450
450
|
[[package]]
|
|
451
451
|
name = "ironcalc"
|
|
452
|
-
version = "0.
|
|
452
|
+
version = "0.8.3"
|
|
453
453
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
454
|
-
checksum = "
|
|
454
|
+
checksum = "384c2a5b1e78741cedfaa4fd3209fdb115c1a52453bc10137dfe970ed92872be"
|
|
455
455
|
dependencies = [
|
|
456
456
|
"bitcode",
|
|
457
457
|
"chrono",
|
|
@@ -466,9 +466,9 @@ dependencies = [
|
|
|
466
466
|
|
|
467
467
|
[[package]]
|
|
468
468
|
name = "ironcalc_base"
|
|
469
|
-
version = "0.
|
|
469
|
+
version = "0.8.3"
|
|
470
470
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
471
|
-
checksum = "
|
|
471
|
+
checksum = "ce1dd83cada7da742782076daccda92e33162e9f4396a958ae3e7c5bb64e6a01"
|
|
472
472
|
dependencies = [
|
|
473
473
|
"bitcode",
|
|
474
474
|
"chrono",
|
|
@@ -477,20 +477,22 @@ dependencies = [
|
|
|
477
477
|
"js-sys",
|
|
478
478
|
"rand",
|
|
479
479
|
"regex",
|
|
480
|
+
"regex-lite",
|
|
480
481
|
"ryu",
|
|
481
482
|
"serde",
|
|
482
483
|
"statrs",
|
|
484
|
+
"wasm-bindgen",
|
|
483
485
|
]
|
|
484
486
|
|
|
485
487
|
[[package]]
|
|
486
488
|
name = "ironcalc_ruby"
|
|
487
|
-
version = "0.
|
|
489
|
+
version = "0.0.0"
|
|
488
490
|
dependencies = [
|
|
489
491
|
"bitcode",
|
|
490
492
|
"ironcalc",
|
|
491
493
|
"magnus",
|
|
492
494
|
"serde",
|
|
493
|
-
"
|
|
495
|
+
"serde_magnus",
|
|
494
496
|
]
|
|
495
497
|
|
|
496
498
|
[[package]]
|
|
@@ -817,6 +819,12 @@ dependencies = [
|
|
|
817
819
|
"regex-syntax",
|
|
818
820
|
]
|
|
819
821
|
|
|
822
|
+
[[package]]
|
|
823
|
+
name = "regex-lite"
|
|
824
|
+
version = "0.1.9"
|
|
825
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
826
|
+
checksum = "cab834c73d247e67f4fae452806d17d3c7501756d98c8808d7c9c7aa7d18f973"
|
|
827
|
+
|
|
820
828
|
[[package]]
|
|
821
829
|
name = "regex-syntax"
|
|
822
830
|
version = "0.8.11"
|
|
@@ -896,6 +904,17 @@ dependencies = [
|
|
|
896
904
|
"zmij",
|
|
897
905
|
]
|
|
898
906
|
|
|
907
|
+
[[package]]
|
|
908
|
+
name = "serde_magnus"
|
|
909
|
+
version = "0.11.0"
|
|
910
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
911
|
+
checksum = "8ff64c88ddd26acdcad5a501f18bcc339927b77b69f4a03bfaf2a6fc5ba2ac4b"
|
|
912
|
+
dependencies = [
|
|
913
|
+
"magnus",
|
|
914
|
+
"serde",
|
|
915
|
+
"tap",
|
|
916
|
+
]
|
|
917
|
+
|
|
899
918
|
[[package]]
|
|
900
919
|
name = "sha1"
|
|
901
920
|
version = "0.10.6"
|
|
@@ -981,6 +1000,12 @@ dependencies = [
|
|
|
981
1000
|
"unicode-ident",
|
|
982
1001
|
]
|
|
983
1002
|
|
|
1003
|
+
[[package]]
|
|
1004
|
+
name = "tap"
|
|
1005
|
+
version = "1.0.1"
|
|
1006
|
+
source = "registry+https://github.com/rust-lang/crates.io-index"
|
|
1007
|
+
checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369"
|
|
1008
|
+
|
|
984
1009
|
[[package]]
|
|
985
1010
|
name = "thiserror"
|
|
986
1011
|
version = "1.0.69"
|
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.
|
|
43
|
-
are
|
|
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
|
-
###
|
|
46
|
+
### API overview
|
|
46
47
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
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
|
-
|
|
58
|
-
|
|
59
|
-
|
|
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**
|
|
71
|
-
|
|
72
|
-
`new_sheet`, `save_to_xlsx`, `to_bytes`, …
|
|
73
|
-
|
|
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,56 @@ 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 |
|
|
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
|
|
113
|
-
|
|
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.8.3**,
|
|
267
|
+
the version this gem tracks, and accurate at the time of writing:
|
|
268
|
+
|
|
269
|
+
| | Python | Ruby |
|
|
270
|
+
|---|---|---|
|
|
271
|
+
| `Model` | 69 | 62 |
|
|
272
|
+
| `UserModel` | 102 | 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 and themes are a known backlog,
|
|
277
|
+
listed explicitly in `rake parity`'s `ENGINE_DEFERRED` so they stay visible.
|
|
278
|
+
|
|
279
|
+
What Ruby adds is mostly layering rather than extra engine coverage: Hash-based
|
|
280
|
+
styles, `batch`, and xlsx in memory (`to_xlsx_bytes` / `load_from_xlsx_bytes`).
|
|
281
|
+
|
|
282
|
+
These numbers move with every engine release; `rake parity` reports the
|
|
283
|
+
current picture.
|
|
284
|
+
|
|
285
|
+
## AI-assisted development
|
|
286
|
+
|
|
287
|
+
These bindings are written and maintained with substantial help from
|
|
288
|
+
[Claude Code](https://claude.com/claude-code), Anthropic's coding agent. A
|
|
289
|
+
human maintainer directs the work, reviews every change and makes the releases.
|
|
290
|
+
|
|
291
|
+
Correctness doesn't rest on review alone. The test suite, run in CI on every
|
|
292
|
+
push, re-runs the engine's own formula regression fixtures through the binding.
|
|
293
|
+
`rake parity` checks the API surface and method signatures against the engine
|
|
294
|
+
and the Python bindings. The conventions agents follow here are in
|
|
295
|
+
[AGENTS.md](https://github.com/jvdp/IronCalc-Ruby/blob/main/AGENTS.md).
|
|
114
296
|
|
|
115
297
|
## License
|
|
116
298
|
|
data/ext/ironcalc/Cargo.toml
CHANGED
|
@@ -10,8 +10,8 @@ crate-type = ["cdylib"]
|
|
|
10
10
|
[dependencies]
|
|
11
11
|
magnus = "0.8"
|
|
12
12
|
serde = { version = "1.0", features = ["derive"] }
|
|
13
|
-
|
|
13
|
+
serde_magnus = "0.11"
|
|
14
14
|
bitcode = "0.6.8"
|
|
15
15
|
# The IronCalc engine, published on crates.io as `ironcalc`. Renamed to `xlsx`
|
|
16
16
|
# here so the source can refer to `xlsx::base`, `xlsx::import`, `xlsx::export`.
|
|
17
|
-
xlsx = { package = "ironcalc", version = "0.
|
|
17
|
+
xlsx = { package = "ironcalc", version = "0.8.3" }
|