Languages / Ruby
Ruby and Rails code analysis: dead code, complexity and call graphs
Ruby has no compiler to find dead code, so tools like debride list methods that are never called by name. repowise resolves require, require_relative and Rails autoload paths, links routes.rb resources to controllers and model associations to model files, and ranks unused files by git history, with const_get and send treated as signs of dynamic use.
Last reviewed: November 2026
Full tier
What repowise detects in Ruby
Checked against the engine source. Every row runs locally with zero LLM calls.
| Files parsed | .rb |
|---|---|
| Import resolution | Full. require_relative, $LOAD_PATH probes such as lib/, Rails and Zeitwerk autoload roots, Gemfile and gemspec gems as external nodes |
| Call graph | Resolved calls and inheritance |
| Dead code | Unreachable files and unused exports; dynamic dispatch lowers confidence |
| Health markers | Complexity, class metrics and test smells |
| Performance markers | ActiveRecord N+1: find_by, pluck, update_all inside each or map blocks; where on a model constant; generic verbs only with database evidence |
| Coverage reports | lcov or Cobertura from SimpleCov formatters, Clover |
| Frameworks recognised | Rails routes.rb resources and namespaces to controllers, belongs_to, has_many, has_one and habtm to model files |
Specific to this language
How Ruby code is read
Rails autoload is resolved
Rails code rarely calls require: Zeitwerk loads constants from app/ by name. repowise resolves autoload roots, so a model used as User in a controller is an edge to app/models/user.rb.
Routes and associations are edges
resources :orders inside a namespace in routes.rb links to the matching controller file. belongs_to, has_many, has_one and has_and_belongs_to_many link a model to the associated model's file.
Dynamic Ruby is a signal
const_get, Kernel.const_get, send(:require ...), Object.send and public_send near a file lower its confidence, so metaprogrammed code lands in the review tier.
Honest comparison
Native Ruby tools, and when they are enough
| Tool | What it covers |
|---|---|
| debride | Methods that are defined and never called by name. Simple and fast; needs whitelists for Rails. |
| RuboCop | Style and Metrics cops, including CyclomaticComplexity and AbcSize. |
| flog, flay, Reek | Complexity scores, duplication and code smells. |
| SimpleCov | Coverage for test suites; with an lcov or Cobertura formatter, repowise reads it. |
| Coverband | Production code usage for Rails: what actually runs in production. |
Where repowise adds value
- File-level dead code with Rails routes, autoload and associations understood, ranked by git history.
- ActiveRecord N+1 markers on the same files as hotspots and churn.
- Ownership and co-change: who knows a model, and which files change with it.
- One graph with the JavaScript or TypeScript frontend in the same repository.
How to run it
Analyse a Ruby repository
From the repository root. Agents get the same results through the get_dead_code, get_health and get_context MCP tools.
uv tool install repowise # or: pipx install repowise
repowise init --yes --no-prose # index the repo, no API key
repowise dead-code --min-confidence 0.7 --safe-only
repowise health --refactoring-targets
bundle exec rspec # SimpleCov with the simplecov-cobertura formatter
repowise coverage add coverage/coverage.xml
repowise serve # graph, health and dead code in a local dashboardQuestions
What people ask before they try it.
How do I find unused code in a Rails app?
Run repowise dead-code. Controllers reached from routes.rb, models reached through associations and autoloaded constants are live; files nothing reaches are reported with a confidence that starts from git history. For runtime proof, pair it with Coverband in production.
Does it understand Zeitwerk?
Yes. Rails and Zeitwerk autoload roots are part of import resolution, so constant references resolve to files without require.
Does it detect N+1 queries?
It flags ActiveRecord calls inside loops and block iterators (each, map) as a static marker. It is not a runtime profiler like Bullet; distinctive verbs such as find_by and pluck fire without extra evidence.
Does repowise send my Ruby code to an LLM?
No. Parsing, the call graph, dead code, health scores, performance markers and git history all run locally with zero LLM calls. repowise init --yes --no-prose needs no API key, and the analysis itself makes no network calls. Written documentation prose is the one opt-in step that uses a model, and it can run on a local Ollama model.
Related reading
Index a Ruby repository.
Public repositories are free on repowise.dev. The CLI is open source and runs on your machine with no API key.