When exploring a new Ruby codebase, I have a pattern of using caller to understand the callstack and build out a visual representation - E.G:
.
└── ApplicationController/
└── UsersController#create/
└── UsersService.create/
├── UsersService::UsersCreate#call/
│ ├── UsersService::UsersValidator#validate
│ └── MetricsService.increment_new_users
└── UsersService.build_create_response
- Put a breakpoint somewhere.
- Get the current callstack via
caller. - Collect callstack via:
data = callee.reject { |l| l.include?("/gems/") } - Dump the callstack via:
puts Base64.encode64(Marshal.dump(data)) - Paste the data into a file next to the script with the name:
callee-to-tree.txt. - Execute the script:
./callee-to-tree.rb. - Format the indentation such that invoked methods are nested 1 level deeper than the callee.
- Paste the output to an ASCII tree maker like https://tree.nathanfriend.com/.
- Keep a plain version of your output so that you can add to it easily as you explore more parts of the codebase and regenerate a new tree.
- Keep a file per flow (Users Create, Users Delete, etc).