diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 5b9f984..0dfa1eb 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -80,7 +80,7 @@ jobs: - name: Generate RBS cache run: | echo "Generating RBS cache..." - ruby -I lib -rmethodray -e 'MethodRay.setup' + ruby -I lib -rmethodray -e '1' # Copy cache to lib directory for bundling # macOS uses ~/Library/Caches, Linux uses ~/.cache if [[ "${{ runner.os }}" == "macOS" ]]; then diff --git a/ext/src/lib.rs b/ext/src/lib.rs index 09fd988..bc99111 100644 --- a/ext/src/lib.rs +++ b/ext/src/lib.rs @@ -2,7 +2,7 @@ //! //! This module provides the Ruby gem interface using magnus. -use magnus::{function, method, prelude::*, Error, Ruby}; +use magnus::{function, prelude::*, Error, Ruby}; use methodray_core::{ analyzer::AstInstaller, env::{GlobalEnv, LocalEnv}, @@ -10,86 +10,65 @@ use methodray_core::{ rbs, }; -#[magnus::wrap(class = "MethodRay::Analyzer")] -pub struct Analyzer { - #[allow(dead_code)] - path: String, -} - -impl Analyzer { - fn new(path: String) -> Self { - Self { path } - } - - fn version(&self) -> String { - "0.1.0".to_string() - } - - /// Execute type inference - fn infer_types(&self, source: String) -> Result { - // Parse - let session = ParseSession::new(); - let parse_result = session.parse_source(&source, "source.rb").map_err(|e| { - let ruby = unsafe { Ruby::get_unchecked() }; - Error::new(ruby.exception_runtime_error(), e.to_string()) - })?; +/// Type inference (public module function) +fn infer_types(source: String) -> Result { + // Parse + let session = ParseSession::new(); + let parse_result = session.parse_source(&source, "source.rb").map_err(|e| { + let ruby = unsafe { Ruby::get_unchecked() }; + Error::new(ruby.exception_runtime_error(), e.to_string()) + })?; - // Build graph - let mut genv = GlobalEnv::new(); + // Build graph + let mut genv = GlobalEnv::new(); - // Register built-in methods from RBS - let ruby = unsafe { Ruby::get_unchecked() }; - rbs::register_rbs_methods(&mut genv, &ruby)?; + // Register built-in methods from RBS + let ruby = unsafe { Ruby::get_unchecked() }; + rbs::register_rbs_methods(&mut genv, &ruby)?; - let mut lenv = LocalEnv::new(); - let mut installer = AstInstaller::new(&mut genv, &mut lenv, &source); + let mut lenv = LocalEnv::new(); + let mut installer = AstInstaller::new(&mut genv, &mut lenv, &source); - // Process AST - let root = parse_result.node(); - if let Some(program_node) = root.as_program_node() { - let statements = program_node.statements(); - for stmt in &statements.body() { - installer.install_node(&stmt); - } + // Process AST + let root = parse_result.node(); + if let Some(program_node) = root.as_program_node() { + let statements = program_node.statements(); + for stmt in &statements.body() { + installer.install_node(&stmt); } + } - installer.finish(); + installer.finish(); - // Return results as string - let mut results = Vec::new(); - for (var_name, vtx_id) in lenv.all_vars() { - if let Some(vtx) = genv.get_vertex(*vtx_id) { - results.push(format!("{}: {}", var_name, vtx.show())); - } + // Return results as string + let mut results = Vec::new(); + for (var_name, vtx_id) in lenv.all_vars() { + if let Some(vtx) = genv.get_vertex(*vtx_id) { + results.push(format!("{}: {}", var_name, vtx.show())); } - - Ok(results.join("\n")) } + + Ok(results.join("\n")) } -/// Setup function that only generates RBS cache -/// This is used during gem build to pre-generate the cache -fn setup() -> Result { +/// RBS cache generation (executed when requiring methodray/setup) +fn setup() -> Result<(), Error> { let ruby = unsafe { Ruby::get_unchecked() }; let mut genv = GlobalEnv::new(); // This will load RBS and save to cache if not already cached - let count = rbs::register_rbs_methods(&mut genv, &ruby)?; + rbs::register_rbs_methods(&mut genv, &ruby)?; - Ok(format!("RBS cache generated with {} methods", count)) + Ok(()) } #[magnus::init] fn init(ruby: &Ruby) -> Result<(), Error> { let module = ruby.define_module("MethodRay")?; - let class = module.define_class("Analyzer", ruby.class_object())?; - - class.define_singleton_method("new", function!(Analyzer::new, 1))?; - class.define_method("version", method!(Analyzer::version, 0))?; - class.define_method("infer_types", method!(Analyzer::infer_types, 1))?; + module.define_singleton_method("infer_types", function!(infer_types, 1))?; - // Module-level setup function for cache generation - module.define_singleton_method("setup", function!(setup, 0))?; + // require methodray/setup to generate RBS cache on Ruby side + setup()?; Ok(()) } diff --git a/rust/src/checker.rs b/rust/src/checker.rs index 3693da9..cd68743 100644 --- a/rust/src/checker.rs +++ b/rust/src/checker.rs @@ -17,8 +17,7 @@ impl FileChecker { // Just verify cache exists use crate::cache::RbsCache; RbsCache::load().context( - "Failed to load RBS cache. Please run from Ruby first to generate cache:\n\ - ruby -rmethodray -e 'MethodRay::Analyzer.new(\".\").infer_types(\"x=1\")'", + "Failed to load RBS cache.", )?; Ok(Self {}) @@ -70,8 +69,7 @@ fn load_rbs_from_cache(genv: &mut GlobalEnv) -> Result<()> { use crate::types::Type; let cache = RbsCache::load().context( - "Failed to load RBS cache. Please run from Ruby first to generate cache:\n\ - ruby -rmethodray -e 'MethodRay::Analyzer.new(\".\").infer_types(\"x=1\")'", + "Failed to load RBS cache.", )?; let methods = cache.methods(); diff --git a/test/test_helper.rb b/test/test_helper.rb index f9ad4d1..0567b93 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,9 +1,6 @@ $LOAD_PATH.unshift File.expand_path("../lib", __dir__) require "methodray" -# Ensure RBS cache exists before any test runs (CheckTest CLI tests depend on it) -MethodRay.setup - require "minitest/autorun" require "tempfile" require "open3" @@ -12,8 +9,7 @@ module CLITestHelper private def infer(source) - analyzer = MethodRay::Analyzer.new("test") - result = analyzer.infer_types(source) + result = MethodRay.infer_types(source) types = {} result.each_line do |line| line = line.strip