rigortype 0.0.8 → 0.1.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.
Files changed (73) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +234 -22
  3. data/data/builtins/ruby_core/encoding.yml +210 -0
  4. data/data/builtins/ruby_core/exception.yml +641 -0
  5. data/data/builtins/ruby_core/numeric.yml +3 -2
  6. data/data/builtins/ruby_core/proc.yml +731 -0
  7. data/data/builtins/ruby_core/random.yml +166 -0
  8. data/data/builtins/ruby_core/re.yml +689 -0
  9. data/data/builtins/ruby_core/struct.yml +449 -0
  10. data/lib/rigor/analysis/check_rules.rb +228 -40
  11. data/lib/rigor/analysis/diagnostic.rb +15 -1
  12. data/lib/rigor/analysis/runner.rb +199 -4
  13. data/lib/rigor/builtins/imported_refinements.rb +6 -1
  14. data/lib/rigor/cache/rbs_class_ancestor_table.rb +63 -0
  15. data/lib/rigor/cache/rbs_class_type_param_names.rb +60 -0
  16. data/lib/rigor/cache/rbs_constant_table.rb +15 -51
  17. data/lib/rigor/cache/rbs_descriptor.rb +55 -0
  18. data/lib/rigor/cache/rbs_environment.rb +52 -0
  19. data/lib/rigor/cache/rbs_environment_marshal_patch.rb +40 -0
  20. data/lib/rigor/cache/rbs_instance_definitions.rb +79 -0
  21. data/lib/rigor/cache/rbs_known_class_names.rb +43 -0
  22. data/lib/rigor/cache/store.rb +81 -15
  23. data/lib/rigor/cli.rb +45 -7
  24. data/lib/rigor/configuration/severity_profile.rb +109 -0
  25. data/lib/rigor/configuration.rb +110 -6
  26. data/lib/rigor/environment/rbs_hierarchy.rb +18 -5
  27. data/lib/rigor/environment/rbs_loader.rb +220 -32
  28. data/lib/rigor/environment.rb +11 -2
  29. data/lib/rigor/flow_contribution/conflict.rb +81 -0
  30. data/lib/rigor/flow_contribution/element.rb +53 -0
  31. data/lib/rigor/flow_contribution/fact.rb +88 -0
  32. data/lib/rigor/flow_contribution/merge_result.rb +67 -0
  33. data/lib/rigor/flow_contribution/merger.rb +275 -0
  34. data/lib/rigor/flow_contribution.rb +179 -0
  35. data/lib/rigor/inference/block_parameter_binder.rb +15 -0
  36. data/lib/rigor/inference/builtins/encoding_catalog.rb +67 -0
  37. data/lib/rigor/inference/builtins/exception_catalog.rb +92 -0
  38. data/lib/rigor/inference/builtins/proc_catalog.rb +122 -0
  39. data/lib/rigor/inference/builtins/random_catalog.rb +58 -0
  40. data/lib/rigor/inference/builtins/re_catalog.rb +81 -0
  41. data/lib/rigor/inference/builtins/struct_catalog.rb +55 -0
  42. data/lib/rigor/inference/expression_typer.rb +110 -6
  43. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +16 -1
  44. data/lib/rigor/inference/method_dispatcher/literal_string_folding.rb +173 -0
  45. data/lib/rigor/inference/method_dispatcher/rbs_dispatch.rb +21 -1
  46. data/lib/rigor/inference/method_dispatcher.rb +2 -0
  47. data/lib/rigor/inference/multi_target_binder.rb +2 -0
  48. data/lib/rigor/inference/narrowing.rb +134 -144
  49. data/lib/rigor/inference/scope_indexer.rb +75 -1
  50. data/lib/rigor/inference/statement_evaluator.rb +380 -40
  51. data/lib/rigor/plugin/access_denied_error.rb +24 -0
  52. data/lib/rigor/plugin/base.rb +241 -0
  53. data/lib/rigor/plugin/io_boundary.rb +102 -0
  54. data/lib/rigor/plugin/load_error.rb +23 -0
  55. data/lib/rigor/plugin/loader.rb +191 -0
  56. data/lib/rigor/plugin/manifest.rb +134 -0
  57. data/lib/rigor/plugin/registry.rb +50 -0
  58. data/lib/rigor/plugin/services.rb +65 -0
  59. data/lib/rigor/plugin/trust_policy.rb +99 -0
  60. data/lib/rigor/plugin.rb +61 -0
  61. data/lib/rigor/rbs_extended.rb +103 -0
  62. data/lib/rigor/reflection.rb +2 -2
  63. data/lib/rigor/type/combinator.rb +72 -0
  64. data/lib/rigor/type/refined.rb +50 -2
  65. data/lib/rigor/version.rb +1 -1
  66. data/lib/rigor.rb +13 -0
  67. data/sig/rigor/environment.rbs +7 -1
  68. data/sig/rigor/inference.rbs +1 -0
  69. data/sig/rigor/rbs_extended.rbs +2 -0
  70. data/sig/rigor/scope.rbs +1 -0
  71. data/sig/rigor/type.rbs +7 -0
  72. data/sig/rigor.rbs +3 -1
  73. metadata +38 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 38aa66f97f5bed742a36c156ceee7f13d3181597b74c32329b693b3c219852b3
4
- data.tar.gz: 69af0ccbf42c2b890b78a558d574b49293ff6b4880875568137098624e66d3f8
3
+ metadata.gz: 257469533556c55164c5dbb9ea351c142ea600b17a90b6f9e632b5307bbbac08
4
+ data.tar.gz: be2141e8f53748716bd7f19e95632a1fab17fde8110dd824d981baaf2522371c
5
5
  SHA512:
6
- metadata.gz: 8a9e0ee0461e2f0b2779981fa95758e0b7b5bd02668254dc1cb2d82002565b383d866534edff6e75c53aa0a9ae2fdb59832a35788ccfda3cb4558982bed61b15
7
- data.tar.gz: 9699b63098d16e1959177684a849923384196f0dac55a532a3a0ecdff77d45c76230c3b72a273f59ec237059127007d7bb1ae01be9c9cf8b9613a02033b89bb5
6
+ metadata.gz: 221248b2968dcd5d11963197468407ffbc34f2c41b79aa45321a5171e8183817e1ed67fbac37c852c6f22c910b065fef7214cf5f5ef2f03ec6f3c2aef5cce213
7
+ data.tar.gz: d2b096836618fd21a44810aa7c87bad2b0fd28a90baf395dd206ece02844d65819f1ab0cc80ea7a956a4b590351a4f67572be959d8b4effc9d086ff120498e2e
data/README.md CHANGED
@@ -1,7 +1,8 @@
1
1
  # Rigor
2
2
 
3
3
  [![Gem Version](https://badge.fury.io/rb/rigortype.svg?icon=si%3Arubygems)](https://badge.fury.io/rb/rigortype)
4
- ![GitHub License](https://img.shields.io/github/license/rigortype/rigor)
4
+ [![GitHub License](https://img.shields.io/github/license/rigortype/rigor)](https://github.com/rigortype/rigor/blob/master/LICENSE)
5
+ [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/rigortype/rigor)
5
6
 
6
7
  **Inference-first static analysis for Ruby.** Add Rigor to your
7
8
  Gemfile and run `rigor check` over your code — no annotations,
@@ -14,14 +15,23 @@ for any class it can find, and reports a small but trustworthy
14
15
  catalogue of bugs (undefined methods on typed receivers, wrong
15
16
  positional arity, provable `Integer / 0`, …).
16
17
 
18
+ The differentiator is a richer type vocabulary than ordinary
19
+ RBS expresses. Rigor reasons about *what values an expression
20
+ actually produces* — literal values, integer ranges,
21
+ refinement-type carriers, per-position tuple / hash shapes —
22
+ not just *which class an object belongs to*. See **[Beyond
23
+ `Integer` and `String`](#beyond-integer-and-string-rigors-richer-type-vocabulary)**
24
+ for the full type-model story; the short pitch is below.
25
+
17
26
  When you want tighter types than RBS expresses, refine them
18
27
  through the
19
28
  [`RBS::Extended`](docs/type-specification/rbs-extended.md)
20
29
  annotation surface — `rigor:v1:return:` /
21
30
  `rigor:v1:param:` / `rigor:v1:assert` directives accept the
22
31
  imported-built-in refinement names (`non-empty-string`,
23
- `positive-int`, `non-empty-array[Integer]`, `int<5, 10>`, …)
24
- without changing the underlying RBS.
32
+ `positive-int`, `non-empty-array[Integer]`, `int<5, 10>`,
33
+ `literal-string`, `non-lowercase-string`, …) without changing
34
+ the underlying RBS.
25
35
 
26
36
  ## Installation
27
37
 
@@ -51,7 +61,7 @@ The gem ships an executable named `rigor` (gem name is
51
61
 
52
62
  **Ruby version.** The gemspec requires `>= 4.0.0, < 4.1`.
53
63
 
54
- ## First analysis
64
+ ## Quick start
55
65
 
56
66
  Drop into your project root and run the canonical commands:
57
67
 
@@ -60,15 +70,15 @@ Drop into your project root and run the canonical commands:
60
70
  # rule-driven bugs across `lib/`.
61
71
  bundle exec rigor check lib
62
72
 
73
+ # Drop a starter .rigor.yml into the project root.
74
+ bundle exec rigor init
75
+
63
76
  # Print the inferred type at a precise FILE:LINE:COL position.
64
77
  bundle exec rigor type-of lib/foo.rb:10:5
65
78
 
66
79
  # Report Scope#type_of coverage across a tree (handy when
67
80
  # diagnosing why a particular call site reads as `untyped`).
68
81
  bundle exec rigor type-scan lib
69
-
70
- # Drop a starter .rigor.yml into the project root.
71
- bundle exec rigor init
72
82
  ```
73
83
 
74
84
  ### Sample output
@@ -90,6 +100,130 @@ RBS or in-source `def` / `define_method` discovery. Implicit-
90
100
  self calls, dynamic receivers, and constant-decl alias classes
91
101
  (e.g. `YAML` → `Psych`) are skipped to avoid false positives.
92
102
 
103
+ ### Faster runs through the cache
104
+
105
+ Rigor caches expensive RBS work (the loaded `RBS::Environment`,
106
+ constant-type translation, class hierarchy, type-parameter
107
+ names, known-class set) under `.rigor/cache/` so the second
108
+ `rigor check` is significantly faster than the first. The cache
109
+ is keyed by your project's `.rbs` file digests + the locked
110
+ `rbs` gem version, so a signature change or a gem upgrade
111
+ invalidates exactly what it should.
112
+
113
+ ```sh
114
+ # Inspect what is cached on disk and what this run did.
115
+ bundle exec rigor check --cache-stats lib
116
+
117
+ # Wipe the cache (do this if you suspect staleness).
118
+ bundle exec rigor check --clear-cache lib
119
+
120
+ # Run with caching disabled.
121
+ bundle exec rigor check --no-cache lib
122
+ ```
123
+
124
+ Add `.rigor/` to your `.gitignore` — the cache is per-checkout
125
+ and contains nothing reproducible to share.
126
+
127
+ ## Beyond `Integer` and `String`: Rigor's richer type vocabulary
128
+
129
+ A vanilla static checker answers "what *class* is this object?"
130
+ Rigor answers a much narrower question: "what *subset of values*
131
+ can this expression actually produce?" That distinction is the
132
+ whole point of Rigor — types like `Integer` and `String` describe
133
+ classes, but real-world code carries far more structure (a count
134
+ that's always non-negative, a name that's never empty, a flag
135
+ that's one of three Symbols). Rigor reasons about that structure
136
+ out of the box, without you writing a single annotation.
137
+
138
+ ### The carrier zoo
139
+
140
+ | Carrier | What it records | Example |
141
+ | --- | --- | --- |
142
+ | **Literal types** (`Type::Constant`) | A single Ruby value | `Constant<42>`, `Constant<"hello">`, `Constant<:foo>` |
143
+ | **Integer ranges** (`Type::IntegerRange`) | A bounded integer interval `int<a, b>` | `positive-int = int<1, max>`, `int<5, 10>` |
144
+ | **Refinement types** — split into two halves: `Type::Difference` and `Type::Refined` | A base nominal minus a single value, or a base nominal restricted by a predicate | `non-empty-string = String - ""`, `lowercase-string = String & lowercase?`, `literal-string` |
145
+ | **Intersection** (`Type::Intersection`) | Composition of multiple refinements | `non-empty-lowercase-string = non-empty-string ∩ lowercase-string` |
146
+ | **Tuple / HashShape** | Heterogeneous arrays / known-key hashes that carry per-position / per-key types | `[1, "two", :three]` types as `Tuple[Constant<1>, Constant<"two">, Constant<:three>]`; `{name: "Alice", age: 30}` as `HashShape{name: Constant<"Alice">, age: Constant<30>}` |
147
+ | **Union** (`Type::Union`) | "One of these literal values" — finite enums Rigor can enumerate | `Constant<:zero> \| Constant<:small> \| Constant<:large>` |
148
+ | **`Dynamic[T]`** | The gradual carrier — wraps a static facet with a "could be anything" admission | `Dynamic[Top]` is the conservative fallback Rigor uses when it cannot prove a narrower type |
149
+
150
+ Each refinement / range / literal carrier **erases to its base
151
+ class** for ordinary RBS interop, so importing Rigor is a
152
+ strictly additive change: a method whose RBS sig says
153
+ `-> String` keeps that contract, and Rigor's narrower inference
154
+ just sits on top.
155
+
156
+ ### What this buys you in practice
157
+
158
+ ```ruby
159
+ # Rigor doesn't just see "Integer", it sees "non-negative integer".
160
+ n = ARGV.size # int<0, max> (non-negative-int)
161
+ m = n + 1 # int<1, max> (positive-int)
162
+ m.zero? # Constant<false> — proven; the
163
+ # branch elision can drop the `else`
164
+
165
+ # String composition stays as precise as the inputs allow.
166
+ greeting = "Hello, " # Constant<"Hello, ">
167
+ name = ARGV.first # String? — RBS-declared
168
+ hello = "Hello, #{name}!" # literal-string — every part is
169
+ # literal-bearing, so the result is
170
+ # provably source-derived.
171
+
172
+ # Tuple-shaped destructuring stays per-position.
173
+ first, _middle, last = [10, 20, 30]
174
+ first # Constant<10>
175
+ last # Constant<30>
176
+
177
+ # Constant folding through user methods.
178
+ def is_odd(n) = n.odd?
179
+ is_odd(3) # Constant<true> — folded through
180
+ # the body, not just typed as `bool`
181
+
182
+ # Case/when narrowing produces a literal-set Union.
183
+ label = case n
184
+ when 0 then :zero
185
+ when 1..9 then :small
186
+ else :large
187
+ end
188
+ label # Constant<:zero> | Constant<:small>
189
+ # | Constant<:large>
190
+
191
+ # RBS::Extended directives let you tighten beyond what RBS expresses.
192
+ class Slug
193
+ %a{rigor:v1:return: non-empty-string}
194
+ def normalise: (::String id) -> ::String
195
+ end
196
+ Slug.new.normalise("foo").size # positive-int — provably ≥ 1
197
+ ```
198
+
199
+ Rigor never invents these answers — every narrower carrier is
200
+ derived from literals in the source, control-flow narrowing
201
+ (`is_a?`, `nil?`, `==` against finite literal sets, integer
202
+ comparisons), per-class catalogues for the bundled built-ins,
203
+ or `RBS::Extended` directives the user opted into. When the
204
+ inference cannot prove a value is in a narrower carrier, it
205
+ stays at the wider one (or `Dynamic[Top]`) and Rigor stays
206
+ silent — diagnostics fire only when the narrow type is
207
+ genuinely proved.
208
+
209
+ ### Where the type model is documented
210
+
211
+ - **End-user handbook** — chapter-by-chapter walkthrough of
212
+ the type model written for Ruby programmers without prior
213
+ static-typing background:
214
+ [`docs/handbook/`](docs/handbook/README.md). Start here if
215
+ you want a guided tour of how Rigor sees your code rather
216
+ than a spec deep-dive.
217
+ - One-page mental model:
218
+ [`docs/types.md`](docs/types.md).
219
+ - Binding spec corpus:
220
+ [`docs/type-specification/`](docs/type-specification/README.md).
221
+ - Imported refinement names (kebab-case catalogue):
222
+ [`docs/type-specification/imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md).
223
+ - The `RBS::Extended` annotation grammar that opens this
224
+ vocabulary up to your own RBS:
225
+ [`docs/type-specification/rbs-extended.md`](docs/type-specification/rbs-extended.md).
226
+
93
227
  ## How Rigor finds your types
94
228
 
95
229
  Rigor consults, in order:
@@ -102,8 +236,9 @@ Rigor consults, in order:
102
236
  3. **Gem RBS.** RBS files vendored with installed gems
103
237
  (Prism's own `.rbs`, the `rbs` gem's, …).
104
238
  4. **In-source class discovery.** When no RBS is available,
105
- Rigor walks `def` / `define_method` / `attr_*` so
106
- user-defined methods on a class are recognised.
239
+ Rigor walks `def` / `define_method` / `attr_*` /
240
+ `Data.define(*Symbol)` so user-defined methods on a class
241
+ are recognised.
107
242
 
108
243
  If a type cannot be proved, the engine returns `Dynamic[Top]`
109
244
  (Rigor's gradual carrier) and stays silent — Rigor never invents
@@ -139,8 +274,17 @@ Right-hand side accepts:
139
274
  - Predicate refinements — `lowercase-string`,
140
275
  `uppercase-string`, `numeric-string`, `decimal-int-string`,
141
276
  `octal-int-string`, `hex-int-string`.
277
+ - Paired complements (`~T`-symmetric) —
278
+ `non-lowercase-string`, `non-uppercase-string`,
279
+ `non-numeric-string`. Writing `~lowercase-string` narrows
280
+ `String` to `non-lowercase-string` instead of the generic
281
+ `Difference[String, lowercase-string]` fallback.
142
282
  - Composed shapes — `non-empty-lowercase-string`,
143
- `non-empty-uppercase-string`.
283
+ `non-empty-uppercase-string`, `non-empty-literal-string`.
284
+ - Flow-tracked source-literal — `literal-string`. Rigor lifts
285
+ `"hi #{name}!"`, `"a" + literal_str`, and `literal_str * 3`
286
+ to `literal-string` when every operand is itself
287
+ literal-bearing.
144
288
 
145
289
  The full directive table is in
146
290
  [`docs/type-specification/rbs-extended.md`](docs/type-specification/rbs-extended.md);
@@ -191,32 +335,75 @@ sees `id` as `non-empty-string` (so `id.empty?` reduces to
191
335
  - **Predicate narrowing** — truthiness, `nil?`, `is_a?` /
192
336
  `kind_of?` / `instance_of?`, finite-literal equality,
193
337
  case-equality (`===`) for Class / Module / Range / Regexp,
194
- `case` / `when` integration.
338
+ `case` / `when` integration. Paired-complement narrowing for
339
+ Refined predicates (`~lowercase-string` →
340
+ `non-lowercase-string`).
195
341
  - **Tuple / HashShape carriers** — shape-aware element access,
196
342
  range / start-length slices, closed / open / required /
197
- optional policies.
343
+ optional policies, per-element block fold over
344
+ `map`, `select`, `filter_map`, `flat_map`, `find` /
345
+ `find_index`, `count`, `any?` / `all?` / `none?`, `zip`.
198
346
  - **Constant folding** — aggressive arithmetic / string /
199
347
  Symbol / Tuple-shaped `divmod` folding, cartesian fold over
200
348
  `Union[Constant…]`, integer-range arithmetic
201
349
  (`positive-int + 1` → `int<2, max>`), branch elision on
202
- provably-truthy / falsey predicates.
203
- - **Built-in catalogues** — Numeric, String, Symbol, Array,
204
- IO, File, Hash, Range, Set, Time. Each catalog drives the
205
- fold dispatcher with per-class blocklists for indirect
206
- mutators.
350
+ provably-truthy / falsey predicates,
351
+ `Constant<String>#%` format-string fold against
352
+ `Tuple` / `HashShape` arguments.
353
+ - **Built-in catalogues** Numeric / Integer / Float, String /
354
+ Symbol, Array, Hash, IO, File, Range, Set, Time, Date /
355
+ DateTime, Comparable, Enumerable, Rational, Complex,
356
+ Pathname, Random, Struct (+ `Data`), Encoding, Regexp /
357
+ MatchData, Proc / Method / UnboundMethod, Exception. Each
358
+ catalog drives the fold dispatcher with per-class blocklists
359
+ for indirect mutators.
207
360
  - **Refinement carriers** — `Type::Difference`,
208
361
  `Type::Refined`, `Type::Intersection` provide the
209
362
  imported-built-in catalogue end-to-end through
210
363
  `Builtins::ImportedRefinements`.
211
364
  - **`RBS::Extended` directive routes** — `return:`, `param:`
212
365
  (call-site + body-side), `assert:` /
213
- `predicate-if-(true|false)` accept refinement payloads.
366
+ `predicate-if-(true|false)` accept refinement payloads, and
367
+ roll up into a single `Rigor::FlowContribution` bundle per
368
+ method (the v0.1.0 plugin contribution merger reads bundles
369
+ directly).
214
370
 
215
371
  The full per-release surface lives in
216
372
  [`CHANGELOG.md`](CHANGELOG.md). The internal contracts the
217
373
  analyzer guarantees live under
218
374
  [`docs/internal-spec/`](docs/internal-spec/).
219
375
 
376
+ ## Plugins (v0.1.0)
377
+
378
+ `v0.1.0` adds an extension API so projects can teach Rigor about
379
+ their own DSLs. Six worked examples ship under
380
+ [`examples/`](examples/) — each is a fully-shaped plugin gem
381
+ with a runnable demo and an end-to-end integration spec, and
382
+ each spotlights a different facet of the plugin contract:
383
+
384
+ - [`rigor-deprecations`](examples/rigor-deprecations/) —
385
+ smallest possible plugin (~80 lines); config-driven rules.
386
+ - [`rigor-lisp-eval`](examples/rigor-lisp-eval/) — typing literal
387
+ AST arguments at a method call.
388
+ - [`rigor-statesman`](examples/rigor-statesman/) — two-pass DSL
389
+ analysis (collect declarations, then validate references).
390
+ - [`rigor-pattern`](examples/rigor-pattern/) — plugin →
391
+ analyzer collaboration via `Scope#type_of` and the
392
+ literal-string carrier.
393
+ - [`rigor-units`](examples/rigor-units/) — local-variable flow
394
+ tracking through arithmetic.
395
+ - [`rigor-routes`](examples/rigor-routes/) — `Plugin::IoBoundary`
396
+ reads under `TrustPolicy` plus cache producers (slice 2 +
397
+ slice 6) — the most architecturally complete example.
398
+
399
+ [`examples/README.md`](examples/README.md) is the plugin
400
+ authoring landing page — comparison table, recommended reading
401
+ order, and the architectural map of which surface each example
402
+ exercises. The binding contract for the plugin API lives in
403
+ [`docs/adr/2-extension-api.md`](docs/adr/2-extension-api.md)
404
+ and the slice-by-slice normative specs under
405
+ [`docs/internal-spec/plugin*.md`](docs/internal-spec/).
406
+
220
407
  ## Configuration
221
408
 
222
409
  `rigor init` writes a starter `.rigor.yml`:
@@ -226,19 +413,42 @@ bundle exec rigor init # fails if .rigor.yml exists
226
413
  bundle exec rigor init --force # overwrite
227
414
  ```
228
415
 
229
- The configuration is intentionally small in v0.0.x; see the
230
- generated file for the available knobs.
416
+ Common knobs the file exposes:
417
+
418
+ - `paths` — directories `rigor check` and `rigor type-scan`
419
+ scan when no path is given (defaults to `lib`).
420
+ - `target_ruby` — minimum Ruby version your project targets.
421
+ - `libraries` — extra stdlib libraries to load on top of the
422
+ bundled defaults (e.g. `["csv", "set"]`).
423
+ - `signature_paths` — explicit list of `sig/`-style directories.
424
+ Leave unset (or `null`) to auto-detect `<root>/sig`. Use `[]`
425
+ to disable project-RBS loading entirely.
426
+ - `disable` — rule identifiers to silence project-wide. Shipped
427
+ rules: `undefined-method`, `wrong-arity`,
428
+ `argument-type-mismatch`, `possible-nil-receiver`,
429
+ `dump-type`, `assert-type`, `always-raises`. In-source
430
+ `# rigor:disable <rule>` end-of-line comments silence
431
+ per-line; `# rigor:disable all` suppresses every rule.
231
432
 
232
433
  ## Status
233
434
 
234
- Current release: **`v0.0.4`** (the fourth preview). The
235
- analyzer is usable on real Ruby code today but the rule
435
+ Current released version: **`v0.0.8`** (the eighth preview).
436
+ The analyzer is usable on real Ruby code today but the rule
236
437
  catalogue is deliberately narrow — Rigor's stance is to surface
237
438
  zero false positives while the inference surface stabilises.
238
439
  The roadmap is tracked in
239
440
  [`docs/MILESTONES.md`](docs/MILESTONES.md); release-by-release
240
441
  detail lives in [`CHANGELOG.md`](CHANGELOG.md).
241
442
 
443
+ `v0.0.9` is the active development cluster on `master` and
444
+ covers the persistent cache infrastructure (`.rigor/cache/`,
445
+ `--cache-stats`, `--clear-cache`, `--no-cache`),
446
+ paired-complement Refined narrowing, `literal-string` flow
447
+ tracking, the `Rigor::FlowContribution` bundle struct, and
448
+ six additional built-in catalogues (Random, Struct, Encoding,
449
+ Regexp + MatchData, Proc / Method / UnboundMethod, Exception).
450
+ The next release after `0.0.9` will be `0.1.0`.
451
+
242
452
  ## Contributing
243
453
 
244
454
  See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the minimal
@@ -248,3 +458,5 @@ skill documentation contributors should know about.
248
458
  ## License
249
459
 
250
460
  Mozilla Public License Version 2.0. See [`LICENSE`](LICENSE).
461
+ </content>
462
+ </invoke>
@@ -0,0 +1,210 @@
1
+ # DO NOT EDIT — generated by tool/extract_builtin_catalog.rb
2
+ ---
3
+ schema_version: 1
4
+ generated_from:
5
+ ruby_init_c: references/ruby/encoding.c
6
+ ruby_prelude:
7
+ rbs:
8
+ - references/rbs/core/encoding.rbs
9
+ purity_levels:
10
+ leaf: Prelude :leaf marker (VM-enforced) or C body uses no dispatch/yield/mutation.
11
+ trivial: Prelude method body is a literal return (self/true/false/nil/Integer).
12
+ leaf_when_numeric: C body falls through to rb_num_coerce_* only when an operand
13
+ is non-numeric; safe to fold when every argument is a concrete numeric.
14
+ inline_block: Prelude method carries :inline_block or :use_block; block-dependent.
15
+ block_dependent: C body yields or checks rb_block_given_p.
16
+ mutates_self: C body checks rb_check_frozen — typically a prelude to mutation.
17
+ dispatch: C body calls user-redefinable methods (rb_funcall*, rb_equal, rb_Float,
18
+ num_funcall*, etc).
19
+ unknown: C body not located in indexed C files.
20
+ classes:
21
+ Encoding:
22
+ parent: Object
23
+ defined_at: references/ruby/encoding.c:1992
24
+ includes: []
25
+ constants: {}
26
+ aliases:
27
+ to_s:
28
+ old: name
29
+ source: c
30
+ defined_at: references/ruby/encoding.c:2001
31
+ instance_methods:
32
+ inspect:
33
+ source: c
34
+ cfunc: enc_inspect
35
+ arity: 0
36
+ defined_at: references/ruby/encoding.c:2003
37
+ c_body_at: references/ruby/encoding.c:1344
38
+ c_effects:
39
+ - raises
40
+ purity: leaf
41
+ rbs:
42
+ - "() -> String"
43
+ rbs_at: references/rbs/core/encoding.rbs:281
44
+ names:
45
+ source: c
46
+ cfunc: enc_names
47
+ arity: 0
48
+ defined_at: references/ruby/encoding.c:2004
49
+ c_body_at: references/ruby/encoding.c:1384
50
+ c_effects: []
51
+ purity: leaf
52
+ rbs:
53
+ - "() -> Array[String]"
54
+ rbs_at: references/rbs/core/encoding.rbs:298
55
+ dummy?:
56
+ source: c
57
+ cfunc: enc_dummy_p
58
+ arity: 0
59
+ defined_at: references/ruby/encoding.c:2005
60
+ c_body_at: references/ruby/encoding.c:663
61
+ c_effects: []
62
+ purity: leaf
63
+ rbs:
64
+ - "() -> bool"
65
+ rbs_at: references/rbs/core/encoding.rbs:270
66
+ ascii_compatible?:
67
+ source: c
68
+ cfunc: enc_ascii_compatible_p
69
+ arity: 0
70
+ defined_at: references/ruby/encoding.c:2006
71
+ c_body_at: references/ruby/encoding.c:679
72
+ c_effects: []
73
+ purity: leaf
74
+ rbs:
75
+ - "() -> bool"
76
+ rbs_at: references/rbs/core/encoding.rbs:257
77
+ _dump:
78
+ source: c
79
+ cfunc: enc_dump
80
+ arity: -1
81
+ defined_at: references/ruby/encoding.c:2013
82
+ c_body_at: references/ruby/encoding.c:1502
83
+ c_effects: []
84
+ purity: leaf
85
+ singleton_methods:
86
+ list:
87
+ source: c
88
+ cfunc: enc_list
89
+ arity: 0
90
+ defined_at: references/ruby/encoding.c:2007
91
+ c_body_at: references/ruby/encoding.c:1416
92
+ c_effects: []
93
+ purity: leaf
94
+ rbs:
95
+ - "() -> Array[Encoding]"
96
+ rbs_at: references/rbs/core/encoding.rbs:232
97
+ name_list:
98
+ source: c
99
+ cfunc: rb_enc_name_list
100
+ arity: 0
101
+ defined_at: references/ruby/encoding.c:2008
102
+ c_body_at: references/ruby/encoding.c:1895
103
+ c_effects: []
104
+ purity: leaf
105
+ rbs:
106
+ - "() -> Array[String]"
107
+ rbs_at: references/rbs/core/encoding.rbs:246
108
+ aliases:
109
+ source: c
110
+ cfunc: rb_enc_aliases
111
+ arity: 0
112
+ defined_at: references/ruby/encoding.c:2009
113
+ c_body_at: references/ruby/encoding.c:1941
114
+ c_effects: []
115
+ purity: leaf
116
+ rbs:
117
+ - "() -> Hash[String, String]"
118
+ rbs_at: references/rbs/core/encoding.rbs:66
119
+ find:
120
+ source: c
121
+ cfunc: enc_find
122
+ arity: 1
123
+ defined_at: references/ruby/encoding.c:2010
124
+ c_body_at: references/ruby/encoding.c:1445
125
+ c_effects: []
126
+ purity: leaf
127
+ rbs:
128
+ - "(encoding enc) -> Encoding?"
129
+ rbs_at: references/rbs/core/encoding.rbs:213
130
+ compatible?:
131
+ source: c
132
+ cfunc: enc_compatible_p
133
+ arity: 2
134
+ defined_at: references/ruby/encoding.c:2011
135
+ c_body_at: references/ruby/encoding.c:1480
136
+ c_effects: []
137
+ purity: leaf
138
+ rbs:
139
+ - "(untyped obj1, untyped obj2) -> Encoding?"
140
+ rbs_at: references/rbs/core/encoding.rbs:91
141
+ _load:
142
+ source: c
143
+ cfunc: enc_load
144
+ arity: 1
145
+ defined_at: references/ruby/encoding.c:2014
146
+ c_body_at: references/ruby/encoding.c:1510
147
+ c_effects: []
148
+ purity: leaf
149
+ rbs:
150
+ - "[T] (T) -> T"
151
+ rbs_at: references/rbs/core/encoding.rbs:30
152
+ default_external:
153
+ source: c
154
+ cfunc: get_default_external
155
+ arity: 0
156
+ defined_at: references/ruby/encoding.c:2016
157
+ c_body_at: references/ruby/encoding.c:1704
158
+ c_effects: []
159
+ purity: leaf
160
+ rbs:
161
+ - "() -> Encoding"
162
+ rbs_at: references/rbs/core/encoding.rbs:121
163
+ default_external=:
164
+ source: c
165
+ cfunc: set_default_external
166
+ arity: 1
167
+ defined_at: references/ruby/encoding.c:2017
168
+ c_body_at: references/ruby/encoding.c:1733
169
+ c_effects: []
170
+ purity: leaf
171
+ rbs:
172
+ - "(Encoding enc) -> Encoding"
173
+ - "[T < _ToStr] (T enc) -> T"
174
+ rbs_at: references/rbs/core/encoding.rbs:135
175
+ default_internal:
176
+ source: c
177
+ cfunc: get_default_internal
178
+ arity: 0
179
+ defined_at: references/ruby/encoding.c:2018
180
+ c_body_at: references/ruby/encoding.c:1787
181
+ c_effects: []
182
+ purity: leaf
183
+ rbs:
184
+ - "() -> Encoding?"
185
+ rbs_at: references/rbs/core/encoding.rbs:166
186
+ default_internal=:
187
+ source: c
188
+ cfunc: set_default_internal
189
+ arity: 1
190
+ defined_at: references/ruby/encoding.c:2019
191
+ c_body_at: references/ruby/encoding.c:1813
192
+ c_effects: []
193
+ purity: leaf
194
+ rbs:
195
+ - "(Encoding enc) -> Encoding"
196
+ - "[T < _ToStr] (T enc) -> T"
197
+ - "(nil) -> nil"
198
+ rbs_at: references/rbs/core/encoding.rbs:181
199
+ locale_charmap:
200
+ source: c
201
+ cfunc: rb_locale_charmap
202
+ arity: 0
203
+ defined_at: references/ruby/encoding.c:2020
204
+ purity: unknown
205
+ c_body_at: not_found
206
+ rbs:
207
+ - "() -> String"
208
+ rbs_at: references/rbs/core/encoding.rbs:54
209
+ undefined:
210
+ - new