rigortype 0.2.0 → 0.2.2
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/README.md +82 -20
- data/data/core_overlay/numeric.rbs +33 -0
- data/data/core_overlay/pathname.rbs +25 -0
- data/data/core_overlay/string_scanner.rbs +28 -0
- data/data/gem_overlay/activesupport/core_ext.rbs +473 -0
- data/data/vendored_gem_sigs/ast/ast.rbs +130 -0
- data/data/vendored_gem_sigs/bcrypt/bcrypt.rbs +47 -0
- data/data/vendored_gem_sigs/bundler/bundler.rbs +238 -0
- data/data/vendored_gem_sigs/cgi/cgi_extras.rbs +34 -0
- data/data/vendored_gem_sigs/did_you_mean/did_you_mean_extras.rbs +34 -0
- data/data/vendored_gem_sigs/idn-ruby/idn.rbs +54 -0
- data/data/vendored_gem_sigs/mysql2/client.rbs +55 -0
- data/data/vendored_gem_sigs/mysql2/error.rbs +5 -0
- data/data/vendored_gem_sigs/mysql2/result.rbs +31 -0
- data/data/vendored_gem_sigs/mysql2/statement.rbs +5 -0
- data/data/vendored_gem_sigs/nokogiri/nokogiri.rbs +2332 -0
- data/data/vendored_gem_sigs/nokogiri/nokogiri_html5.rbs +47 -0
- data/data/vendored_gem_sigs/pg/pg.rbs +212 -0
- data/data/vendored_gem_sigs/prism/prism_supplement.rbs +44 -0
- data/data/vendored_gem_sigs/redis/errors.rbs +50 -0
- data/data/vendored_gem_sigs/redis/future.rbs +5 -0
- data/data/vendored_gem_sigs/redis/redis.rbs +348 -0
- data/data/vendored_gem_sigs/redis/redis_extras.rbs +130 -0
- data/data/vendored_gem_sigs/rubygems/rubygems_extras.rbs +226 -0
- data/docs/handbook/01-getting-started.md +311 -0
- data/docs/handbook/02-everyday-types.md +337 -0
- data/docs/handbook/03-narrowing.md +359 -0
- data/docs/handbook/04-tuples-and-shapes.md +321 -0
- data/docs/handbook/05-methods-and-blocks.md +339 -0
- data/docs/handbook/06-classes.md +305 -0
- data/docs/handbook/07-rbs-and-extended.md +427 -0
- data/docs/handbook/08-understanding-errors.md +373 -0
- data/docs/handbook/09-plugins.md +241 -0
- data/docs/handbook/10-sorbet.md +347 -0
- data/docs/handbook/11-sig-gen.md +312 -0
- data/docs/handbook/12-lightweight-hkt.md +333 -0
- data/docs/handbook/README.md +275 -0
- data/docs/handbook/appendix-elixir.md +370 -0
- data/docs/handbook/appendix-go.md +399 -0
- data/docs/handbook/appendix-java-csharp.md +470 -0
- data/docs/handbook/appendix-liskov.md +580 -0
- data/docs/handbook/appendix-mypy.md +370 -0
- data/docs/handbook/appendix-phpstan.md +338 -0
- data/docs/handbook/appendix-protocols-and-structural-typing.md +292 -0
- data/docs/handbook/appendix-rust.md +446 -0
- data/docs/handbook/appendix-steep.md +336 -0
- data/docs/handbook/appendix-type-theory.md +1662 -0
- data/docs/handbook/appendix-typeprof.md +416 -0
- data/docs/handbook/appendix-typescript.md +332 -0
- data/docs/install.md +189 -0
- data/docs/llms.txt +72 -0
- data/docs/manual/01-installation.md +342 -0
- data/docs/manual/02-cli-reference.md +557 -0
- data/docs/manual/03-configuration.md +152 -0
- data/docs/manual/04-diagnostics.md +206 -0
- data/docs/manual/05-inspecting-types.md +109 -0
- data/docs/manual/06-baseline.md +104 -0
- data/docs/manual/07-plugins.md +92 -0
- data/docs/manual/08-skills.md +143 -0
- data/docs/manual/09-editor-integration.md +245 -0
- data/docs/manual/10-mcp-server.md +532 -0
- data/docs/manual/11-ci.md +274 -0
- data/docs/manual/12-caching.md +116 -0
- data/docs/manual/13-troubleshooting.md +120 -0
- data/docs/manual/14-rails-quickstart.md +332 -0
- data/docs/manual/15-type-protection-coverage.md +204 -0
- data/docs/manual/16-rbs-extended-annotations.md +190 -0
- data/docs/manual/17-driving-improvement.md +160 -0
- data/docs/manual/README.md +87 -0
- data/docs/manual/ci-templates/README.md +58 -0
- data/docs/manual/plugins/README.md +86 -0
- data/docs/manual/plugins/rigor-actioncable.md +78 -0
- data/docs/manual/plugins/rigor-actionmailer.md +74 -0
- data/docs/manual/plugins/rigor-actionpack.md +80 -0
- data/docs/manual/plugins/rigor-activejob.md +58 -0
- data/docs/manual/plugins/rigor-activerecord.md +102 -0
- data/docs/manual/plugins/rigor-activestorage.md +74 -0
- data/docs/manual/plugins/rigor-activesupport-core-ext.md +86 -0
- data/docs/manual/plugins/rigor-devise.md +70 -0
- data/docs/manual/plugins/rigor-dry-schema.md +56 -0
- data/docs/manual/plugins/rigor-dry-struct.md +60 -0
- data/docs/manual/plugins/rigor-dry-types.md +59 -0
- data/docs/manual/plugins/rigor-dry-validation.md +62 -0
- data/docs/manual/plugins/rigor-factorybot.md +76 -0
- data/docs/manual/plugins/rigor-graphql.md +89 -0
- data/docs/manual/plugins/rigor-hanami.md +83 -0
- data/docs/manual/plugins/rigor-mangrove.md +73 -0
- data/docs/manual/plugins/rigor-minitest.md +86 -0
- data/docs/manual/plugins/rigor-pundit.md +72 -0
- data/docs/manual/plugins/rigor-rails-i18n.md +92 -0
- data/docs/manual/plugins/rigor-rails-routes.md +94 -0
- data/docs/manual/plugins/rigor-rails.md +44 -0
- data/docs/manual/plugins/rigor-rbs-inline.md +83 -0
- data/docs/manual/plugins/rigor-rspec-rails.md +72 -0
- data/docs/manual/plugins/rigor-rspec.md +86 -0
- data/docs/manual/plugins/rigor-shoulda-matchers.md +78 -0
- data/docs/manual/plugins/rigor-sidekiq.md +78 -0
- data/docs/manual/plugins/rigor-sinatra.md +61 -0
- data/docs/manual/plugins/rigor-sorbet.md +63 -0
- data/docs/manual/plugins/rigor-statesman.md +75 -0
- data/docs/manual/plugins/rigor-typescript-utility-types.md +71 -0
- data/exe/rigor +1 -1
- data/lib/rigor/analysis/incremental_session.rb +4 -2
- data/lib/rigor/analysis/run_stats.rb +13 -1
- data/lib/rigor/analysis/runner.rb +54 -12
- data/lib/rigor/cli/check_command.rb +26 -3
- data/lib/rigor/cli/coverage_command.rb +67 -92
- data/lib/rigor/cli/coverage_mutation.rb +149 -0
- data/lib/rigor/cli/docs_command.rb +248 -0
- data/lib/rigor/cli/fused_protection_renderer.rb +67 -0
- data/lib/rigor/cli/fused_protection_report.rb +76 -0
- data/lib/rigor/cli/skill_command.rb +103 -41
- data/lib/rigor/cli/skill_describe.rb +346 -0
- data/lib/rigor/cli.rb +25 -3
- data/lib/rigor/config_audit.rb +152 -0
- data/lib/rigor/configuration.rb +12 -0
- data/lib/rigor/environment/rbs_loader.rb +27 -0
- data/lib/rigor/environment.rb +49 -1
- data/lib/rigor/inference/method_dispatcher/constant_folding.rb +140 -38
- data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +37 -6
- data/lib/rigor/inference/scope_indexer.rb +87 -89
- data/lib/rigor/inference/statement_evaluator.rb +27 -0
- data/lib/rigor/plugin/isolation.rb +5 -5
- data/lib/rigor/plugin/loader.rb +4 -2
- data/lib/rigor/protection/diagnostic_oracle.rb +51 -0
- data/lib/rigor/protection/mutation_scanner.rb +98 -38
- data/lib/rigor/protection/mutator.rb +21 -0
- data/lib/rigor/protection/test_suite_oracle.rb +68 -0
- data/lib/rigor/signature_path_audit.rb +92 -0
- data/lib/rigor/version.rb +1 -1
- data/skills/rigor-ask/SKILL.md +172 -0
- data/skills/rigor-doctor/SKILL.md +87 -0
- data/skills/rigor-editor-setup/SKILL.md +114 -0
- data/skills/rigor-mcp-setup/SKILL.md +117 -0
- data/skills/rigor-monkeypatch-resolve/SKILL.md +79 -0
- data/skills/rigor-next-steps/SKILL.md +113 -0
- data/skills/rigor-plugin-tune/SKILL.md +79 -0
- data/skills/rigor-protection-uplift/SKILL.md +133 -0
- data/skills/rigor-rbs-setup/SKILL.md +128 -0
- data/skills/rigor-upgrade/SKILL.md +79 -0
- metadata +120 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: a23952ba800fa7d807c8b8acc4d1cfbb3489024d91c3c30d687ebfdb75c7d1f5
|
|
4
|
+
data.tar.gz: 1a301a820c1c0bd3c2946695ae59f8e00906d1ecebedc0fbfb1fa93da3f6a72a
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6574512ee06d1eb87e42f697d7261eac8ecf9bba9ae4a8a4be6263fba188de5b9786babdcef7e9b2cf41ac4877010726d60f66b741af7b5295d6d3e98e5937cb
|
|
7
|
+
data.tar.gz: d1bcccf23cac521597657aadd2f1c35d7a860998dd3fc8e02a7802c2dc0e9bf23ca3c0e6c368cdb9574cc1ac1e5ff2395f9dd5f164beae13541874d617886b19
|
data/README.md
CHANGED
|
@@ -4,20 +4,25 @@
|
|
|
4
4
|
[](https://github.com/rigortype/rigor/blob/master/LICENSE)
|
|
5
5
|
[](https://deepwiki.com/rigortype/rigor)
|
|
6
6
|
|
|
7
|
-
**Type-aware bug finding for Ruby —
|
|
8
|
-
zero-false-positive bar enforced against real codebases.**
|
|
9
|
-
|
|
10
|
-
|
|
7
|
+
**Type-aware bug finding for Ruby — no annotations required, and a
|
|
8
|
+
zero-false-positive bar enforced against real codebases.** Built on
|
|
9
|
+
RBS: Rigor infers types from the values your code produces, reads any
|
|
10
|
+
RBS you write as an authoritative source, and generates more — but
|
|
11
|
+
needs none to start. Run one command over the code you already have,
|
|
12
|
+
and trust every line of output.
|
|
11
13
|
|
|
12
14
|
```sh
|
|
13
|
-
gem install
|
|
15
|
+
mise use -g ruby@4.0 gem:rigortype # install the tool, globally, on Ruby 4.0
|
|
16
|
+
rigor check app lib # find bugs in the code you already have
|
|
14
17
|
```
|
|
15
18
|
|
|
16
|
-
(The tool
|
|
17
|
-
|
|
19
|
+
(The tool runs on Ruby 4.0 while your project keeps its own Ruby; the
|
|
20
|
+
global `-g` install keeps it off your project's pins. See
|
|
21
|
+
[Get started](#get-started-in-one-prompt).)
|
|
18
22
|
|
|
19
|
-
No
|
|
20
|
-
|
|
23
|
+
No annotations required, no runtime dependency, no changes to your
|
|
24
|
+
code — and any RBS you do add, Rigor reads and uses. Rigor parses Ruby
|
|
25
|
+
with
|
|
21
26
|
[Prism](https://github.com/ruby/prism) and runs a flow-sensitive
|
|
22
27
|
inference engine that reasons about the *values* your expressions
|
|
23
28
|
produce — not just their classes. It catches undefined methods (and
|
|
@@ -106,13 +111,14 @@ Bahasa Indonesia, Polski, Українська, Русский, Română, Türk
|
|
|
106
111
|
the [installation guide](https://rigor.typedduck.fail/reference/manual/01-installation/#set-up-in-your-language).
|
|
107
112
|
|
|
108
113
|
**Manual install** — Rigor is a tool, not a library: install it
|
|
109
|
-
independently, **not** in your project's `Gemfile`.
|
|
110
|
-
|
|
111
|
-
|
|
114
|
+
independently, **not** in your project's `Gemfile`. Install it
|
|
115
|
+
**globally** so `rigor` is on your `PATH` everywhere, running on Ruby
|
|
116
|
+
4.0 while each project keeps its own Ruby — the `-g` install lives in
|
|
117
|
+
your global [`mise`](https://mise.jdx.dev/) config and never touches a
|
|
118
|
+
project's pins:
|
|
112
119
|
|
|
113
120
|
```sh
|
|
114
|
-
mise use ruby@4.0
|
|
115
|
-
mise use gem:rigortype # or: gem install rigortype
|
|
121
|
+
mise use -g ruby@4.0 gem:rigortype # or: gem install rigortype
|
|
116
122
|
```
|
|
117
123
|
|
|
118
124
|
The gem is named `rigortype` (the name `rigor` was taken on RubyGems);
|
|
@@ -202,14 +208,38 @@ walks the whole type model; the
|
|
|
202
208
|
and [user manual](https://rigor.typedduck.fail/reference/manual/) are
|
|
203
209
|
the reference companions.
|
|
204
210
|
|
|
211
|
+
**Stuck on Rigor — or just curious how it works? Ask your agent in
|
|
212
|
+
plain language.** The whole skill surface collapses to two an agent (and
|
|
213
|
+
you) need to remember: **`rigor-next-steps`** ("what should we do
|
|
214
|
+
next?") and **`rigor-ask`** ("answer this about Rigor"). Rigor is niche
|
|
215
|
+
and fast-moving, so a model's *remembered* answer is often stale —
|
|
216
|
+
`rigor-ask` **investigates instead**: it reads Rigor's own handbook and
|
|
217
|
+
manual (bundled in the gem, served **offline** by `rigor docs`, always
|
|
218
|
+
matching your installed version) *and* runs Rigor over your actual code
|
|
219
|
+
(`rigor check` / `annotate` / `type-of`), then answers from what it
|
|
220
|
+
found — citing the page, or the inferred type. Ask *"why is this
|
|
221
|
+
flagged?"*, *"how does narrowing work?"*, *"how is it different from
|
|
222
|
+
Sorbet?"*, *"does it handle Sidekiq?"*, or *"how do I type this
|
|
223
|
+
method?"* — you only have to remember the question, never the command.
|
|
224
|
+
To browse the docs yourself:
|
|
225
|
+
|
|
226
|
+
```sh
|
|
227
|
+
rigor docs # the offline doc index
|
|
228
|
+
rigor docs handbook/03-narrowing # any handbook or manual page by name
|
|
229
|
+
rigor docs --list # list every bundled page
|
|
230
|
+
```
|
|
231
|
+
|
|
205
232
|
## Status
|
|
206
233
|
|
|
207
|
-
Current release: **`v0.
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
234
|
+
Current release: **`v0.2.0`** (2026-06-17) — the first
|
|
235
|
+
publicly-announced (general / evaluation) release. It publishes an
|
|
236
|
+
enumerated [compatibility surface](docs/compatibility.md) as a
|
|
237
|
+
minor-non-break trial, rehearsing the contract that hard-freezes at
|
|
238
|
+
`v1.0.0`. Rigor analyses real Ruby today: it has been hardened against
|
|
239
|
+
Mastodon, Redmine, and GitLab FOSS, and the deliberately conservative
|
|
240
|
+
rule catalogue grows only as fast as the zero-false-positive bar
|
|
241
|
+
allows. Release history: [`CHANGELOG.md`](CHANGELOG.md) ·
|
|
242
|
+
forward-looking commitments:
|
|
213
243
|
[Roadmap](https://rigor.typedduck.fail/reference/roadmap/).
|
|
214
244
|
|
|
215
245
|
## Contributing
|
|
@@ -221,3 +251,35 @@ contributors should read.
|
|
|
221
251
|
## License
|
|
222
252
|
|
|
223
253
|
Mozilla Public License Version 2.0. See [`LICENSE`](LICENSE).
|
|
254
|
+
|
|
255
|
+
## Sponsors
|
|
256
|
+
|
|
257
|
+
Rigor is built and maintained by one person, who has spent the better
|
|
258
|
+
part of the last month — nearly every spare hour of personal time — on
|
|
259
|
+
this project. Sustainable development depends on sustainable funding.
|
|
260
|
+
|
|
261
|
+
**The current monthly budget is well short of the $200 minimum needed
|
|
262
|
+
to keep this pace going; $600 or more would let me work on it
|
|
263
|
+
properly.** If Rigor is saving you time or catching real bugs, please
|
|
264
|
+
consider contributing:
|
|
265
|
+
|
|
266
|
+
- **GitHub Sponsors**: [github.com/sponsors/zonuexe](https://github.com/sponsors/zonuexe)
|
|
267
|
+
- **FANBOX** (credit-card / PayPal): [tadsan.fanbox.cc](https://tadsan.fanbox.cc/)
|
|
268
|
+
|
|
269
|
+
**For individuals** — any amount is welcome and genuinely appreciated.
|
|
270
|
+
Even a small recurring pledge (think of it as buying me one coffee a
|
|
271
|
+
month) makes a difference when it adds up across many users.
|
|
272
|
+
|
|
273
|
+
**For companies** using Rigor in production — please consider a
|
|
274
|
+
contribution that reflects the engineering hours Rigor is saving you.
|
|
275
|
+
A modest business sponsorship goes a long way toward keeping this
|
|
276
|
+
project alive and actively maintained.
|
|
277
|
+
|
|
278
|
+
**Sponsors at $50/month or more** are listed here with a banner.
|
|
279
|
+
*(This threshold will likely move to $100/month at some point — early
|
|
280
|
+
sponsors lock in the lower bar.)*
|
|
281
|
+
|
|
282
|
+
To the sponsors who have already contributed: **thank you sincerely.**
|
|
283
|
+
Your support makes the difference between a project that stalls and
|
|
284
|
+
one that ships.
|
|
285
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
# Rigor core overlay — supplemental core signatures.
|
|
2
|
+
#
|
|
3
|
+
# This directory holds Rigor-owned reopenings of Ruby core classes that
|
|
4
|
+
# add methods upstream `ruby/rbs` does not declare on a class but which
|
|
5
|
+
# every concrete value of that class answers at runtime. It is loaded
|
|
6
|
+
# LAST into the RBS environment (after core + stdlib + vendored gem
|
|
7
|
+
# sigs), so an upstream declaration always wins on conflict — these
|
|
8
|
+
# entries only fill genuine holes.
|
|
9
|
+
#
|
|
10
|
+
# Provenance: hand-authored against the documented CRuby behaviour, not
|
|
11
|
+
# extracted. Keep each addition justified by an observed false positive.
|
|
12
|
+
#
|
|
13
|
+
# --- Numeric coercion methods ---
|
|
14
|
+
#
|
|
15
|
+
# `ruby/rbs`'s `Numeric` declares only `to_c` and `to_int`; the three
|
|
16
|
+
# value-coercion selectors `to_f` / `to_i` / `to_r` are declared solely
|
|
17
|
+
# on the concrete subclasses (`Integer`, `Float`, `Rational`, `Complex`).
|
|
18
|
+
# But Rigor routinely *widens* an arithmetic chain to the abstract
|
|
19
|
+
# `Numeric` nominal — `Complex#abs -> Numeric`, or an overload join over
|
|
20
|
+
# `Integer | Float` — and the instant a widened value is asked for
|
|
21
|
+
# `.to_f`, dispatch misses and `call.undefined-method` fires on plain,
|
|
22
|
+
# correct arithmetic (observed four times across actionview's
|
|
23
|
+
# `date_helper`: `(distance_in_minutes.to_f / 60.0)`).
|
|
24
|
+
#
|
|
25
|
+
# Every concrete `Numeric` responds to all three, so the widening must
|
|
26
|
+
# not strip the capability. Returns mirror the concrete subclass
|
|
27
|
+
# signatures. `to_int` is already upstream and intentionally not
|
|
28
|
+
# duplicated here.
|
|
29
|
+
class Numeric
|
|
30
|
+
def to_f: () -> Float
|
|
31
|
+
def to_i: () -> Integer
|
|
32
|
+
def to_r: () -> Rational
|
|
33
|
+
end
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
# Rigor core overlay — supplemental core signatures.
|
|
2
|
+
#
|
|
3
|
+
# --- Pathname#expand_path ---
|
|
4
|
+
#
|
|
5
|
+
# Upstream `ruby/rbs` declares `Pathname#expand_path` as:
|
|
6
|
+
#
|
|
7
|
+
# def expand_path: (?String dir) -> Pathname
|
|
8
|
+
#
|
|
9
|
+
# But `Pathname#expand_path` delegates to `File.expand_path`, whose `dir`
|
|
10
|
+
# parameter is typed as `path` (= `string | _ToPath`). Passing a `Pathname`
|
|
11
|
+
# as the base directory is the idiomatic Bundler pattern:
|
|
12
|
+
#
|
|
13
|
+
# Pathname.new(path).expand_path(Bundler.root) # root → Pathname
|
|
14
|
+
#
|
|
15
|
+
# With the ADR-57 self-call adoption gate now resolving `Bundler.root` to
|
|
16
|
+
# `Pathname`, all five call sites in bundler.rb / bundler/source/git.rb fire
|
|
17
|
+
# `argument type mismatch at parameter 'dir'`. The upstream sig is simply
|
|
18
|
+
# under-typed: the runtime accepts any `to_path`-bearing object.
|
|
19
|
+
#
|
|
20
|
+
# The overlay widens `dir` to `String | Pathname`, matching the runtime
|
|
21
|
+
# delegation and the `File.expand_path` `path` alias used elsewhere in RBS.
|
|
22
|
+
class Pathname
|
|
23
|
+
def expand_path: (?String | Pathname dir) -> Pathname
|
|
24
|
+
| ...
|
|
25
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# Rigor core overlay — supplemental core signatures.
|
|
2
|
+
#
|
|
3
|
+
# --- StringScanner#[] ---
|
|
4
|
+
#
|
|
5
|
+
# The pinned `rbs` gem (4.0.2) declares `StringScanner#[]` as only:
|
|
6
|
+
#
|
|
7
|
+
# def []: (Integer) -> String?
|
|
8
|
+
#
|
|
9
|
+
# But `StringScanner#[]` also accepts a capture-group *name* — a `String`
|
|
10
|
+
# or `Symbol` — and returns the named capture from the most recent match.
|
|
11
|
+
# Named-capture access (`scanner[:key]`) is the idiomatic form when the
|
|
12
|
+
# scan pattern uses named groups:
|
|
13
|
+
#
|
|
14
|
+
# scanner.skip(/(?<key>\w+)=/)
|
|
15
|
+
# scanner[:key] # => the captured String, or nil
|
|
16
|
+
#
|
|
17
|
+
# Newer `ruby/rbs` already widens the signature to
|
|
18
|
+
# `(Integer | String | Symbol) -> String?`; the pinned 4.0.2 gem lags.
|
|
19
|
+
# Without the wider overload, a named-capture access such as Mastodon's
|
|
20
|
+
# `scanner[:key]` false-fires `call.argument-type-mismatch` (the lone
|
|
21
|
+
# overload rejects a `Symbol`).
|
|
22
|
+
#
|
|
23
|
+
# The overlay supplies the runtime-accurate overload; drop it once the
|
|
24
|
+
# pinned `rbs` gem carries the wider signature.
|
|
25
|
+
class StringScanner
|
|
26
|
+
def []: (Integer | String | Symbol) -> String?
|
|
27
|
+
| ...
|
|
28
|
+
end
|