rigortype 0.0.4 → 0.0.6

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 (34) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +215 -134
  3. data/data/builtins/ruby_core/comparable.yml +87 -0
  4. data/data/builtins/ruby_core/complex.yml +505 -0
  5. data/data/builtins/ruby_core/date.yml +1737 -0
  6. data/data/builtins/ruby_core/enumerable.yml +557 -0
  7. data/data/builtins/ruby_core/file.yml +9 -0
  8. data/data/builtins/ruby_core/pathname.yml +1067 -0
  9. data/data/builtins/ruby_core/rational.yml +365 -0
  10. data/data/builtins/ruby_core/string.yml +9 -0
  11. data/data/builtins/ruby_core/time.yml +6 -4
  12. data/lib/rigor/cli.rb +1 -1
  13. data/lib/rigor/inference/builtins/comparable_catalog.rb +27 -0
  14. data/lib/rigor/inference/builtins/complex_catalog.rb +41 -0
  15. data/lib/rigor/inference/builtins/date_catalog.rb +98 -0
  16. data/lib/rigor/inference/builtins/enumerable_catalog.rb +27 -0
  17. data/lib/rigor/inference/builtins/pathname_catalog.rb +35 -0
  18. data/lib/rigor/inference/builtins/rational_catalog.rb +38 -0
  19. data/lib/rigor/inference/expression_typer.rb +285 -23
  20. data/lib/rigor/inference/method_dispatcher/block_folding.rb +322 -0
  21. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +197 -12
  22. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +99 -0
  23. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +95 -0
  24. data/lib/rigor/inference/method_dispatcher.rb +20 -8
  25. data/lib/rigor/inference/narrowing.rb +210 -1
  26. data/lib/rigor/inference/scope_indexer.rb +87 -11
  27. data/lib/rigor/inference/statement_evaluator.rb +5 -1
  28. data/lib/rigor/rbs_extended.rb +11 -6
  29. data/lib/rigor/type/integer_range.rb +4 -2
  30. data/lib/rigor/version.rb +1 -1
  31. data/sig/rigor/environment.rbs +4 -6
  32. data/sig/rigor/inference.rbs +2 -1
  33. data/sig/rigor/type.rbs +41 -41
  34. metadata +15 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 23970981c0d0b952bc6885102dcf163fbb0cd0f00e4bb2232300676a6904d3a3
4
- data.tar.gz: 07211b55ad358bcb535de36b86d00465c5ba708197ce0945667386b2eca0e3eb
3
+ metadata.gz: 0af88abcc3dd912fd5c9d22440dc456b0418d6bd0de2cae58167f8538880c1a0
4
+ data.tar.gz: 2ef580ca7c24007313fd4b30e4e2f0dc1cd59e68ccdc4113f3fe060694880782
5
5
  SHA512:
6
- metadata.gz: 170f4ce6750090993b14cc4d899d2cf89a89cf1c2a0a086188988a9062b70d569db78488efa4d25805a42204f4b62ad02fee2f812ad51d36008bb75d648b58bf
7
- data.tar.gz: 63df03ee2ef43fa69716911399d971e48da46567ab4f6b5dd4b9ee5c3543fca2db5a169f12f84c4a3964a293f50704190439fc1d32475f41808bfdac771eb50a
6
+ metadata.gz: 46bd06614cdbf530ada69f28fd5be8620b5e54d834c8af69663fdf0949f0592a7123e0f564d924046dbc9b3d9d04ffec96af593825c6b84cafebf1a6b1a60431
7
+ data.tar.gz: df1f86d712a8a081356917989a4c98c775180eb805d54300b671d652a2d87eee86a7624d9b8812f2e7a4b3b26364a668948aa8aa06481c53295908428ab0d4ae
data/README.md CHANGED
@@ -1,169 +1,250 @@
1
1
  # Rigor
2
2
 
3
- Rigor is a static analyzer for Ruby that aims to provide modern,
4
- inference-first type checking without adding type annotations or
5
- runtime dependencies to application code.
6
-
7
- This first preview ships a usable end-to-end pipeline: parse Ruby
8
- with Prism, build a flow-sensitive type-inference engine
9
- (`Rigor::Scope#type_of`), drive a project-aware RBS environment,
10
- and surface diagnostics through a small `rigor check` rule
11
- catalogue.
12
-
13
- ## Status
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)
5
+
6
+ **Inference-first static analysis for Ruby.** Add Rigor to your
7
+ Gemfile and run `rigor check` over your code no annotations,
8
+ no runtime dependency on the analyzer, no DSL.
9
+
10
+ Rigor parses Ruby with [Prism](https://github.com/ruby/prism),
11
+ runs a flow-sensitive type-inference engine over each file,
12
+ consults RBS signatures and the project's own `sig/` directory
13
+ for any class it can find, and reports a small but trustworthy
14
+ catalogue of bugs (undefined methods on typed receivers, wrong
15
+ positional arity, provable `Integer / 0`, …).
16
+
17
+ When you want tighter types than RBS expresses, refine them
18
+ through the
19
+ [`RBS::Extended`](docs/type-specification/rbs-extended.md)
20
+ annotation surface — `rigor:v1:return:` /
21
+ `rigor:v1:param:` / `rigor:v1:assert` directives accept the
22
+ imported-built-in refinement names (`non-empty-string`,
23
+ `positive-int`, `non-empty-array[Integer]`, `int<5, 10>`, …)
24
+ without changing the underlying RBS.
25
+
26
+ ## Installation
27
+
28
+ Add the gem to your application's Gemfile (development group is
29
+ typical — Rigor is a static analyzer, not a runtime dependency):
30
+
31
+ ```ruby
32
+ group :development do
33
+ gem "rigortype", require: false
34
+ end
35
+ ```
14
36
 
15
- `master` is at the **fourth preview** (`v0.0.4`). The engine
16
- recognises the bulk of canonical Ruby surface — local variables,
17
- ivars / cvars / globals (intra- and cross-method), self typing,
18
- lexical constant lookup, predicate narrowing
19
- (`is_a?` / `==` / `===` / `case`-`when`), block parameter binding,
20
- closure escape, Tuple / HashShape carriers — plus the v0.0.3
21
- constant-folding surface and the v0.0.4 refinement-carrier
22
- catalogue (`Type::Difference` / `Type::Refined` / `Type::Intersection`,
23
- 14 imported built-in refinement names through
24
- `Builtins::ImportedRefinements`, and the symmetric
25
- `rigor:v1:return:` / `rigor:v1:param:` / `rigor:v1:assert:`
26
- RBS::Extended directive routes). See [CHANGELOG.md](CHANGELOG.md)
27
- for the per-release surface and
28
- [docs/CURRENT_WORK.md](docs/CURRENT_WORK.md) for the live slice
29
- trail.
30
-
31
- ## Requirements
32
-
33
- - Nix with the `nix-command` and `flakes` features available.
34
- - Ruby 4.0.x and Bundler 4.x, provided by the Flake development
35
- shell.
36
-
37
- ## Setup
37
+ Install:
38
38
 
39
39
  ```sh
40
- nix --extra-experimental-features 'nix-command flakes' develop --command bundle install
41
- nix --extra-experimental-features 'nix-command flakes' develop --command bundle exec rake
40
+ bundle install
42
41
  ```
43
42
 
44
- For interactive development, enter the Flake shell first:
43
+ Or, for a one-off install outside Bundler:
45
44
 
46
45
  ```sh
47
- nix --extra-experimental-features 'nix-command flakes' develop
46
+ gem install rigortype
48
47
  ```
49
48
 
50
- ## Quick Start
49
+ The gem ships an executable named `rigor` (gem name is
50
+ `rigortype` because `rigor` was already taken on RubyGems).
51
51
 
52
- Inside the Flake shell:
52
+ **Ruby version.** The gemspec requires `>= 4.0.0, < 4.1`.
53
53
 
54
- ```sh
55
- # Show available subcommands.
56
- bundle exec exe/rigor help
54
+ ## First analysis
55
+
56
+ Drop into your project root and run the canonical commands:
57
57
 
58
- # Print the inferred type at FILE:LINE:COL.
59
- bundle exec exe/rigor type-of lib/rigor/scope.rb:55:9
58
+ ```sh
59
+ # Diagnose unknown methods, wrong-arity calls, and other
60
+ # rule-driven bugs across `lib/`.
61
+ bundle exec rigor check lib
60
62
 
61
- # Report Scope#type_of coverage across a tree.
62
- bundle exec exe/rigor type-scan lib
63
+ # Print the inferred type at a precise FILE:LINE:COL position.
64
+ bundle exec rigor type-of lib/foo.rb:10:5
63
65
 
64
- # Diagnose unknown methods and wrong-arity calls on typed receivers.
65
- bundle exec exe/rigor check lib
66
+ # Report Scope#type_of coverage across a tree (handy when
67
+ # diagnosing why a particular call site reads as `untyped`).
68
+ bundle exec rigor type-scan lib
66
69
 
67
- # Write a starter .rigor.yml.
68
- bundle exec exe/rigor init
70
+ # Drop a starter .rigor.yml into the project root.
71
+ bundle exec rigor init
69
72
  ```
70
73
 
71
- ### Example diagnostics
72
-
73
- `rigor check` reports the canonical type-check signals it can
74
- prove against the loaded RBS environment:
74
+ ### Sample output
75
75
 
76
76
  ```sh
77
77
  $ cat /tmp/demo.rb
78
- "hello".no_such_method # bug: undefined method
79
- [1, 2, 3].rotate(1, 2) # bug: wrong number of arguments
78
+ "hello".no_such_method # undefined method
79
+ [1, 2, 3].rotate(1, 2) # wrong number of arguments
80
80
 
81
- $ bundle exec exe/rigor check /tmp/demo.rb
81
+ $ bundle exec rigor check /tmp/demo.rb
82
82
  /tmp/demo.rb:1:9: error: undefined method `no_such_method' for "hello"
83
83
  /tmp/demo.rb:2:11: error: wrong number of arguments to `rotate' on Array (given 2, expected 0..1)
84
84
  ```
85
85
 
86
- The rule catalogue is intentionally narrow: a diagnostic fires
87
- only when the receiver type is statically known and the method
88
- set on that class is enumerable through RBS or in-source `def` /
89
- `define_method` discovery. Implicit-self calls, dynamic
90
- receivers, and constant-decl alias classes (e.g. `YAML` → `Psych`)
91
- are skipped to avoid false positives.
92
-
93
- ## What works
94
-
95
- The first preview engine resolves:
96
-
97
- - **Local / instance / class / global variables** — intra-method
98
- bindings (`@x = 1; @x`), cross-method ivar / cvar accumulators
99
- (`def init; @x = 1; end; def get; @x; end`), program-wide
100
- globals.
101
- - **Compound writes** `||=`, `&&=`, `+=` and friends thread
102
- through scope for every variable kind.
103
- - **`self` typing** class- and method-body boundaries inject
104
- `Singleton[T]` / `Nominal[T]`; implicit-self call dispatch
105
- routes through the enclosing class's RBS.
106
- - **Constant lookup** lexical walk against `scope.self_type`,
107
- RBS-core, common stdlib (`pathname`, `optparse`, `json`,
108
- `yaml`, ...), the `prism` and `rbs` gems' RBS, in-source
109
- class discovery, and in-source constant value tracking
110
- (`BUCKETS = [:a, :b, :c]; BUCKETS.first` → `Constant[:a]`).
86
+ The rule catalogue is **deliberately conservative**: a
87
+ diagnostic fires only when the receiver type is statically
88
+ known and the method set on that class is enumerable through
89
+ RBS or in-source `def` / `define_method` discovery. Implicit-
90
+ self calls, dynamic receivers, and constant-decl alias classes
91
+ (e.g. `YAML` → `Psych`) are skipped to avoid false positives.
92
+
93
+ ## How Rigor finds your types
94
+
95
+ Rigor consults, in order:
96
+
97
+ 1. **In-source RBS.** If your project has a `sig/` directory,
98
+ Rigor auto-loads it. `rigor init` writes a `.rigor.yml`
99
+ that points at `sig/` by default.
100
+ 2. **Bundled RBS core + stdlib.** Pathname, OptParse, JSON,
101
+ YAML, etc. ship with the analyzer.
102
+ 3. **Gem RBS.** RBS files vendored with installed gems
103
+ (Prism's own `.rbs`, the `rbs` gem's, …).
104
+ 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.
107
+
108
+ If a type cannot be proved, the engine returns `Dynamic[Top]`
109
+ (Rigor's gradual carrier) and stays silent Rigor never invents
110
+ diagnostics it cannot prove.
111
+
112
+ ## Refining types through `RBS::Extended`
113
+
114
+ When the RBS-declared type is too wide, attach a
115
+ `%a{rigor:v1:…}` annotation to the relevant method in your
116
+ `sig/` file. The annotation is a no-op for ordinary RBS tools
117
+ and a tightening signal for Rigor.
118
+
119
+ ```rbs
120
+ class Slug
121
+ # The runtime always returns a non-empty string. The override
122
+ # tightens the call-site result to non-empty-string and tells
123
+ # the body's `assert_type` that `id` cannot be "".
124
+ %a{rigor:v1:return: non-empty-string}
125
+ %a{rigor:v1:param: id is non-empty-string}
126
+ def normalise: (::String id) -> ::String
127
+ end
128
+ ```
129
+
130
+ Right-hand side accepts:
131
+
132
+ - **RBS class names** — `String`, `::Foo::Bar` (with optional
133
+ `~T` negation for `assert` / `predicate-if-*`).
134
+ - **Imported-built-in refinement names** (kebab-case):
135
+ - Point-removal — `non-empty-string`, `non-zero-int`,
136
+ `non-empty-array[T]`, `non-empty-hash[K, V]`.
137
+ - IntegerRange aliases — `positive-int`, `non-negative-int`,
138
+ `negative-int`, `non-positive-int`, `int<min, max>`.
139
+ - Predicate refinements — `lowercase-string`,
140
+ `uppercase-string`, `numeric-string`, `decimal-int-string`,
141
+ `octal-int-string`, `hex-int-string`.
142
+ - Composed shapes — `non-empty-lowercase-string`,
143
+ `non-empty-uppercase-string`.
144
+
145
+ The full directive table is in
146
+ [`docs/type-specification/rbs-extended.md`](docs/type-specification/rbs-extended.md);
147
+ the catalogue of refinement names is in
148
+ [`docs/type-specification/imported-built-in-types.md`](docs/type-specification/imported-built-in-types.md).
149
+
150
+ ### Example: argument-type-mismatch caught at the call site
151
+
152
+ ```rbs
153
+ # sig/normaliser.rbs
154
+ class Normaliser
155
+ %a{rigor:v1:param: id is non-empty-string}
156
+ def normalise: (::String id) -> ::String
157
+ end
158
+ ```
159
+
160
+ ```ruby
161
+ # app/normaliser.rb
162
+ class Normaliser
163
+ def normalise(id)
164
+ id.upcase
165
+ end
166
+ end
167
+
168
+ n = Normaliser.new
169
+ n.normalise("hello") # OK
170
+ n.normalise("") # rigor flags: argument type mismatch
171
+ ```
172
+
173
+ `rigor check` reports the second call as an
174
+ `argument-type-mismatch` because the literal `""` does not
175
+ satisfy `non-empty-string`. Inside the method body, Rigor also
176
+ sees `id` as `non-empty-string` (so `id.empty?` reduces to
177
+ `Constant[false]` and `id.size` reduces to `positive-int`).
178
+
179
+ ## What rigor sees today
180
+
181
+ - **Local / instance / class / global variables** —
182
+ intra-method bindings, cross-method ivar / cvar
183
+ accumulators, program-wide globals, and compound writes
184
+ (`||=`, `&&=`, `+=`).
185
+ - **`self` typing and constant lookup** — class and method
186
+ body boundaries inject `Singleton[T]` / `Nominal[T]`;
187
+ lexical constant resolution walks RBS-core, common stdlib,
188
+ in-source class discovery, and in-source constant-value
189
+ tracking (`BUCKETS = [:a, :b]; BUCKETS.first` →
190
+ `Constant[:a]`).
111
191
  - **Predicate narrowing** — truthiness, `nil?`, `is_a?` /
112
192
  `kind_of?` / `instance_of?`, finite-literal equality,
113
193
  case-equality (`===`) for Class / Module / Range / Regexp,
114
194
  `case` / `when` integration.
115
- - **Blocks** — parameter binding (incl. destructuring + numbered
116
- parameters), block-return-type uplift through generic methods
117
- (`Array#map { |n| n.to_s }` → `Array[String]`), closure escape
118
- classification, captured-local invalidation on escaping blocks.
119
195
  - **Tuple / HashShape carriers** — shape-aware element access,
120
- range / start-length slices, closed / open / required / optional
121
- policies threaded through `Acceptance`.
122
- - **`rigor check` first-preview rules** — undefined method on
123
- typed receiver, wrong number of positional arguments. Both
124
- consult RBS plus in-source `def` / `define_method` discovery so
125
- reopened classes do not produce false positives.
126
- - **`RBS::Extended` annotation routes** —
127
- `rigor:v1:return: <refinement>` overrides a method's RBS-declared
128
- return; `rigor:v1:param: <name> [is] <refinement>` tightens a
129
- parameter at both the call boundary and inside the method body;
130
- `rigor:v1:assert <name> is <refinement>` substitutes the
131
- refinement carrier at the post-call scope. The right-hand side
132
- accepts any Capitalised class name OR a kebab-case refinement
133
- payload from the imported-built-in catalogue (including
134
- parameterised forms `non-empty-array[Integer]` and bounded
135
- ranges `int<5, 10>`).
136
-
137
- See [docs/CURRENT_WORK.md](docs/CURRENT_WORK.md) for the canonical
138
- status snapshot, [docs/internal-spec/inference-engine.md](docs/internal-spec/inference-engine.md)
139
- for the engine contract, and [docs/adr/](docs/adr/) for the
140
- decision records.
141
-
142
- ## Project layout
143
-
144
- - `lib/rigor` — runtime library, type model, inference engine, CLI.
145
- - `lib/rigor/analysis` — `Runner`, `CheckRules`, `Diagnostic`,
146
- `FactStore`.
147
- - `lib/rigor/inference` — `Scope`-driven typers, dispatchers, and
148
- narrowing.
149
- - `sig` RBS signatures for Rigor itself.
150
- - `spec` RSpec test suite (1250+ examples).
151
- - `docs/adr` — architecture decision records.
152
- - `docs/internal-spec` — engine contracts.
153
- - `docs/type-specification` type-language semantics.
154
-
155
- ## Roadmap past first preview
156
-
157
- In rough priority order (see CURRENT_WORK.md for details):
158
-
159
- 1. More `rigor check` rules (nil-call, type-incompatible writes,
160
- unbound locals).
161
- 2. `RBS::Extended` effect plumbing (`%a{rigor:v1:pure}`,
162
- mutation / escape / call-timing effects).
163
- 3. Diagnostic publication for `FallbackTracer` events.
164
- 4. Plugin contribution layer.
196
+ range / start-length slices, closed / open / required /
197
+ optional policies.
198
+ - **Constant folding** — aggressive arithmetic / string /
199
+ Symbol / Tuple-shaped `divmod` folding, cartesian fold over
200
+ `Union[Constant…]`, integer-range arithmetic
201
+ (`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.
207
+ - **Refinement carriers** `Type::Difference`,
208
+ `Type::Refined`, `Type::Intersection` provide the
209
+ imported-built-in catalogue end-to-end through
210
+ `Builtins::ImportedRefinements`.
211
+ - **`RBS::Extended` directive routes** — `return:`, `param:`
212
+ (call-site + body-side), `assert:` /
213
+ `predicate-if-(true|false)` accept refinement payloads.
214
+
215
+ The full per-release surface lives in
216
+ [`CHANGELOG.md`](CHANGELOG.md). The internal contracts the
217
+ analyzer guarantees live under
218
+ [`docs/internal-spec/`](docs/internal-spec/).
219
+
220
+ ## Configuration
221
+
222
+ `rigor init` writes a starter `.rigor.yml`:
223
+
224
+ ```sh
225
+ bundle exec rigor init # fails if .rigor.yml exists
226
+ bundle exec rigor init --force # overwrite
227
+ ```
228
+
229
+ The configuration is intentionally small in v0.0.x; see the
230
+ generated file for the available knobs.
231
+
232
+ ## Status
233
+
234
+ Current release: **`v0.0.4`** (the fourth preview). The
235
+ analyzer is usable on real Ruby code today but the rule
236
+ catalogue is deliberately narrow — Rigor's stance is to surface
237
+ zero false positives while the inference surface stabilises.
238
+ The roadmap is tracked in
239
+ [`docs/MILESTONES.md`](docs/MILESTONES.md); release-by-release
240
+ detail lives in [`CHANGELOG.md`](CHANGELOG.md).
241
+
242
+ ## Contributing
243
+
244
+ See [`CONTRIBUTING.md`](CONTRIBUTING.md) for the minimal
245
+ `git clone` → green-tests path and a map of the spec / ADR /
246
+ skill documentation contributors should know about.
165
247
 
166
248
  ## License
167
249
 
168
- Rigor is licensed under the Mozilla Public License Version 2.0.
169
- See [LICENSE](LICENSE).
250
+ Mozilla Public License Version 2.0. See [`LICENSE`](LICENSE).
@@ -0,0 +1,87 @@
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/compar.c
6
+ ruby_prelude:
7
+ rbs:
8
+ - references/rbs/core/comparable.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
+ Comparable:
22
+ parent: Module
23
+ defined_at: references/ruby/compar.c:324
24
+ includes: []
25
+ constants: {}
26
+ aliases: {}
27
+ instance_methods:
28
+ "==":
29
+ source: c
30
+ cfunc: cmp_equal
31
+ arity: 1
32
+ defined_at: references/ruby/compar.c:325
33
+ c_body_at: references/ruby/compar.c:79
34
+ c_effects:
35
+ - dispatch
36
+ purity: dispatch
37
+ ">":
38
+ source: c
39
+ cfunc: cmp_gt
40
+ arity: 1
41
+ defined_at: references/ruby/compar.c:326
42
+ c_body_at: references/ruby/compar.c:105
43
+ c_effects: []
44
+ purity: leaf
45
+ ">=":
46
+ source: c
47
+ cfunc: cmp_ge
48
+ arity: 1
49
+ defined_at: references/ruby/compar.c:327
50
+ c_body_at: references/ruby/compar.c:119
51
+ c_effects: []
52
+ purity: leaf
53
+ "<":
54
+ source: c
55
+ cfunc: cmp_lt
56
+ arity: 1
57
+ defined_at: references/ruby/compar.c:328
58
+ c_body_at: references/ruby/compar.c:137
59
+ c_effects: []
60
+ purity: leaf
61
+ "<=":
62
+ source: c
63
+ cfunc: cmp_le
64
+ arity: 1
65
+ defined_at: references/ruby/compar.c:329
66
+ c_body_at: references/ruby/compar.c:156
67
+ c_effects: []
68
+ purity: leaf
69
+ between?:
70
+ source: c
71
+ cfunc: cmp_between
72
+ arity: 2
73
+ defined_at: references/ruby/compar.c:330
74
+ c_body_at: references/ruby/compar.c:177
75
+ c_effects: []
76
+ purity: leaf
77
+ clamp:
78
+ source: c
79
+ cfunc: cmp_clamp
80
+ arity: -1
81
+ defined_at: references/ruby/compar.c:331
82
+ c_body_at: references/ruby/compar.c:231
83
+ c_effects:
84
+ - raises
85
+ purity: leaf
86
+ singleton_methods: {}
87
+ undefined: []