Rails cto static analysis
Run Reek, Flog, and Flay static analysis on changed Ruby files and auto-refactor when issues are found. Use after modifying any .rb file. Also use when the user mentions "reek", "flog", "flay", "code smells", "complexity", "duplication", "static analysis", or "refactor". Proactively invoke this skill after code changes, even if the user doesn't ask.From its SKILL.md
npx -y skills add mattsears/rails-cto --skill rails-cto-static-analysisAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 14 stars14 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
SKILL.md
12.1 KB, as published. Nobody here has run it
Static Analysis (Reek, Flog, Flay)
Every .rb change is analyzed with Reek, Flog, and Flay before the work is considered done. Code smells are fixed, complex methods are refactored, and duplication is eliminated. This skill runs before RuboCop and tests — refactor first, then lint and verify.
Pre-flight
Check tool availability
Before running any analysis, verify each tool is installed. Run all three checks:
bundle exec reek --version 2>/dev/null
bundle exec ruby -e "require 'flog'" 2>/dev/null
bundle exec flay --version 2>/dev/null
Note: Flog does not support a --version flag. Use require 'flog' to verify it's installed.
If a tool is not available, print this message and skip that tool's steps (but continue with the others):
[tool]is not installed. Add it to your Gemfile under:development:gem "[tool]", require: falseThen run
bundle install.
If none of the three tools are available, stop and inform the user that static analysis cannot run.
Install .reek.yml if missing
Check for a Reek configuration file:
ls .reek.yml 2>/dev/null
If .reek.yml does not exist, create it with the Rails-friendly defaults from the Configuration section below. If it already exists, leave it as-is.
Identify changed files
Collect all .rb files that have been created or modified:
git diff --name-only --diff-filter=ACMR HEAD 2>/dev/null | grep -E '\.rb$' | sort -u
git diff --name-only --diff-filter=ACMR 2>/dev/null | grep -E '\.rb$' | sort -u
Combine and deduplicate both lists. If no .rb files changed, skip all scans and report "No Ruby files changed — static analysis skipped."
Step 1: Method Documentation Check
Every Ruby method must have a comment directly above the def line describing why it exists — not what it does (the code shows that). Focus on intent, context, or the business reason.
Scan changed files
For each changed .rb file, scan for def declarations and verify a comment appears on the line(s) immediately above. If any methods are missing a comment, add one before proceeding.
What a good comment looks like
# Ensures the user sees their most relevant posts first,
# because recently active tags reflect current interests.
def prioritized_posts
posts.joins(:tags).order("tags.updated_at DESC")
end
# Strips tracking parameters so we store clean URLs
# and don't leak referral data to downstream services.
def sanitize_url(url)
URI.parse(url).tap { |u| u.query = nil }.to_s
end
What to skip
Do not add comments to trivial or framework-conventional methods where intent is self-evident:
initializewith simple assignment- Single-line delegation (
delegate :name, to: :user) - Accessor-style methods (
def name = @name) - Standard Rails callbacks already named descriptively (
before_save :normalize_email) - Empty method stubs or
super-only overrides - Test methods (
it,test,describeblocks)
Auto-fix
For each undocumented method, read the method body and write a one-line comment explaining why the method exists. If the reason isn't clear from context, write what it does and flag it for the user to refine. After adding comments, move on to Reek.
Step 2: Reek — Code Smell Detection
Run Reek on each changed file individually:
bundle exec reek path/to/changed_file.rb
For multiple changed files:
bundle exec reek app/models/user.rb app/commands/users/create.rb app/controllers/users_controller.rb
Interpreting Reek output
Reek reports warnings in this format:
app/models/user.rb -- 2 warnings:
[4]:UncommunicativeMethodName: User#x has the name 'x'
[12]:TooManyStatements: User#process has approx 15 statements
Use this table to decide what to fix and how:
| Smell | When it's real | Auto-fix |
|---|---|---|
TooManyStatements | > 10 statements in a non-migration method | Extract into private methods or a service/command object |
LongParameterList | > 4 parameters | Introduce keyword arguments or a parameter object |
FeatureEnvy | Method uses another object's data more than its own | Move the method to the object it references most |
DataClump | 3+ methods share the same parameter group | Extract a value object |
DuplicateMethodCall | Same call appears 3+ times in one method | Extract to a local variable |
UncommunicativeVariableName | Single-letter or cryptic names | Rename to something descriptive |
UncommunicativeMethodName | Single-letter or cryptic names | Rename to something descriptive |
NilCheck | Explicit nil? checks | Fix only if it masks a real nil-safety issue — often noise in Rails |
UtilityFunction | Method doesn't use self | Fix in models and services; ignore in helpers and decorators |
TooManyInstanceVariables | > 6 instance variables in a class | Extract a value object or split responsibilities |
TooManyMethods | > 20 methods in a class | Extract concerns or split into smaller classes |
ControlCouple | Method behavior depends on a boolean/flag arg | Replace with two methods or use polymorphism — ignore in controllers |
BooleanParameter | def method(flag = true) | Replace with two methods — ignore in controllers and helpers |
Auto-fix rules
- For each Reek warning, apply the fix from the table above.
- Refactor silently when the fix is internal (Extract Method, rename, extract local variable).
- Ask the user first if the fix would rename a public method, change a method signature, or move a method to a different class.
- After fixing, re-run Reek on the file to verify the smell is gone.
Step 3: Flog — Complexity Measurement
Run Flog on each changed file individually:
bundle exec flog path/to/changed_file.rb
Interpreting Flog output
Flog outputs a pain score per method, sorted by complexity:
47.2: User#process app/models/user.rb:12-45
18.3: User#validate_email app/models/user.rb:50-62
6.1: User#name app/models/user.rb:8-10
Higher scores mean more complex, harder-to-maintain code.
| Score | Verdict | Action |
|---|---|---|
| ≤ 10 | Trivial | No action needed |
| 11–25 | Acceptable | No action needed |
| 26–60 | Too complex | Must refactor — extract methods, simplify conditionals, reduce nesting |
| > 60 | Severe | Stop and refactor immediately — this method is a maintenance hazard |
Auto-fix for high Flog scores
For methods scoring above 25:
- Identify complexity drivers — nested conditionals, long method chains, multiple responsibilities, deeply nested blocks.
- Apply Extract Method — pull cohesive blocks into private methods with descriptive names.
- Simplify conditionals — replace nested
if/elsewith guard clauses, early returns, orcasestatements. - Split responsibilities — if a method does more than one thing, extract a command or service object.
- Re-run Flog to verify the score dropped below 25.
If the score remains above 25 after one refactoring pass, report the method and its score to the user and move on.
Step 4: Flay — Duplication Detection
Flay identifies structural similarities in code, ignoring surface-level differences like variable names, literal values, and whitespace.
Determine scan scope
For each changed .rb file, collect its sibling files:
- Identify the parent directory of the changed file (e.g.,
app/models/forapp/models/user.rb). - Collect all
.rbfiles in that directory. - If the directory contains more than 20
.rbfiles, limit to the changed file plus the 10 most recently modified siblings:ls -t app/models/*.rb | head -10 - If only one
.rbfile exists in the directory, skip Flay for that file — duplication detection requires at least two files.
Run Flay
bundle exec flay app/models/*.rb
Or with a specific set of files:
bundle exec flay app/models/user.rb app/models/account.rb app/models/profile.rb
Interpreting Flay output
Flay reports structural duplication with a mass score:
1) IDENTICAL code found in :defn (mass = 72)
app/models/user.rb:15
app/models/account.rb:22
2) Similar code found in :defn (mass = 32)
app/controllers/users_controller.rb:10
app/controllers/accounts_controller.rb:12
| Mass | Verdict | Action |
|---|---|---|
| < 16 | Insignificant | No action needed |
| 16–50 | Moderate duplication | Extract shared logic into a concern, module, or shared method |
| > 50 | Significant duplication | Must extract — this is copy-paste code that will drift |
Auto-fix for duplication
For nodes with mass ≥ 16:
- Read both locations — understand the duplicated structure.
- Choose an extraction target:
- Models → shared concern in
app/models/concerns/ - Controllers → controller concern in
app/controllers/concerns/ - Commands/services → shared module or base class
- Same file → private method
- Models → shared concern in
- Extract the shared logic into the chosen target.
- Include the concern or module in both original locations.
- Re-run Flay to verify the mass dropped below 16.
If the duplication spans fundamentally different contexts where extraction would be forced or artificial, report it to the user instead of extracting.
Verify and summarize
After all three tools have run and fixes have been applied:
- Re-run all three tools on the changed files to confirm fixes took effect.
- Produce a brief summary:
**Static Analysis Summary**
- Reek: N smells found, N fixed, N remaining
- Flog: N methods above threshold (25), N refactored
- Flay: N duplications (mass ≥ 16), N extracted
- Status: PASS / NEEDS ATTENTION
PASS means all issues were resolved or no issues were found. NEEDS ATTENTION means some issues remain that require manual intervention — list them with file, line, and description.
Configuration
.reek.yml — Rails-friendly defaults
If the project has no .reek.yml, create this file in the project root:
---
# Rails-friendly Reek configuration
# Generated by rails-cto-static-analysis
detectors:
IrresponsibleModule:
enabled: false
InstanceVariableAssumption:
enabled: false
TooManyStatements:
max_statements: 10
ControlCouple:
exclude:
- !ruby/regexp /app\/controllers/
BooleanParameter:
exclude:
- !ruby/regexp /app\/controllers/
- !ruby/regexp /app\/helpers/
FeatureEnvy:
exclude:
- !ruby/regexp /app\/helpers/
- !ruby/regexp /app\/decorators/
UtilityFunction:
exclude:
- !ruby/regexp /app\/helpers/
- !ruby/regexp /app\/decorators/
UncommunicativeMethodName:
accept:
- e
- t
- q
- x
- y
LongParameterList:
max_params: 4
TooManyInstanceVariables:
max_instance_variables: 6
TooManyMethods:
max_methods: 20
directories:
"test":
enabled: false
"db/migrate":
TooManyStatements:
enabled: false
FeatureEnvy:
enabled: false
Thresholds summary
| Tool | Metric | Threshold | Action |
|---|---|---|---|
| Reek | Code smell | Any warning | Auto-fix per interpretation table |
| Flog | Method complexity | > 25 per method | Must refactor |
| Flog | Severe complexity | > 60 per method | Stop and refactor immediately |
| Flay | Structural duplication | Mass ≥ 16 | Extract shared logic |
Quick Reference
| Task | Command |
|---|---|
| Scan one file for smells | bundle exec reek path/to/file.rb |
| Scan one file for complexity | bundle exec flog path/to/file.rb |
| Scan directory for duplication | bundle exec flay path/to/dir/*.rb |
| Scan specific files for duplication | bundle exec flay file1.rb file2.rb |