runtimeanalyz.ing ● early access · sign-up open

← All capabilities

what_it_receives

CLI · LSP · MCP free

What a method receives. The observed shape of each argument at a call site. The messages the method actually sends to what it's passed, not only the class it was given.

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 · 22 other public methods never sent · 9 examples · 2,406 prod runs
The argument is followed by identity through the call. Whatever the parameter is called, and however big Book is, summary_line only ever asks it for a title and a length.

The problem

A parameter name is a guess about what a method needs. This one says book:

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

So its spec builds a book, and a real Book needs an author, a curriculum and a price before it will save:

it "prints the title and length" do
  book = create(:book, :with_author, :with_curriculum, weeks: 12, title: "Geometry")

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

The spec is slow, it breaks whenever Book’s validations change, and none of that setup has anything to do with a summary line. The method sends two messages to its argument. Nothing in the code says so except the body, and the body gets longer.

The same question comes up when you want to reuse the method. Can summary_line take a Course? Only if you know what it actually asks of what it’s given.

The fix

Ask what the argument receives:

$ ra what_it_receives Report#summary_line

book  (arg 1)
  classes   Book                  41 calls · 3 call sites
  receives  #title #weeks
  never     #author #curriculum #price #chapters …  (19 more public methods on Book)
  · from 9 spec examples and 2,406 production runs

summary_line depends on something that answers #title and #weeks. That’s the whole contract, so that’s all the spec has to supply:

it "prints the title and length" do
  book = instance_double(Book, title: "Geometry", weeks: 12)

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

And the reuse question has an answer: anything with #title and #weeks will do, so a Course that has both can be passed straight in. Rename the parameter to say so, if you like.

Where it shows up

  • Your editor (LSP). Hover an argument and see its classes and the messages it receives.
  • Your agent (MCP). Before writing a double or a factory call, the agent asks what the method needs and builds only that.
  • The command line. ra what_it_receives Report#summary_line, per argument, and per call site with --by-caller when different callers pass different things.

How it works

  1. Argument classes. Every recorded call to Report#summary_line carries the class of each argument it was passed. That gives the classes line.
  2. Argument identity. 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. Collect the messages. Those calls are the messages sent to the argument while the method ran, including by anything it passed the argument on to.
  4. Aggregate. The message sets are merged across every call tree, and kept per call site so you can see when one caller’s argument is asked for more than another’s.

Limits

  • App methods only, for now. Messages to your own classes are recorded. A message to a core type, like #to_s on a String, isn’t yet, so an argument that only ever gets #to_s shows no messages.
  • Only what ran. A branch that sends #author but never ran in any recording won’t show up. Read receives as “was asked for”, not “can only be asked for”.
  • Shapes, not values. It knows book was a Book that answered #weeks. It doesn’t know it was 12.

observed_shape

CLI · LSP · MCP free

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 →

who_actually_answered

CLI · LSP · MCP free

Who actually answered. At a duck-typed call site, the concrete classes that received the message at runtime, and how often. Go to implementation, from real runs.

See more →

how_to_reach

MCP free

Reach any method. The collaborators and call path that get an object into the state a method needs, taken from a real run. Setup for tests that use real objects instead of doubles.

See more →