class Curriculum
def unlocked_for(student) = …
def archived_books = …
end class Report
def legacy_totals = …
end archived_books is only reached by the spec
written for it, and legacy_totals by nothing at all, so both are greyed out in your editor.
The problem
Public methods are easy to add and hard to remove. Nobody’s sure whether anything still calls
Curriculum#archived_books, so it stays, gets tested, gets documented and gets maintained.
Static tools can’t settle it in Ruby. A method can be called through send, public_send, a
callback or a name built from a string, so “no references found” proves nothing.
Test-first code adds a subtler kind: methods you wrote a test for, made pass, and then nothing else ever needed. The spec calls it, so it looks alive. That’s speculative generality, and it’s worth knowing about while the method is still new.
The fix
In your editor, the method is greyed out with a hint:
class Curriculum
def unlocked_for(student) = eligible(student)
def archived_books = @archived.dup
# ⤷ only caller: spec/models/curriculum_spec.rb · no production code calls this
end
On the command line:
$ ra dead_api app/models
Curriculum#archived_books
only caller: its own spec (curriculum_spec.rb:40)
Report#legacy_totals
no caller in any recorded run
Delete the method and the spec that was keeping it alive:
class Curriculum
def unlocked_for(student) = eligible(student)
end
The suite stays green, because nothing but that spec ever needed it. If a rake task or a job you didn’t record does need it, you’ll find out when you record that run, not months later in a code review.
How it works
The recording wraps every method defined in your app, so a call is recorded however it was made:
directly, through send or public_send, or from a callback. dead_api lists each public method
and its recorded callers.
Two kinds get flagged:
- Methods with no recorded caller at all.
- Methods whose only callers are their own spec examples. Because each call tree is stamped with the
example that produced it, it can tell
curriculum_spec.rbcallingarchived_booksdirectly apart from production code calling it.
Limits
- Only as complete as what you recorded. A method called by a rake task, a rarely hit path or a job you didn’t run looks dead. Record those runs, or treat the result as a question rather than a verdict.
- A hint, not a deletion. It greys the method out and never removes it or fails a build.
- For proof from production,
prod_dead_apion the hosted tier pools real traffic across every deploy.
Related tools
split_interface
Split a fat interface. A class whose callers each use a different slice of it. It names the role interfaces to split it into, measured from who actually calls what.
See more →specs_that_reach
Run only the specs that matter. The spec examples whose recorded runs reach a method, so a change reruns those and nothing else. Keeps a red-green loop in seconds.
See more →observed_shape
The observed contract. The messages your code actually sends to a value, read from real runs. The interface a call depends on, whether or not anyone declared it.
See more →