runtimeanalyz.ing

← All capabilities

what_it_receives

CLI · LSP · MCP free

What a method receives. For each argument of a method, the classes it was given in recorded calls and the messages the method sent to it.

Scheduler 1 of 3 callers
summary_line ( book Book )
41 calls
Report receiver
def summary_line(book)
  "#{book.title} · #{book.weeks} weeks"
end
Report#summary_line while it runs
title
weeks
book Book
class Book
  def title = …
  def weeks = …
  def author = …
  def curriculum = …
  def price = …
end
Received book · Book#title#weeks · 6 other public methods never sent · 4 spec examples · 30 app runs
The argument is followed by object identity through the call. summary_line asks the Book for a title and a length and sends it none of its other public methods.

The problem

The parameter of this method is named book:

def summary_line(book)
  "#{book.title} · #{book.weeks} weeks"
end

Going by the name, its spec builds a book, and a real Book needs a curriculum, an author and a prerequisite chain before it will save. That makes the spec slow, and it breaks whenever Book’s validations change, although a summary line uses none of that setup. The method sends two messages to its argument, which you learn by reading its body.

The same question comes up when you want to reuse the method: whether summary_line can take a Course depends on which messages it sends to its argument.

The fix

Ask what the argument receives:

$ ra what_it_receives Report#summary_line
Report#summary_line
· 66 calls · 3 call sites
book (arg 1)
    classes   Book 65 · RSpec::Mocks::InstanceVerifyingDouble 1
    receives  #title #weeks
    never     #chapters #price #unlocked? #archived_book? #author_name #unlock!
  · from 4 spec examples and 30 app runs

summary_line needs an argument that answers #title and #weeks. No recorded call sent it any other message, so those two methods are what a spec has to supply. The one example that passed a double already does:

it "prints a line for a double" do
  book = instance_double(Book, title: "Geometry", weeks: 12)

  expect(Report.new(account.id).summary_line(book)).to eq("Geometry · 12 weeks")
end

For reuse, any object with #title and #weeks will work, so a Course that has both can be passed in unchanged. You could rename the parameter to say so.

Where it shows up

  • In your editor (LSP), hover a method definition to see each argument’s classes and the messages it received.
  • Over MCP, your agent can ask which messages a method sends before it writes a double or a factory call, and build an object that answers those.
  • On the command line, ra what_it_receives Report#summary_line reports per argument, and --by-caller reports per calling method, for when different callers pass different things.

How it works

  1. Every recorded call to Report#summary_line includes the class of each argument it was passed. The classes line comes from those, the double included.
  2. The recording also keeps each argument’s object identity. Inside one call tree, an object is live and its id can’t be reused, so the argument can be followed to every later call where it’s the receiver.
  3. Those calls are the messages sent to the argument while the method ran, including by anything it passed the argument on to.
  4. The never line is the argument class’s other public methods, read from the source, that no recorded call sent it.

Run it on your app

The output on this page comes from our example Rails app, and it is regenerated whenever a tool changes. These are the commands behind it. On your own app, run ra record first, then put your own class, method or file in their place.

ra what_it_receives 'Report#summary_line'

The method is app/models/report.rb:28. The double is in spec/models/report_spec.rb, and the dashboard calls it twice per request through Report#summary.

Reading the result

  • Messages to your own classes are recorded. A message to a core type, like #to_s on a String, is not recorded, so an argument whose one message is #to_s shows no messages.
  • The lists cover what ran. A branch that sends #author_name and did not run in any recording is missing from receives, so read receives as “was asked for” and never as “was not asked for in what you recorded”.

Every tool reads the same recording. What gets recorded and how far to trust an answer are on the questions page.

observed_shape

CLI · LSP · MCP Pro

The interface a call depends on. The messages your code sends to a value, read from recorded runs. They are the interface a call depends on, whether or not anyone declared it.

See more →

who_actually_answered

CLI · LSP · MCP free

The classes that answered a call. At a duck-typed call site, the concrete classes that received the message in recorded runs, and how often each did. In an editor it answers go to implementation from the recording.

See more →

how_to_reach

MCP · CLI Pro

The setup a method needs. The collaborators and the call path that put an object into the state a method needs, taken from a recorded run. Use it to write setup for tests that use real objects in place of doubles.

See more →