I have added an alias on RSpec using pry-byebug
, just like this:
# frozen_string_literal: true
RSpec.configure do |rspec|
rspec.alias_example_group_to :pcontext, pry: true
rspec.alias_example_group_to :pdescribe, pry: true
rspec.alias_example_to :pit, pry: true
rspec.before(:example, pry: true) do |_|
# rubocop:disable Lint/Debugger
binding.pry
# rubocop:enable Lint/Debugger
end
end
I would like that when using this alias, for example in this line of code:
pit { expect(published_post.published?).to be_truthy }
For the session to start on the test line like this:
...
=> 16: pit { expect(published_post.published?).to be_truthy }
But at moment it start inside the alias:
From: /opt/hobbyonrails/spec/support/alias.rb:12 :
7:
8: rspec.before(:example, pry: true) do |_|
9: # rubocop:disable Lint/Debugger
10: binding.pry
11: # rubocop:enable Lint/Debugger
=> 12: end
13: end
To go to where I want I need to run this command: step 25
. So, I was wondering if there is a way to have this command run automatically right after the session starts, but I can't find the answer.
Can you give me some tips to achieve this, please?
Use a Pry before_session
hook as described in the Pry wiki article on hooks.
A before_session
hook is executed before dropping you into the REPL when binding.pry
is called. Pry uses a before_session
hook every time you invoke binding.pry
to call whereami --quiet
, like you have in your post:
From: /opt/hobbyonrails/spec/support/alias.rb:12 :
7:
8: rspec.before(:example, pry: true) do |_|
9: # rubocop:disable Lint/Debugger
10: binding.pry
11: # rubocop:enable Lint/Debugger
=> 12: end
13: end
The idea of using a before_session
hook to solve your problem is to tell Pry that when it is invoked it should automatically call step 25
. (or however many steps you need)
It gets a little bit tricky though because the step
command from pry-byebug actually invokes a new Pry session. If you add a before_session
hook that calls step
, and step
then invokes a new session, you'll get caught in a loop that steps through until the program finishes executing.
Another issue is that any invocation of binding.pry
in your code that is executed after the hook is added will invoke step
again, and you probably don't want it to step
every time, just in one particular spot.
The fix for this is to add a hook that removes itself when executed:
Pry.hooks.add_hook(:before_session, 'step') do |output, binding, pry|
Pry.hooks.delete_hook(:before_session, 'step')
pry.run_command('step 1')
end
Now the flow should be:
binding.pry
is invokedstep 1
step
invokes a new Pry sessionbinding.pry
invocations do not execute the hookHere is an example app to show how this would work:
require 'pry'
require 'pry-byebug'
Pry.hooks.add_hook(:before_session, 'step') do |output, binding, pry|
Pry.hooks.delete_hook(:before_session, 'step')
pry.run_command('step 1')
end
binding.pry
puts 'Pry will run `whereami` and point at this line with => first'
puts 'But when the hook runs it will step to and point at this line with =>'
puts 'And it will stop before it reaches this line'
binding.pry
puts 'And after this second binding, there will be no hook and thus no step'
puts 'And it will stop before it reaches this line'
And here's its output demonstrating that it works as described:
$ ruby foo.rb
From: /Users/foo/foo.rb:10 :
5: Pry.hooks.delete_hook(:before_session, 'step')
6: pry.run_command('step 1')
7: end
8:
9: binding.pry
=> 10: puts 'Pry will run `whereami` and point at this line with => first'
11: puts 'But when the hook runs it will step to and point at this line with =>'
12: puts 'And it will stop before it reaches this line'
13:
14: binding.pry
15: puts 'And after this second binding, there will be no hook and thus no step'
Pry will run `whereami` and point at this line with => first
From: /Users/foo/foo.rb:11 :
6: pry.run_command('step 1')
7: end
8:
9: binding.pry
10: puts 'Pry will run `whereami` and point at this line with => first'
=> 11: puts 'But when the hook runs it will step to and point at this line with =>'
12: puts 'And it will stop before it reaches this line'
13:
14: binding.pry
15: puts 'And after this second binding, there will be no hook and thus no step'
16: puts 'And it will stop before it reaches this line'
foo|(main):1 ⇒ exit
But when the hook runs it will step to and point at this line with =>
And it will stop before it reaches this line
From: /Users/foo/foo.rb:15 :
10: puts 'Pry will run `whereami` and point at this line with => first'
11: puts 'But when the hook runs it will step to and point at this line with =>'
12: puts 'And it will stop before it reaches this line'
13:
14: binding.pry
=> 15: puts 'And after this second binding, there will be no hook and thus no step'
16: puts 'And it will stop before it reaches this line'
foo|(main):1 ⇒
Integrating this into your app should be pretty straightforward:
rspec.before(:example, pry: true) do |_|
# rubocop:disable Lint/Debugger
# You should find a good way to set this value as it seems likely to change
steps = 25
Pry.hooks.add_hook(:before_session, 'step') do |output, binding, pry|
Pry.hooks.delete_hook(:before_session, 'step')
pry.run_command("step #{steps}")
end
binding.pry
# rubocop:enable Lint/Debugger
end