ワンクリックで
refactor
Refactor Ruby Fast LSP modules, extract abstractions, reduce complexity, and preserve test coverage during structural changes.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
メニュー
Refactor Ruby Fast LSP modules, extract abstractions, reduce complexity, and preserve test coverage during structural changes.
Codex または Claude でインストール この Prompt をコピーして Codex、Claude、または他のアシスタントに貼り付けると、Skill ページを確認してインストールできます。
SOC 職業分類に基づく
Design Ruby Fast LSP features, understand module responsibilities, apply layer boundaries, and make structural changes.
Create, update, validate, and maintain Ruby Fast LSP C4 architecture diagrams using LikeC4.
Implement or review error handling patterns in Ruby Fast LSP, including Result, Option, logging, failures, and exception flows.
Optimize Ruby Fast LSP performance, profile latency and memory, benchmark changes, and make performance-critical decisions.
Release a new version of ruby-fast-lsp. Bumps version in Cargo.toml, commits, tags, and pushes to trigger CI. Use when the user says /release, 'release', 'publish', 'bump version', 'cut a release', or 'new version'.
Review Ruby Fast LSP code changes and PRs using TigerStyle principles, project standards, and correctness checks.
| name | refactor |
| description | Refactor Ruby Fast LSP modules, extract abstractions, reduce complexity, and preserve test coverage during structural changes. |
Use this skill when breaking down large modules, extracting abstractions, or simplifying complex code in the Ruby Fast LSP project. Provides strategies for safe refactoring while maintaining test coverage. Triggers: refactor, split module, extract, simplify, break down, too long, complexity, modularize.
Current modules exceeding complexity limits:
| File | Lines | Target | Priority |
|---|---|---|---|
analyzer_prism/mod.rs | 2420 | 800 | High |
capabilities/completion/mod.rs | 2231 | 500 | High |
inferrer/return_type.rs | 1661 | 500 | Medium |
inferrer/cfg/builder.rs | 1467 | 500 | Medium |
inferrer/cfg/engine.rs | 1142 | 500 | Medium |
indexer/coordinator.rs | 1108 | 500 | Medium |
test/harness/check.rs | 1307 | 500 | Low |
cargo testcargo testcargo clippycargo fmt --checkFor large files with distinct logical sections.
Current structure (2420 lines, monolithic):
// mod.rs contains everything:
// - Identifier enum (50 lines)
// - MethodReceiver enum (80 lines)
// - RubyPrismAnalyzer struct (2000+ lines)
// - Helper functions (200+ lines)
Target structure:
analyzer_prism/
├── mod.rs # Re-exports, 50 lines
├── identifier.rs # Identifier enum + Display, 100 lines
├── method_receiver.rs # MethodReceiver enum, 100 lines
├── analyzer.rs # RubyPrismAnalyzer, 800 lines max
├── visitors/
│ ├── mod.rs
│ ├── definition.rs # Definition extraction
│ ├── reference.rs # Reference tracking
│ └── scope.rs # Scope management
└── helpers.rs # Utility functions, 200 lines
Steps:
// analyzer_prism/identifier.rs
#[derive(Debug, Clone, PartialEq, Eq)]
pub enum Identifier {
Constant(String, Range),
Method(String, Range),
// ...
}
impl std::fmt::Display for Identifier { ... }
// analyzer_prism/mod.rs
mod identifier;
mod method_receiver;
mod analyzer;
pub use identifier::Identifier;
pub use method_receiver::MethodReceiver;
pub use analyzer::RubyPrismAnalyzer;
Run tests: cargo test analyzer
Repeat for each extraction
For long functions that do multiple things.
Identify extraction points:
Example: Long function
// BEFORE: 150 lines
fn process_method_call(&mut self, node: &MethodCall) {
// Extract receiver (30 lines)
let receiver = ...;
// Resolve method (50 lines)
let method = ...;
// Check arguments (40 lines)
for arg in node.args() {
...
}
// Build result (30 lines)
...
}
AFTER: 20 lines + 4 helpers
fn process_method_call(&mut self, node: &MethodCall) {
let receiver = self.extract_receiver(node);
let method = self.resolve_method(&receiver, node.name());
self.check_arguments(node, &method);
self.build_call_result(receiver, method)
}
fn extract_receiver(&self, node: &MethodCall) -> MethodReceiver { ... }
fn resolve_method(&self, receiver: &MethodReceiver, name: &str) -> Option<Method> { ... }
fn check_arguments(&mut self, node: &MethodCall, method: &Method) { ... }
fn build_call_result(&self, receiver: MethodReceiver, method: Option<Method>) -> CallResult { ... }
For polymorphic behavior or shared interfaces.
Current: One large module with match statements
// BEFORE
fn get_completions(context: &Context) -> Vec<CompletionItem> {
match context.trigger {
Trigger::Constant => complete_constants(context),
Trigger::Method => complete_methods(context),
Trigger::Variable => complete_variables(context),
// ... more cases
}
}
AFTER: Trait-based strategies
// completion/strategy.rs
pub trait CompletionStrategy {
fn applies(&self, context: &Context) -> bool;
fn complete(&self, context: &Context) -> Vec<CompletionItem>;
}
// completion/strategies/constant.rs
pub struct ConstantStrategy;
impl CompletionStrategy for ConstantStrategy { ... }
// completion/strategies/method.rs
pub struct MethodStrategy;
impl CompletionStrategy for MethodStrategy { ... }
// completion/mod.rs
fn get_completions(context: &Context) -> Vec<CompletionItem> {
STRATEGIES.iter()
.filter(|s| s.applies(context))
.flat_map(|s| s.complete(context))
.collect()
}
For long parameter lists or repeated data groupings.
BEFORE:
fn find_at_position(
index: &Index,
uri: &Url,
position: Position,
document: &Document,
include_declaration: bool,
) -> Vec<Location> { ... }
AFTER:
struct PositionContext<'a> {
index: &'a Index,
uri: &'a Url,
position: Position,
document: &'a Document,
}
impl PositionContext<'_> {
fn find_definitions(&self) -> Vec<Location> { ... }
fn find_references(&self, include_declaration: bool) -> Vec<Location> { ... }
}
For functions that do sequential phases.
BEFORE: One 500-line function
fn index_workspace(&mut self) {
// Phase 1: Collect definitions (200 lines)
for file in files {
// ...
}
// Phase 2: Resolve references (200 lines)
for file in files {
// ...
}
// Phase 3: Build graphs (100 lines)
// ...
}
AFTER: Separate phase functions
fn index_workspace(&mut self) {
let definitions = self.phase1_collect_definitions();
let references = self.phase2_resolve_references(&definitions);
self.phase3_build_graphs(&definitions, &references);
}
fn phase1_collect_definitions(&self) -> DefinitionMap { ... }
fn phase2_resolve_references(&self, defs: &DefinitionMap) -> ReferenceMap { ... }
fn phase3_build_graphs(&mut self, defs: &DefinitionMap, refs: &ReferenceMap) { ... }
Problem: "While I'm here, let me fix this bug..." Solution: Separate commits. Refactor first, then fix.
Problem: Renaming public functions breaks callers.
Solution: Use pub(crate) for internal APIs. Deprecate before removing.
Problem: 50 tiny functions that are hard to follow. Solution: Extract for reuse or clarity, not just line count.
Problem: Extracted function has unclear purpose. Solution: Name clearly, add doc comments.
// BAD
fn helper1(x: &Node) -> bool { ... }
// GOOD
/// Returns true if the node represents a method definition.
fn is_method_definition(node: &Node) -> bool { ... }
For modules like analyzer_prism/mod.rs (2420 lines):
Identifier enum to identifier.rsMethodReceiver to method_receiver.rshelpers.rsvisitors/ submodule