def summary_line(book)
"#{book.title} · #{book.weeks} weeks"
end class Book
def title = …
def weeks = …
def author = …
def curriculum = …
def price = …
end #title#weeks · 6 other public methods never sent · 4 spec examples · 30 app runs 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_linereports per argument, and--by-callerreports per calling method, for when different callers pass different things.
How it works
- Every recorded call to
Report#summary_lineincludes the class of each argument it was passed. Theclassesline comes from those, the double included. - 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.
- Those calls are the messages sent to the argument while the method ran, including by anything it passed the argument on to.
- The
neverline 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_son aString, is not recorded, so an argument whose one message is#to_sshows no messages. - The lists cover what ran. A branch that sends
#author_nameand did not run in any recording is missing fromreceives, so readreceivesas “was asked for” andneveras “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.
Related tools
observed_shape
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
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
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 →