rigortype 0.0.3 → 0.0.5

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 (48) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +215 -117
  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/hash.yml +936 -0
  9. data/data/builtins/ruby_core/range.yml +389 -0
  10. data/data/builtins/ruby_core/rational.yml +365 -0
  11. data/data/builtins/ruby_core/set.yml +594 -0
  12. data/data/builtins/ruby_core/string.yml +9 -0
  13. data/data/builtins/ruby_core/time.yml +752 -0
  14. data/lib/rigor/analysis/check_rules.rb +11 -3
  15. data/lib/rigor/builtins/imported_refinements.rb +192 -10
  16. data/lib/rigor/cli.rb +1 -1
  17. data/lib/rigor/inference/acceptance.rb +181 -12
  18. data/lib/rigor/inference/builtins/comparable_catalog.rb +27 -0
  19. data/lib/rigor/inference/builtins/complex_catalog.rb +41 -0
  20. data/lib/rigor/inference/builtins/date_catalog.rb +98 -0
  21. data/lib/rigor/inference/builtins/enumerable_catalog.rb +27 -0
  22. data/lib/rigor/inference/builtins/hash_catalog.rb +40 -0
  23. data/lib/rigor/inference/builtins/range_catalog.rb +46 -0
  24. data/lib/rigor/inference/builtins/rational_catalog.rb +38 -0
  25. data/lib/rigor/inference/builtins/set_catalog.rb +54 -0
  26. data/lib/rigor/inference/builtins/time_catalog.rb +64 -0
  27. data/lib/rigor/inference/method_dispatcher/constant_folding.rb +145 -11
  28. data/lib/rigor/inference/method_dispatcher/iterator_dispatch.rb +202 -1
  29. data/lib/rigor/inference/method_dispatcher/kernel_dispatch.rb +95 -0
  30. data/lib/rigor/inference/method_dispatcher/overload_selector.rb +23 -7
  31. data/lib/rigor/inference/method_dispatcher/shape_dispatch.rb +135 -6
  32. data/lib/rigor/inference/method_dispatcher.rb +3 -1
  33. data/lib/rigor/inference/method_parameter_binder.rb +29 -4
  34. data/lib/rigor/inference/narrowing.rb +211 -0
  35. data/lib/rigor/inference/scope_indexer.rb +87 -11
  36. data/lib/rigor/inference/statement_evaluator.rb +6 -0
  37. data/lib/rigor/rbs_extended.rb +170 -14
  38. data/lib/rigor/type/combinator.rb +90 -0
  39. data/lib/rigor/type/integer_range.rb +4 -2
  40. data/lib/rigor/type/intersection.rb +135 -0
  41. data/lib/rigor/type/refined.rb +174 -0
  42. data/lib/rigor/type.rb +2 -0
  43. data/lib/rigor/version.rb +1 -1
  44. data/sig/rigor/environment.rbs +4 -6
  45. data/sig/rigor/inference.rbs +2 -1
  46. data/sig/rigor/rbs_extended.rbs +11 -0
  47. data/sig/rigor/type.rbs +75 -35
  48. metadata +22 -1
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 72dac247bb2b31d9f2b226d392242da9b6db2b3ee5638f4a6f66e8739019e18b
4
- data.tar.gz: a39d687e673df117dc61182391a37a33b0a6c30e9489bd94549a7bf9ee8e5245
3
+ metadata.gz: 3b0e7446849097317ae0f4a26114036f41c4ad321abfcc492d25ac67995150b6
4
+ data.tar.gz: 95736bd636be7ba8698d4bf9a4cbdcbf870eaaf5a9117207f238f7429e064e94
5
5
  SHA512:
6
- metadata.gz: 4aa2cfec0a5c4fd968fe0071d29073ab2131e802a1749f23009e5845d9efebff2e5abe58e97882911c34fb90c9ef32858a47acf7bc64d4b98b91bc7c5acf7bc6
7
- data.tar.gz: 991d69e4ad0447c192c468ab13d387baee0334e401528b79676c9374b9b2137b6a3c4b3ada761e33e145ae963aee5fa6a8f7f84194a6c0b053bd1d4c39790507
6
+ metadata.gz: b16976fea05e9c4f9d9f9247e5858817e9938eff6329ce7e091f7c9196051170f3a36c528e6f6cb0386f4762c8b17302a6bb3a9df239e9385ec375a2c1b3a6ca
7
+ data.tar.gz: c8ac86259a502f4bfac5ef51464cf5eea45d599bdd3f9d164798b5b66a8257a8a117ea4e54b2314c27da9845a3723fa3fca61fe2f259988f2e19eb9b79c9df6d
data/README.md CHANGED
@@ -1,152 +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
14
-
15
- The current branch (`impl/scope-type-of`) is a **first preview**.
16
- The engine recognises the bulk of canonical Ruby surface — local
17
- variables, ivars / cvars / globals (intra- and cross-method), self
18
- typing, lexical constant lookup, predicate narrowing
19
- (`is_a?` / `==` / `===` / `case`-`when`), block parameter binding,
20
- closure escape, Tuple / HashShape carriers, and more. See
21
- [docs/CURRENT_WORK.md](docs/CURRENT_WORK.md) for the full slice
22
- trail.
23
-
24
- ## Requirements
25
-
26
- - Nix with the `nix-command` and `flakes` features available.
27
- - Ruby 4.0.x and Bundler 4.x, provided by the Flake development
28
- shell.
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
+ ```
29
36
 
30
- ## Setup
37
+ Install:
31
38
 
32
39
  ```sh
33
- nix --extra-experimental-features 'nix-command flakes' develop --command bundle install
34
- nix --extra-experimental-features 'nix-command flakes' develop --command bundle exec rake
40
+ bundle install
35
41
  ```
36
42
 
37
- For interactive development, enter the Flake shell first:
43
+ Or, for a one-off install outside Bundler:
38
44
 
39
45
  ```sh
40
- nix --extra-experimental-features 'nix-command flakes' develop
46
+ gem install rigortype
41
47
  ```
42
48
 
43
- ## Quick Start
49
+ The gem ships an executable named `rigor` (gem name is
50
+ `rigortype` because `rigor` was already taken on RubyGems).
44
51
 
45
- Inside the Flake shell:
52
+ **Ruby version.** The gemspec requires `>= 4.0.0, < 4.1`.
46
53
 
47
- ```sh
48
- # Show available subcommands.
49
- bundle exec exe/rigor help
54
+ ## First analysis
50
55
 
51
- # Print the inferred type at FILE:LINE:COL.
52
- bundle exec exe/rigor type-of lib/rigor/scope.rb:55:9
56
+ Drop into your project root and run the canonical commands:
53
57
 
54
- # Report Scope#type_of coverage across a tree.
55
- bundle exec exe/rigor type-scan lib
58
+ ```sh
59
+ # Diagnose unknown methods, wrong-arity calls, and other
60
+ # rule-driven bugs across `lib/`.
61
+ bundle exec rigor check lib
56
62
 
57
- # Diagnose unknown methods and wrong-arity calls on typed receivers.
58
- bundle exec exe/rigor check lib
63
+ # Print the inferred type at a precise FILE:LINE:COL position.
64
+ bundle exec rigor type-of lib/foo.rb:10:5
59
65
 
60
- # Write a starter .rigor.yml.
61
- bundle exec exe/rigor init
62
- ```
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
63
69
 
64
- ### Example diagnostics
70
+ # Drop a starter .rigor.yml into the project root.
71
+ bundle exec rigor init
72
+ ```
65
73
 
66
- `rigor check` reports the canonical type-check signals it can
67
- prove against the loaded RBS environment:
74
+ ### Sample output
68
75
 
69
76
  ```sh
70
77
  $ cat /tmp/demo.rb
71
- "hello".no_such_method # bug: undefined method
72
- [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
73
80
 
74
- $ bundle exec exe/rigor check /tmp/demo.rb
81
+ $ bundle exec rigor check /tmp/demo.rb
75
82
  /tmp/demo.rb:1:9: error: undefined method `no_such_method' for "hello"
76
83
  /tmp/demo.rb:2:11: error: wrong number of arguments to `rotate' on Array (given 2, expected 0..1)
77
84
  ```
78
85
 
79
- The rule catalogue is intentionally narrow: a diagnostic fires
80
- only when the receiver type is statically known and the method
81
- set on that class is enumerable through RBS or in-source `def` /
82
- `define_method` discovery. Implicit-self calls, dynamic
83
- receivers, and constant-decl alias classes (e.g. `YAML` → `Psych`)
84
- are skipped to avoid false positives.
85
-
86
- ## What works
87
-
88
- The first preview engine resolves:
89
-
90
- - **Local / instance / class / global variables** — intra-method
91
- bindings (`@x = 1; @x`), cross-method ivar / cvar accumulators
92
- (`def init; @x = 1; end; def get; @x; end`), program-wide
93
- globals.
94
- - **Compound writes** `||=`, `&&=`, `+=` and friends thread
95
- through scope for every variable kind.
96
- - **`self` typing** class- and method-body boundaries inject
97
- `Singleton[T]` / `Nominal[T]`; implicit-self call dispatch
98
- routes through the enclosing class's RBS.
99
- - **Constant lookup** lexical walk against `scope.self_type`,
100
- RBS-core, common stdlib (`pathname`, `optparse`, `json`,
101
- `yaml`, ...), the `prism` and `rbs` gems' RBS, in-source
102
- class discovery, and in-source constant value tracking
103
- (`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]`).
104
191
  - **Predicate narrowing** — truthiness, `nil?`, `is_a?` /
105
192
  `kind_of?` / `instance_of?`, finite-literal equality,
106
193
  case-equality (`===`) for Class / Module / Range / Regexp,
107
194
  `case` / `when` integration.
108
- - **Blocks** — parameter binding (incl. destructuring + numbered
109
- parameters), block-return-type uplift through generic methods
110
- (`Array#map { |n| n.to_s }` → `Array[String]`), closure escape
111
- classification, captured-local invalidation on escaping blocks.
112
195
  - **Tuple / HashShape carriers** — shape-aware element access,
113
- range / start-length slices, closed / open / required / optional
114
- policies threaded through `Acceptance`.
115
- - **`rigor check` first-preview rules** — undefined method on
116
- typed receiver, wrong number of positional arguments. Both
117
- consult RBS plus in-source `def` / `define_method` discovery so
118
- reopened classes do not produce false positives.
119
-
120
- See [docs/CURRENT_WORK.md](docs/CURRENT_WORK.md) for the canonical
121
- status snapshot, [docs/internal-spec/inference-engine.md](docs/internal-spec/inference-engine.md)
122
- for the engine contract, and [docs/adr/](docs/adr/) for the
123
- decision records.
124
-
125
- ## Project layout
126
-
127
- - `lib/rigor` — runtime library, type model, inference engine, CLI.
128
- - `lib/rigor/analysis` — `Runner`, `CheckRules`, `Diagnostic`,
129
- `FactStore`.
130
- - `lib/rigor/inference` `Scope`-driven typers, dispatchers, and
131
- narrowing.
132
- - `sig` RBS signatures for Rigor itself.
133
- - `spec` RSpec test suite (830+ examples).
134
- - `docs/adr` architecture decision records.
135
- - `docs/internal-spec` — engine contracts.
136
- - `docs/type-specification` — type-language semantics.
137
-
138
- ## Roadmap past first preview
139
-
140
- In rough priority order (see CURRENT_WORK.md for details):
141
-
142
- 1. More `rigor check` rules (nil-call, type-incompatible writes,
143
- unbound locals).
144
- 2. `RBS::Extended` effect plumbing (`%a{rigor:v1:pure}`,
145
- mutation / escape / call-timing effects).
146
- 3. Diagnostic publication for `FallbackTracer` events.
147
- 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.
148
247
 
149
248
  ## License
150
249
 
151
- Rigor is licensed under the Mozilla Public License Version 2.0.
152
- 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: []