method-ray 0.1.4 → 0.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +28 -0
- data/ext/Cargo.toml +1 -1
- data/ext/src/lib.rs +38 -59
- data/lib/methodray/cli.rb +1 -0
- data/lib/methodray/commands.rb +0 -1
- data/lib/methodray/version.rb +1 -1
- data/rust/Cargo.toml +1 -1
- data/rust/src/analyzer/attributes.rs +2 -2
- data/rust/src/analyzer/conditionals.rs +72 -0
- data/rust/src/analyzer/definitions.rs +385 -8
- data/rust/src/analyzer/dispatch.rs +31 -12
- data/rust/src/analyzer/install.rs +18 -0
- data/rust/src/analyzer/literals.rs +45 -0
- data/rust/src/analyzer/mod.rs +3 -0
- data/rust/src/analyzer/operators.rs +192 -0
- data/rust/src/analyzer/parentheses.rs +113 -0
- data/rust/src/analyzer/returns.rs +191 -0
- data/rust/src/checker.rs +2 -4
- data/rust/src/cli/args.rs +1 -1
- data/rust/src/env/global_env.rs +3 -4
- data/rust/src/env/scope.rs +21 -0
- data/rust/src/graph/box.rs +4 -2
- data/rust/src/main.rs +1 -0
- data/rust/src/rbs/loader.rs +3 -4
- data/rust/src/rbs/mod.rs +29 -0
- metadata +4 -1
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: ee779223feab7110e29256fdc4860ba480d13d676d18e85284fd0765eef2cc4b
|
|
4
|
+
data.tar.gz: 249087d8f6b7772aa7428a4828ffc35eacb1b0aa8b27d5cd909b803176d6a683
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 8d6534a955eaf4937c5ebc4c525e07f5f7cd8599861f128cbb10161e00a6a932f1b47760e1283e7e2f48940ea0a89bb5c038ac83cdd8ce8a629f8f91b05e534a
|
|
7
|
+
data.tar.gz: cbe0d247ffcbd0ce4965f9e20a2293336aca3d7a6eeb96878665cb7692e11ea4366d3c1f2a87ea32711dbcd00a404d4a41da3e84d34829d40568ec0bb37d74b4
|
data/CHANGELOG.md
CHANGED
|
@@ -5,6 +5,32 @@ All notable changes to this project will be documented in this file.
|
|
|
5
5
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
6
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
7
|
|
|
8
|
+
## [0.1.6] - 2026-02-23
|
|
9
|
+
|
|
10
|
+
### Fixed
|
|
11
|
+
|
|
12
|
+
- Embed `method_loader.rb` at compile time with `include_str!` to eliminate runtime dependency on source directory ([#35](https://github.com/dak2/method-ray/pull/35))
|
|
13
|
+
|
|
14
|
+
## [0.1.5] - 2026-02-23
|
|
15
|
+
|
|
16
|
+
### Added
|
|
17
|
+
|
|
18
|
+
- String interpolation type inference (`InterpolatedStringNode`, `InterpolatedSymbolNode`, `InterpolatedRegularExpressionNode`) ([#26](https://github.com/dak2/method-ray/pull/26))
|
|
19
|
+
- Parentheses node type inference for parenthesized expressions ([#27](https://github.com/dak2/method-ray/pull/27))
|
|
20
|
+
- Qualified name method registration to resolve namespace conflicts ([#28](https://github.com/dak2/method-ray/pull/28))
|
|
21
|
+
- Return statement type inference with merge vertex pattern ([#29](https://github.com/dak2/method-ray/pull/29))
|
|
22
|
+
- Ternary operator type inference tests ([#30](https://github.com/dak2/method-ray/pull/30))
|
|
23
|
+
- Logical operator (`&&`/`||`) type inference with union type approximation ([#31](https://github.com/dak2/method-ray/pull/31))
|
|
24
|
+
- Class method (`def self.foo`) type registration and checking ([#32](https://github.com/dak2/method-ray/pull/32))
|
|
25
|
+
|
|
26
|
+
### Changed
|
|
27
|
+
|
|
28
|
+
- Removed stateless `Analyzer` class and simplified Ruby FFI surface to module functions ([#33](https://github.com/dak2/method-ray/pull/33))
|
|
29
|
+
|
|
30
|
+
### Deprecated
|
|
31
|
+
|
|
32
|
+
- `clear_cache` command ([#25](https://github.com/dak2/method-ray/pull/25))
|
|
33
|
+
|
|
8
34
|
## [0.1.4] - 2026-02-16
|
|
9
35
|
|
|
10
36
|
### Added
|
|
@@ -69,6 +95,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
69
95
|
- Initial release
|
|
70
96
|
- `methodray check` - Static type checking for Ruby files
|
|
71
97
|
|
|
98
|
+
[0.1.6]: https://github.com/dak2/method-ray/releases/tag/v0.1.6
|
|
99
|
+
[0.1.5]: https://github.com/dak2/method-ray/releases/tag/v0.1.5
|
|
72
100
|
[0.1.4]: https://github.com/dak2/method-ray/releases/tag/v0.1.4
|
|
73
101
|
[0.1.3]: https://github.com/dak2/method-ray/releases/tag/v0.1.3
|
|
74
102
|
[0.1.2]: https://github.com/dak2/method-ray/releases/tag/v0.1.2
|
data/ext/Cargo.toml
CHANGED
data/ext/src/lib.rs
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
//!
|
|
3
3
|
//! This module provides the Ruby gem interface using magnus.
|
|
4
4
|
|
|
5
|
-
use magnus::{function,
|
|
5
|
+
use magnus::{function, prelude::*, Error, Ruby};
|
|
6
6
|
use methodray_core::{
|
|
7
7
|
analyzer::AstInstaller,
|
|
8
8
|
env::{GlobalEnv, LocalEnv},
|
|
@@ -10,86 +10,65 @@ use methodray_core::{
|
|
|
10
10
|
rbs,
|
|
11
11
|
};
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
Self { path }
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
fn version(&self) -> String {
|
|
25
|
-
"0.1.0".to_string()
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
/// Execute type inference
|
|
29
|
-
fn infer_types(&self, source: String) -> Result<String, Error> {
|
|
30
|
-
// Parse
|
|
31
|
-
let session = ParseSession::new();
|
|
32
|
-
let parse_result = session.parse_source(&source, "source.rb").map_err(|e| {
|
|
33
|
-
let ruby = unsafe { Ruby::get_unchecked() };
|
|
34
|
-
Error::new(ruby.exception_runtime_error(), e.to_string())
|
|
35
|
-
})?;
|
|
13
|
+
/// Type inference (public module function)
|
|
14
|
+
fn infer_types(source: String) -> Result<String, Error> {
|
|
15
|
+
// Parse
|
|
16
|
+
let session = ParseSession::new();
|
|
17
|
+
let parse_result = session.parse_source(&source, "source.rb").map_err(|e| {
|
|
18
|
+
let ruby = unsafe { Ruby::get_unchecked() };
|
|
19
|
+
Error::new(ruby.exception_runtime_error(), e.to_string())
|
|
20
|
+
})?;
|
|
36
21
|
|
|
37
|
-
|
|
38
|
-
|
|
22
|
+
// Build graph
|
|
23
|
+
let mut genv = GlobalEnv::new();
|
|
39
24
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
25
|
+
// Register built-in methods from RBS
|
|
26
|
+
let ruby = unsafe { Ruby::get_unchecked() };
|
|
27
|
+
rbs::register_rbs_methods(&mut genv, &ruby)?;
|
|
43
28
|
|
|
44
|
-
|
|
45
|
-
|
|
29
|
+
let mut lenv = LocalEnv::new();
|
|
30
|
+
let mut installer = AstInstaller::new(&mut genv, &mut lenv, &source);
|
|
46
31
|
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
}
|
|
32
|
+
// Process AST
|
|
33
|
+
let root = parse_result.node();
|
|
34
|
+
if let Some(program_node) = root.as_program_node() {
|
|
35
|
+
let statements = program_node.statements();
|
|
36
|
+
for stmt in &statements.body() {
|
|
37
|
+
installer.install_node(&stmt);
|
|
54
38
|
}
|
|
39
|
+
}
|
|
55
40
|
|
|
56
|
-
|
|
41
|
+
installer.finish();
|
|
57
42
|
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
}
|
|
43
|
+
// Return results as string
|
|
44
|
+
let mut results = Vec::new();
|
|
45
|
+
for (var_name, vtx_id) in lenv.all_vars() {
|
|
46
|
+
if let Some(vtx) = genv.get_vertex(*vtx_id) {
|
|
47
|
+
results.push(format!("{}: {}", var_name, vtx.show()));
|
|
64
48
|
}
|
|
65
|
-
|
|
66
|
-
Ok(results.join("\n"))
|
|
67
49
|
}
|
|
50
|
+
|
|
51
|
+
Ok(results.join("\n"))
|
|
68
52
|
}
|
|
69
53
|
|
|
70
|
-
///
|
|
71
|
-
|
|
72
|
-
fn setup() -> Result<String, Error> {
|
|
54
|
+
/// RBS cache generation (executed when requiring methodray/setup)
|
|
55
|
+
fn setup() -> Result<(), Error> {
|
|
73
56
|
let ruby = unsafe { Ruby::get_unchecked() };
|
|
74
57
|
let mut genv = GlobalEnv::new();
|
|
75
58
|
|
|
76
59
|
// This will load RBS and save to cache if not already cached
|
|
77
|
-
|
|
60
|
+
rbs::register_rbs_methods(&mut genv, &ruby)?;
|
|
78
61
|
|
|
79
|
-
Ok(
|
|
62
|
+
Ok(())
|
|
80
63
|
}
|
|
81
64
|
|
|
82
65
|
#[magnus::init]
|
|
83
66
|
fn init(ruby: &Ruby) -> Result<(), Error> {
|
|
84
67
|
let module = ruby.define_module("MethodRay")?;
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
class.define_singleton_method("new", function!(Analyzer::new, 1))?;
|
|
88
|
-
class.define_method("version", method!(Analyzer::version, 0))?;
|
|
89
|
-
class.define_method("infer_types", method!(Analyzer::infer_types, 1))?;
|
|
68
|
+
module.define_singleton_method("infer_types", function!(infer_types, 1))?;
|
|
90
69
|
|
|
91
|
-
//
|
|
92
|
-
|
|
70
|
+
// require methodray/setup to generate RBS cache on Ruby side
|
|
71
|
+
setup()?;
|
|
93
72
|
|
|
94
73
|
Ok(())
|
|
95
74
|
}
|
data/lib/methodray/cli.rb
CHANGED
data/lib/methodray/commands.rb
CHANGED
|
@@ -14,7 +14,6 @@ module MethodRay
|
|
|
14
14
|
methodray version # Show version
|
|
15
15
|
methodray check [FILE] [OPTIONS] # Type check a Ruby file
|
|
16
16
|
methodray watch FILE # Watch file for changes and auto-check
|
|
17
|
-
methodray clear-cache # Clear RBS method cache
|
|
18
17
|
|
|
19
18
|
Examples:
|
|
20
19
|
methodray check app/models/user.rb
|
data/lib/methodray/version.rb
CHANGED
data/rust/Cargo.toml
CHANGED
|
@@ -18,10 +18,10 @@ pub(crate) fn process_attr_declaration(
|
|
|
18
18
|
kind: AttrKind,
|
|
19
19
|
attr_names: Vec<String>,
|
|
20
20
|
) {
|
|
21
|
-
let Some(
|
|
21
|
+
let Some(qualified_name) = genv.scope_manager.current_qualified_name() else {
|
|
22
22
|
return;
|
|
23
23
|
};
|
|
24
|
-
let recv_ty = Type::instance(&
|
|
24
|
+
let recv_ty = Type::instance(&qualified_name);
|
|
25
25
|
|
|
26
26
|
for attr_name in attr_names {
|
|
27
27
|
let ivar_name = format!("@{}", attr_name);
|
|
@@ -463,4 +463,76 @@ end
|
|
|
463
463
|
let ret_vtx = info.return_vertex.unwrap();
|
|
464
464
|
assert_eq!(get_type_show(&genv, ret_vtx), "String");
|
|
465
465
|
}
|
|
466
|
+
|
|
467
|
+
// Test 11: ternary operator - different types → union
|
|
468
|
+
#[test]
|
|
469
|
+
fn test_ternary_union_type() {
|
|
470
|
+
let source = r#"
|
|
471
|
+
class Foo
|
|
472
|
+
def bar
|
|
473
|
+
true ? "hello" : 42
|
|
474
|
+
end
|
|
475
|
+
end
|
|
476
|
+
"#;
|
|
477
|
+
let genv = analyze(source);
|
|
478
|
+
let info = genv
|
|
479
|
+
.resolve_method(&Type::instance("Foo"), "bar")
|
|
480
|
+
.expect("Foo#bar should be registered");
|
|
481
|
+
let ret_vtx = info.return_vertex.unwrap();
|
|
482
|
+
assert_eq!(get_type_show(&genv, ret_vtx), "(Integer | String)");
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
// Test 12: ternary operator - same type → single type
|
|
486
|
+
#[test]
|
|
487
|
+
fn test_ternary_same_type() {
|
|
488
|
+
let source = r#"
|
|
489
|
+
class Foo
|
|
490
|
+
def bar
|
|
491
|
+
true ? "hello" : "world"
|
|
492
|
+
end
|
|
493
|
+
end
|
|
494
|
+
"#;
|
|
495
|
+
let genv = analyze(source);
|
|
496
|
+
let info = genv
|
|
497
|
+
.resolve_method(&Type::instance("Foo"), "bar")
|
|
498
|
+
.expect("Foo#bar should be registered");
|
|
499
|
+
let ret_vtx = info.return_vertex.unwrap();
|
|
500
|
+
assert_eq!(get_type_show(&genv, ret_vtx), "String");
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
// Test 13: ternary operator - nil branch → union with nil
|
|
504
|
+
#[test]
|
|
505
|
+
fn test_ternary_nil_branch() {
|
|
506
|
+
let source = r#"
|
|
507
|
+
class Foo
|
|
508
|
+
def bar
|
|
509
|
+
true ? "hello" : nil
|
|
510
|
+
end
|
|
511
|
+
end
|
|
512
|
+
"#;
|
|
513
|
+
let genv = analyze(source);
|
|
514
|
+
let info = genv
|
|
515
|
+
.resolve_method(&Type::instance("Foo"), "bar")
|
|
516
|
+
.expect("Foo#bar should be registered");
|
|
517
|
+
let ret_vtx = info.return_vertex.unwrap();
|
|
518
|
+
assert_eq!(get_type_show(&genv, ret_vtx), "(String | nil)");
|
|
519
|
+
}
|
|
520
|
+
|
|
521
|
+
// Test 14: nested ternary operator
|
|
522
|
+
#[test]
|
|
523
|
+
fn test_ternary_nested() {
|
|
524
|
+
let source = r#"
|
|
525
|
+
class Foo
|
|
526
|
+
def bar
|
|
527
|
+
true ? (false ? "inner" : 42) : :sym
|
|
528
|
+
end
|
|
529
|
+
end
|
|
530
|
+
"#;
|
|
531
|
+
let genv = analyze(source);
|
|
532
|
+
let info = genv
|
|
533
|
+
.resolve_method(&Type::instance("Foo"), "bar")
|
|
534
|
+
.expect("Foo#bar should be registered");
|
|
535
|
+
let ret_vtx = info.return_vertex.unwrap();
|
|
536
|
+
assert_eq!(get_type_show(&genv, ret_vtx), "(Integer | String | Symbol)");
|
|
537
|
+
}
|
|
466
538
|
}
|