runtimeanalyz.ing ● early access · sign-up open

← All capabilities

what_calls

CLI · LSP · MCP free

Who can call this method. Every caller of a method from real runs, with where and how often. The calls that actually happened, not grep. what_it_calls does the reverse.

Invoice app code
debit ( total Money )
invoice.rb:41 · 1,204 calls
Finance::Accounts receives
module Finance
  class Accounts
    def debit(amount, memo:) = …
  end
end
Transfer app code
public_send ( :debit Symbol )
transfer.rb:9 · 388 calls
Refund app code
debit ( amount Money )
refund.rb:22 · 57 calls
NightlyFeesJob grep match only
debit_fees!
a different method
Each recorded edge names the method that made the call, the line it was made from, and the method that received it. A call through public_send lands on the same wrapper as a direct one, and a name that only looks similar never does.

The problem

You’re about to change Finance::Accounts#debit. Before you touch it, you want to know who calls it. So you search:

$ grep -rn "debit" app lib
app/models/finance/accounts.rb:14:    def debit(amount, memo:)
app/models/invoice.rb:41:      accounts.debit(total, memo: number)
app/services/refund.rb:22:      ledger.debit(amount, memo: "refund #{id}")
app/services/transfer.rb:9:     public_send(direction, amount, memo:)
app/jobs/nightly_fees_job.rb:17: account.debit_fees!
spec/models/finance/accounts_spec.rb:8: ...

That’s the wrong answer in both directions. ledger.debit in Refund might be a Finance::Accounts, or it might be a Ledger with its own #debit. debit_fees! matches the string and has nothing to do with it. And Transfer calls it through public_send(direction, ...), which grep can only find if you already know to look.

An agent asked the same question does the same search, and gets the same list wrong.

The fix

Ask the recording instead:

$ ra what_calls Finance::Accounts#debit

Finance::Accounts#debit · 4 callers in 3 recorded runs

  Invoice#settle            app/models/invoice.rb:41        1,204 calls
  Transfer#call             app/services/transfer.rb:9        388 calls  via public_send
  Refund#process            app/services/refund.rb:22          57 calls
  accounts_spec.rb:8        its own spec                        6 calls

not callers: Ledger#debit is a different method on a different class

Four real callers, including the one hidden behind public_send, and none of the noise. Now the change has a scope: three pieces of app code and a spec.

what_it_calls is the same question the other way round:

$ ra what_it_calls Finance::Accounts#debit

  Finance::Accounts#balance       1,655 calls
  Finance::Entry.create!          1,655 calls
  Finance::Accounts#overdrawn?      412 calls

Where it shows up

  • Your editor (LSP). “Find references” and the call hierarchy view come from the recording, so they list the callers that ran, with counts.
  • Your agent (MCP). what_calls is the first thing to ask before editing a method, and it answers in one call instead of a page of grep.
  • The command line. ra what_calls and ra what_it_calls, taking any Class#method or Class.method.

How it works

Every call into a method defined in your app is recorded as an edge: the method that made the call, the file and line it was made from, and the method that received it. what_calls groups those edges by the receiving method and counts them.

Because the recorder wraps the method itself rather than reading source, it doesn’t matter how the call was made. A direct call, send, public_send, a callback or a method name built from a string all arrive at the same wrapper, so they all land in the same place.

The receiver’s class is part of the edge, so Accounts#debit and Ledger#debit are two methods, not one string.

Limits

  • Only what ran. A caller on a path nothing exercised in any recorded run isn’t listed. Record more of your suite, or your app, and it appears.
  • App methods only. Calls into your own classes are recorded. A caller inside a gem that calls back into your code shows up at the point it enters your code, not by its own name.
  • Counts are traffic in what you recorded. 1,204 calls in your test suite says how often the specs went through it, not how often production does.

how_it_got_here

CLI · MCP free

How execution got here. The real call chains that reach a method, in order, taken from recorded runs. The stack trace you'd have got if it had raised, on demand, for every route in.

See more →

what_a_change_touches

CLI · MCP free

What a change touches. Every caller that relies on a method's observed shape, the argument classes it passes and the messages it sends to what comes back, so you know what a signature change reaches before you make it.

See more →

dead_api

LSP · CLI free

Find dead public API. Public methods no caller reached in any recorded run, including the ones whose only caller is their own spec. Greyed out in your editor.

See more →