원클릭으로
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 페이지를 검토하고 설치를 진행할 수 있습니다.
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.
SOC 직업 분류 기준
| 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