method-ray 0.1.1 → 0.1.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8b9351553b262a65f3b398bbb715a2e9600f893e1ff12703c1e903942798201a
4
- data.tar.gz: 677baf919f242bc8e47a4b252f0ed929b64548bc6f873c58bb954b52515e0042
3
+ metadata.gz: b03f7efedd583d2cda9e59cd651ded78d5357c53eb06eac8980aae25db0529de
4
+ data.tar.gz: c02996cc2a511f800d34cec0ce46744c6ae2bddb8974e361f994a332b898c467
5
5
  SHA512:
6
- metadata.gz: b87a06709a8bb8dd57087f260a07a045c7f34f572d0595a4669d3d569d609d4076cfe7b2ae8897e67edb5e3d65c68a1259151e9ce40ce9b79f598430949c0450
7
- data.tar.gz: 33703cf7ae417499620b85081e0e95f4bd5049e91cb40c8e3f9c8a5f4f4ed60d2cdaa57475022abd090f7ae3bc5314eb37d27a8275cda6f35769807305bdb704
6
+ metadata.gz: 3aa19e8a26274f5d8c7b5b746e67f10d4e47ac281852251c737ebed4f933b5426e8b842d575f26110ee279fc48079a1dc382e78b2a184e0d4211d241dabae77a
7
+ data.tar.gz: '08e6b8bf49475c874538c007b52fec615459eb0c376357e1b2429868a67885eb695d261ba02d078b7fb0835321b92e84f06a6ac5366066379229b0e78072d786'
data/CHANGELOG.md CHANGED
@@ -5,6 +5,17 @@ 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.2] - 2025-01-19
9
+
10
+ ### Added
11
+
12
+ - Pre-built RBS cache bundled with gem (no initialization required)
13
+ - `MethodRay.setup` for cache generation (internal API)
14
+
15
+ ### Changed
16
+
17
+ - Separated `setup` logic from `infer_types` for cleaner cache generation
18
+
8
19
  ## [0.1.1] - 2025-01-19
9
20
 
10
21
  ### Added
@@ -19,5 +30,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
19
30
  - Initial release
20
31
  - `methodray check` - Static type checking for Ruby files
21
32
 
33
+ [0.1.2]: https://github.com/dak2/method-ray/releases/tag/v0.1.2
22
34
  [0.1.1]: https://github.com/dak2/method-ray/releases/tag/v0.1.1
23
35
  [0.1.0]: https://github.com/dak2/method-ray/releases/tag/v0.1.0
data/ext/src/lib.rs CHANGED
@@ -66,6 +66,18 @@ impl Analyzer {
66
66
  }
67
67
  }
68
68
 
69
+ /// Setup function that only generates RBS cache
70
+ /// This is used during gem build to pre-generate the cache
71
+ fn setup() -> Result<String, Error> {
72
+ let ruby = unsafe { Ruby::get_unchecked() };
73
+ let mut genv = GlobalEnv::new();
74
+
75
+ // This will load RBS and save to cache if not already cached
76
+ let count = rbs::register_rbs_methods(&mut genv, &ruby)?;
77
+
78
+ Ok(format!("RBS cache generated with {} methods", count))
79
+ }
80
+
69
81
  #[magnus::init]
70
82
  fn init(ruby: &Ruby) -> Result<(), Error> {
71
83
  let module = ruby.define_module("MethodRay")?;
@@ -75,5 +87,8 @@ fn init(ruby: &Ruby) -> Result<(), Error> {
75
87
  class.define_method("version", method!(Analyzer::version, 0))?;
76
88
  class.define_method("infer_types", method!(Analyzer::infer_types, 1))?;
77
89
 
90
+ // Module-level setup function for cache generation
91
+ module.define_singleton_method("setup", function!(setup, 0))?;
92
+
78
93
  Ok(())
79
94
  }
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MethodRay
4
- VERSION = '0.1.1'
4
+ VERSION = '0.1.2'
5
5
  end
data/rust/Cargo.toml CHANGED
@@ -37,3 +37,6 @@ magnus = { version = "0.8", optional = true }
37
37
  cli = ["clap", "notify"]
38
38
  lsp = ["tower-lsp", "tokio", "tempfile"]
39
39
  ruby-ffi = ["magnus"]
40
+
41
+ [dev-dependencies]
42
+ tempfile = "3.13"
@@ -39,7 +39,7 @@ impl SerializableMethodInfo {
39
39
 
40
40
  #[allow(dead_code)]
41
41
  impl RbsCache {
42
- /// Get cache file path
42
+ /// Get user cache file path (in ~/.cache/methodray/)
43
43
  pub fn cache_path() -> Result<PathBuf> {
44
44
  let cache_dir = dirs::cache_dir()
45
45
  .context("Failed to get cache directory")?
@@ -50,8 +50,42 @@ impl RbsCache {
50
50
  Ok(cache_dir.join("rbs_cache.bin"))
51
51
  }
52
52
 
53
+ /// Get bundled cache path (shipped with gem)
54
+ ///
55
+ /// Gem structure after install:
56
+ /// lib/methodray/
57
+ /// methodray-cli # CLI binary
58
+ /// methodray.bundle # FFI extension (macOS) or methodray.so (Linux)
59
+ /// rbs_cache.bin # Pre-built cache
60
+ ///
61
+ /// The CLI binary and cache are in the same directory.
62
+ fn bundled_cache_path() -> Option<PathBuf> {
63
+ if let Ok(exe_path) = std::env::current_exe() {
64
+ if let Some(exe_dir) = exe_path.parent() {
65
+ // Cache is in the same directory as CLI binary
66
+ let bundled = exe_dir.join("rbs_cache.bin");
67
+ if bundled.exists() {
68
+ return Some(bundled);
69
+ }
70
+ }
71
+ }
72
+ None
73
+ }
74
+
53
75
  /// Load cache from disk
76
+ /// Tries bundled cache first, then user cache
54
77
  pub fn load() -> Result<Self> {
78
+ // Try bundled cache first (shipped with gem)
79
+ if let Some(bundled_path) = Self::bundled_cache_path() {
80
+ if let Ok(bytes) = fs::read(&bundled_path) {
81
+ if let Ok(cache) = bincode::deserialize::<Self>(&bytes) {
82
+ eprintln!("Loaded bundled cache from {}", bundled_path.display());
83
+ return Ok(cache);
84
+ }
85
+ }
86
+ }
87
+
88
+ // Fall back to user cache
55
89
  let path = Self::cache_path()?;
56
90
  let bytes = fs::read(&path)
57
91
  .with_context(|| format!("Failed to read cache from {}", path.display()))?;
@@ -121,6 +155,7 @@ impl RbsCache {
121
155
  #[cfg(test)]
122
156
  mod tests {
123
157
  use super::*;
158
+ use tempfile::tempdir;
124
159
 
125
160
  #[test]
126
161
  fn test_cache_serialization() {
@@ -155,4 +190,113 @@ mod tests {
155
190
  assert!(!cache.is_valid("0.2.0", "3.7.0"));
156
191
  assert!(!cache.is_valid("0.1.0", "3.8.0"));
157
192
  }
193
+
194
+ #[test]
195
+ fn test_serializable_method_info_return_type() {
196
+ let method_info = SerializableMethodInfo {
197
+ receiver_class: "String".to_string(),
198
+ method_name: "upcase".to_string(),
199
+ return_type_str: "String".to_string(),
200
+ };
201
+
202
+ let return_type = method_info.return_type();
203
+ assert_eq!(return_type.show(), "String");
204
+ }
205
+
206
+ #[test]
207
+ fn test_cache_methods_accessor() {
208
+ let cache = RbsCache {
209
+ version: "0.1.0".to_string(),
210
+ rbs_version: "3.7.0".to_string(),
211
+ methods: vec![
212
+ SerializableMethodInfo {
213
+ receiver_class: "String".to_string(),
214
+ method_name: "upcase".to_string(),
215
+ return_type_str: "String".to_string(),
216
+ },
217
+ SerializableMethodInfo {
218
+ receiver_class: "Integer".to_string(),
219
+ method_name: "to_s".to_string(),
220
+ return_type_str: "String".to_string(),
221
+ },
222
+ ],
223
+ timestamp: SystemTime::now(),
224
+ };
225
+
226
+ let methods = cache.methods();
227
+ assert_eq!(methods.len(), 2);
228
+ assert_eq!(methods[0].receiver_class, "String");
229
+ assert_eq!(methods[0].method_name, "upcase");
230
+ assert_eq!(methods[1].receiver_class, "Integer");
231
+ assert_eq!(methods[1].method_name, "to_s");
232
+ }
233
+
234
+ #[test]
235
+ fn test_cache_save_and_load() {
236
+ let temp_dir = tempdir().unwrap();
237
+ let cache_path = temp_dir.path().join("test_cache.bin");
238
+
239
+ let original_cache = RbsCache {
240
+ version: "0.1.0".to_string(),
241
+ rbs_version: "3.7.0".to_string(),
242
+ methods: vec![
243
+ SerializableMethodInfo {
244
+ receiver_class: "String".to_string(),
245
+ method_name: "upcase".to_string(),
246
+ return_type_str: "String".to_string(),
247
+ },
248
+ SerializableMethodInfo {
249
+ receiver_class: "Array".to_string(),
250
+ method_name: "first".to_string(),
251
+ return_type_str: "Object".to_string(),
252
+ },
253
+ ],
254
+ timestamp: SystemTime::now(),
255
+ };
256
+
257
+ // Save to temp file
258
+ let bytes = bincode::serialize(&original_cache).unwrap();
259
+ fs::write(&cache_path, &bytes).unwrap();
260
+
261
+ // Load from temp file
262
+ let loaded_bytes = fs::read(&cache_path).unwrap();
263
+ let loaded_cache: RbsCache = bincode::deserialize(&loaded_bytes).unwrap();
264
+
265
+ assert_eq!(loaded_cache.version, "0.1.0");
266
+ assert_eq!(loaded_cache.rbs_version, "3.7.0");
267
+ assert_eq!(loaded_cache.methods.len(), 2);
268
+ assert_eq!(loaded_cache.methods[0].method_name, "upcase");
269
+ assert_eq!(loaded_cache.methods[1].method_name, "first");
270
+ }
271
+
272
+ #[test]
273
+ fn test_cache_with_empty_methods() {
274
+ let cache = RbsCache {
275
+ version: "0.1.0".to_string(),
276
+ rbs_version: "3.7.0".to_string(),
277
+ methods: vec![],
278
+ timestamp: SystemTime::now(),
279
+ };
280
+
281
+ let bytes = bincode::serialize(&cache).unwrap();
282
+ let deserialized: RbsCache = bincode::deserialize(&bytes).unwrap();
283
+
284
+ assert_eq!(deserialized.methods.len(), 0);
285
+ assert!(deserialized.is_valid("0.1.0", "3.7.0"));
286
+ }
287
+
288
+ #[test]
289
+ fn test_cache_validation_version_mismatch() {
290
+ let cache = RbsCache {
291
+ version: "0.1.0".to_string(),
292
+ rbs_version: "3.7.0".to_string(),
293
+ methods: vec![],
294
+ timestamp: SystemTime::now(),
295
+ };
296
+
297
+ // Both versions must match
298
+ assert!(!cache.is_valid("0.1.1", "3.7.0"));
299
+ assert!(!cache.is_valid("0.1.0", "3.7.1"));
300
+ assert!(!cache.is_valid("0.2.0", "4.0.0"));
301
+ }
158
302
  }
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: method-ray
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - dak2