One engine, many tools — Introducing Rubydex
https://railsatscale.com/2026-05-12-one-engine-many-tools/
Vinicius StockによるRubyの静的解析エンジンRubydexについての記事
背景: 基盤的構成要素の重複実装問題
数年前、新しいRubyパーサPrismがリリースされた
目的は複数のパーサ実装が乱立していた状況をコミュニティとして統一すること
単一パーサ化によりパフォーマンス・正確性への投資が全ツールに波及する
同じ問題が一段上のコードインデックス・静的解析レイヤーでも繰り返されている
言語サーバ: Ruby LSPやSolargraphがgo to definition・hover・補完などに利用
型チェッカー: SorbetやSteepが型チェックのために利用
ドキュメント生成: RDocやYARDが宣言を集約するために利用
デッドコード検出: Spoomやdebrideが宣言と参照を突合して未使用宣言を特定
リンター: RuboCopやStandardは未使用だが、コードベース全体の知識があればより高度なリントが可能
各実装でパフォーマンス・実装・正確性に差異があり、ポータブルなAPIとして提供されていない
コミュニティの労力が分散している状態
Rubydexとは
コードインデックスや型解析を便利なAPI経由で提供する、ポータブルな静的解析エンジン
ツールそのものではなく、他ツールを作るためのフレームワーク/エンジンである
開発初期段階ながら以下が可能
クラス・モジュール・定数・特異クラス・各種変数・メソッドなど全定義の収集
RBSドキュメントのインデックス(core・stdlib・ワークスペース内のRBS含む)
定数解決、定数・インスタンス変数参照の追跡
発見した定義と定数参照からの宣言生成
祖先チェーンの線形化、子孫の追跡、グラフへの多様なクエリ
ポータビリティのための設計
異なる言語やWASM経由のブラウザ向けツール作成を可能にすることが目標
Rust・C・Rubyで構築し、3つの異なるコンポーネントを出荷
メインのRustクレート: 全ロジックを実装。高パフォーマンスと容易な並列処理が利点
FFIクレート: C互換バインディングを提供し、他言語からの統合を可能にする
Rubyのgem: ネイティブ拡張でRuby APIを提供。主要プラットフォーム向けのコンパイル済みバイナリを同梱
他プラットフォームではcargoに依存してコンパイルする
既存ツールへの影響
共通の成果は「パフォーマンス向上・正確性向上・保守コードの削減」
Tapioca
Tapiocaはランタイム解析に加え静的情報も消費する
RBIに含める宣言のドキュメント取得、gem RBI生成の初期解析のブートストラップ
YARDベースのドキュメント処理をRubydexに置き換え
Core monolithでのgem RBI生成時間が約6分から約20秒に短縮、メモリ使用も大幅減
定数解決アルゴリズムの正確性によりコメントが意図した宣言に確実に紐付くようになった
Tapioca v0.19.0から利用可能
Packwerk
Packwerkはパッケージ違反の特定に定数解決を多用する
Rubyの定数解決はアルゴリズムが複雑でエッジケースが多く、正しく実装するのが難しい
Rubydexへの置き換えの初期検証で battle tested なアルゴリズムの再利用効果を確認
コードベース約-3000行の削減
正確な定数解決により約3倍の定数参照を解決し、より多くの違反を検出
条件次第でパフォーマンス改善(シングルスレッド vs 並列)
Spoom
Spoomのデッドコード候補検出の移行を試作開始
定数解決と祖先を正しく扱えるため高速・高精度
移行途中で「これをRubydex本体に取り込むべきでは」という問いが生じた
デッドコード検出はコアエンジンの一部になり得ると判断し、移行を一旦停止して取り込みを検討中
Ruby LSP
Rubydexが旧コードインデクサを全面的に置き換え、より高速かつ正確に
直接影響する機能
go to definition・hover・signature help: ネスト解決の改善で精度向上
補完: 新エンジンが従来より大幅に良い結果
workspace symbol: 新しいファジー検索が高速化
型階層: 祖先情報がより完全に。子孫トラッカーでサブタイプ機能を実装可能に
find references・rename: Rubydexが自動追跡するため高速
Foundation: 十分高速なためインデックスを同期処理でき、レースコンディションを排除しコードを簡素化
新たに可能になった改善
セマンティックハイライトで定数参照をclass/namespace/variable.constantに正しく分類可能に
Minitest::Test継承クラスとtest_接頭辞メソッドの特定が容易になり、globパターンに頼らないテスト探索が可能に
アドオンはほとんどが破壊的変更となるため、移行手順はドキュメント・リリースノートを参照
MCPサーバ
LLMがコードベースを効率的に探索するための実験的MCPサーバを同梱
ファイル全体の読み込みやテキストgrepの代わりに、宣言・定義・参照・祖先・子孫を直接問い合わせ可能
現状はソースからビルドが必要だが、将来的にgemの一部として出荷予定
初期テストで特定のLLMタスクにおいてトークン使用量・コスト・所要時間が15〜80%削減
例: リファクタリング時にコードベース全体を走査せず、使用箇所を直接問い合わせできる
現在のAPI
Ruby LSP・Tapioca・Packwerk等の用途を支える広範なAPI
基本的な流れ
Rubydex::Graph.newでグラフ生成 → index_workspaceでインデックス → resolveで定義を宣言に変換
graph["Foo"]で宣言取得し.ancestors/.descendantsを照会
graph.searchでメソッド検索、graph.resolve_constantでネスト内の定数解決
今後の計画
共有データベース: 解析結果をDBに保存
ブート時間削減(毎回ゼロから解析しない)
部分データのロードでメモリ使用を削減し、ツール数に対し線形にスケールしないようにする
言語サーバ・MCPサーバ・リンター・型チェッカーが同一DBを共有して同時稼働可能に
セマンティックリンティング: 解析データを使った高度な