feat(ruby): Add Ruby language support for CLI and web#111
Conversation
Add Ruby as the 11th supported language in GitNexus, enabling code intelligence for Ruby codebases. This includes: - Tree-sitter parsing for classes, modules, methods, and singleton methods - Import extraction for require/require_relative via call post-processing - Mixin heritage detection for include/extend/prepend - attr_accessor/attr_reader/attr_writer property extraction - Ruby-specific built-in filtering (Kernel methods + enumerables) - Framework detection for lib/, bin/, exe/, and Rake patterns - Entry point scoring for service objects, jobs, and CLI commands - Test file detection for _spec.rb, _test.rb, and spec/ directories - WASM grammar for web version Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
@candidosales is attempting to deploy a commit to the NexusCore Team on Vercel. A member of the Team first needs to authorize it. |
|
@abhigyanpatwari when you get a chance, could you review it? 🙇 |
|
Sure will look into it. Would you join the discord https://discord.gg/f3DAmGZb its getting difficult to manage stuff so created discord |
…ed modules Conflicts resolved by taking upstream refactored shared module approach (extractFunctionName, isBuiltInOrNoise, isNodeExported from utils.js and export-detection.js) while preserving Ruby-specific call handling (require, include/extend/prepend, attr_accessor) and adding Ruby to the language matrix.
|
@claude review this pr and recommend a him the best way to migrate his ruby implementation into our current architucture. |
|
Claude finished @magyargergo's task in 3m 2s —— View job Ruby Implementation Migration AnalysisTasks:
Review SummaryThis is a solid Ruby implementation that works end-to-end, but it has 4 architectural friction points that need to be resolved before merging. The core issue is that Ruby's unconventional grammar (everything-is-a-call) is handled with ad-hoc conditionals scattered across 3 files rather than following the patterns other languages use. Issue 1: Critical — Triplicated Ruby Routing LogicThe require/include/attr_* routing logic is duplicated in three separate files with slightly different implementations:
Each copy is subtly different — the sequential Recommended fix: Extract the routing logic into a shared helper in // gitnexus/src/core/ingestion/utils.ts
export type RubyCallRouting =
| { kind: 'import'; importPath: string }
| { kind: 'heritage'; enclosingClass: string; mixinName: string }
| { kind: 'property'; propName: string; startLine: number; endLine: number }
| { kind: 'call' }
| { kind: 'skip' };
export function routeRubyCall(calledName: string, callNode: any): RubyCallRouting { ... }Then import and call this helper from all three locations. Issue 2: Critical — Sequential Path Bypasses
|
CI Report✅ All checks passed Pipeline Status
Test Results✅ 1609 passed Code CoverageCombined (Unit + Integration)
Coverage breakdown by test suiteUnit Tests
Integration Tests
Coverage thresholds are auto-ratcheted — they only go upVitest 📋 View full run · Generated by CI |
|
@claude can you please design the ingestion integration tests similarly to other languages like c/c++? We need as much coverage as we can get for ruby. |
|
Claude finished @magyargergo's task in 8m 6s —— View job Ruby Integration Tests DesignTasks:
What was added
Design notes mirroring C/C++
|
|
@magyargergo it's ready 👍 |
|
Hi @candidosales, While working on my PR #274 I merged #111 into master and then into my branch, which gave me a chance to test the Ruby graph building end-to-end. I found a few issues worth flagging: 1. Ruby methods not recognised as function scopes (fixed in #274)
2. Bare Ruby method calls are not captured (tree-sitter limitation) This is the main finding. In Ruby it's idiomatic to call methods without a receiver or parentheses , e.g. 3. Ruby receiver extraction not wired up (minor)
Current state: 10 Ruby resolver integration tests passing, 3 marked as todo due to the bare call limitation. I also moved all Ruby-specific call routing logic into Happy to discuss any of this further! |
Summary
require/require_relative) with proper path handlinginclude/extend/prepend) routed asIMPLEMENTSedgesattr_accessor/attr_reader/attr_writer_spec.rb,_test.rb,/spec/) in MCP impact toolWhat changed
Core parsing (both CLI + web):
tree-sitter-queries.ts— new Ruby query capturing classes, modules, methods, singleton methods, calls, and heritageparsing-processor.ts— Ruby export detection (all symbols public by default)utils.ts— file extension + extensionless filename mapping (Rakefile,Gemfile, etc.)parser-loader.ts— Ruby WASM grammar registrationCall resolution (both CLI + web):
call-processor.ts— Ruby-specific routing:require/require_relativeskipped (handled by import-processor),include/extend/prepend→IMPLEMENTSedges,attr_*→Propertynodesimport-processor.ts— Rubyrequire/require_relativecaptured from@callnodes (Ruby grammar doesn't produce@importcaptures)CLI worker thread:
parse-worker.ts— Full Ruby call routing in the worker path (heritage, properties, import-like calls)Scoring & detection (both CLI + web):
entry-point-scoring.ts— Ruby entry point patterns:call,perform,executeframework-detection.ts— Ruby bin/exe detection, Rake tasksMCP layer:
local-backend.ts—isTestFilePathnow filters_spec.rb,_test.rb,/spec/Config:
supported-languages.ts—Ruby = 'ruby'added to enumtree-sitter-ruby.wasm— WASM grammar binary for webDesign decisions
Ruby calls routed in call-processor, not heritage-processor — Ruby's tree-sitter grammar captures
include/extend/prependas generic@callnodes, not@heritage. The routing lives in call-processor since it already iterates@callcaptures.All mixin types use
trait-impl→IMPLEMENTS—include,extend, andprependall add module methods to a class/module. None represent true class inheritance (EXTENDS), so all three map toIMPLEMENTS.Ruby imports in import-processor —
require/require_relativeare routed to import-processor (not just filtered as built-ins) soimportMapgets populated before call resolution, enabling high-confidence (0.9) import-resolved call edges.Removed
lib/framework boost — Every.rbfile underlib/was getting a 1.5x entry point multiplier, which conflicts withisUtilityFile(). Removed to avoid scoring contradictions.Removed
initializeandrunfrom entry points —initializeis a constructor (called implicitly), not an entry point.runis too generic and creates false positives.Test plan
npx gitnexus analyzeon a Ruby/Rails codebase and verify:require/require_relativecreateIMPORTSedgesinclude/extend/prependcreateIMPLEMENTSedgesattr_*createPropertynodesCALLSedges with appropriate confidenceimpact({ includeTests: false })filters Ruby spec filescall/perform/executemethods higherDemo
Tested with Fizzy
How test it?
Syntax Highlight at Code inspector