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.

repowise capabilities for Ruby
Files parsed.rb
Import resolutionFull. require_relative, $LOAD_PATH probes such as lib/, Rails and Zeitwerk autoload roots, Gemfile and gemspec gems as external nodes
Call graphResolved calls and inheritance
Dead codeUnreachable files and unused exports; dynamic dispatch lowers confidence
Health markersComplexity, class metrics and test smells
Performance markersActiveRecord N+1: find_by, pluck, update_all inside each or map blocks; where on a model constant; generic verbs only with database evidence
Coverage reportslcov or Cobertura from SimpleCov formatters, Clover
Frameworks recognisedRails 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

Native Ruby analysis tools
ToolWhat it covers
debrideMethods that are defined and never called by name. Simple and fast; needs whitelists for Rails.
RuboCopStyle and Metrics cops, including CyclomaticComplexity and AbcSize.
flog, flay, ReekComplexity scores, duplication and code smells.
SimpleCovCoverage for test suites; with an lcov or Cobertura formatter, repowise reads it.
CoverbandProduction 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 dashboard

Questions

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.

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.