pry-byebug 1.3.3 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,126 +2,104 @@ require 'pry'
2
2
  require 'byebug'
3
3
 
4
4
  module PryByebug
5
+ #
6
+ # Extends raw byebug's processor.
7
+ #
5
8
  class Processor < Byebug::Processor
6
9
  attr_accessor :pry
7
10
 
8
11
  def initialize(interface = Byebug::LocalInterface.new)
9
12
  super(interface)
10
-
13
+
11
14
  Byebug.handler = self
12
- @always_enabled = true
13
- @delayed = Hash.new(0)
14
15
  end
15
16
 
16
17
  # Wrap a Pry REPL to catch navigational commands and act on them.
17
- def run(initial = true, &block)
18
+ def run(initial = false, &_block)
18
19
  return_value = nil
19
20
 
20
- command = catch(:breakout_nav) do # Throws from PryByebug::Commands
21
- return_value = yield
22
- {} # Nothing thrown == no navigational command
23
- end
21
+ if initial
22
+ Byebug.start
23
+ Byebug.current_context.step_out(3)
24
+ else
25
+ command = catch(:breakout_nav) do # Throws from PryByebug::Commands
26
+ return_value = yield
27
+ {} # Nothing thrown == no navigational command
28
+ end
24
29
 
25
- times = (command[:times] || 1).to_i # Command argument
26
- times = 1 if times <= 0
30
+ times = (command[:times] || 1).to_i # Command argument
31
+ times = 1 if times <= 0
27
32
 
28
- if [:step, :next, :finish].include? command[:action]
29
- @pry = command[:pry] # Pry instance to resume after stepping
30
- Byebug.start unless Byebug.started?
33
+ if [:step, :next, :finish].include? command[:action]
34
+ @pry = command[:pry] # Pry instance to resume after stepping
31
35
 
32
- if initial
33
- # Movement when on the initial binding.pry line will have a frame
34
- # inside Byebug. If we step normally, it'll stop inside this
35
- # Processor. So jump out and stop at the above frame, then step/next
36
- # from our callback.
37
- @delayed[command[:action]] = times
38
- Byebug.current_context.step_out(2)
39
- elsif :next == command[:action]
40
- Byebug.current_context.step_over(times, 0)
36
+ if :next == command[:action]
37
+ Byebug.current_context.step_over(times, 0)
41
38
 
42
- elsif :step == command[:action]
43
- Byebug.current_context.step_into(times)
39
+ elsif :step == command[:action]
40
+ Byebug.current_context.step_into(times)
44
41
 
45
- elsif :finish == command[:action]
46
- Byebug.current_context.step_out(0)
42
+ elsif :finish == command[:action]
43
+ Byebug.current_context.step_out(times)
44
+ end
47
45
  end
48
- else
49
- stop
50
46
  end
51
47
 
52
48
  return_value
53
49
  end
54
50
 
55
- # Adjust debugging. When set to false, the Processor will manage enabling
56
- # and disabling the debugger itself. When set to true, byebug is always
57
- # enabled.
58
- def debugging=(enabled)
59
- if enabled
60
- @always_enabled = true
61
- Byebug.start unless Byebug.started?
62
- else
63
- @always_enabled = false
64
- # Byebug will get stopped if necessary in `stop` once the repl ends.
65
- end
66
- end
67
-
68
51
  # --- Callbacks from byebug C extension ---
69
- def at_line(context, file, line)
70
- # If any delayed nexts/steps, do 'em.
71
- if @delayed[:next] > 1
72
- context.step_over(@delayed[:next] - 1, 0)
73
52
 
74
- elsif @delayed[:step] > 1
75
- context.step_into(@delayed[:step] - 1)
53
+ #
54
+ # Called when the wants to stop at a regular line
55
+ #
56
+ def at_line(context, _file, _line)
57
+ resume_pry(context)
58
+ end
59
+
60
+ #
61
+ # Called when the wants to stop right before a method return
62
+ #
63
+ def at_return(context, _file, _line)
64
+ resume_pry(context)
65
+ end
76
66
 
77
- elsif @delayed[:finish] > 1
78
- context.step_out(@delayed[:finish] - 1)
67
+ #
68
+ # Called when a breakpoint is hit. Note that `at_line`` is called
69
+ # inmediately after with the context's `stop_reason == :breakpoint`, so we
70
+ # must not resume the pry instance here
71
+ #
72
+ def at_breakpoint(_context, breakpoint)
73
+ @pry ||= Pry.new
79
74
 
80
- # Otherwise, resume the pry session at the stopped line.
81
- else
82
- resume_pry context
83
- end
75
+ brkpt_num = "\nBreakpoint #{breakpoint.id}. "
76
+ @pry.output.print Pry::Helpers::Text.bold(brkpt_num)
84
77
 
85
- @delayed = Hash.new(0)
86
- end
78
+ n_hits = breakpoint.hit_count
79
+ @pry.output.puts(n_hits == 1 ? 'First hit' : "Hit #{n_hits} times.")
87
80
 
88
- # Called when a breakpoint is triggered. Note: `at_line`` is called
89
- # immediately after with the context's `stop_reason == :breakpoint`.
90
- def at_breakpoint(context, breakpoint)
91
- @pry.output.print Pry::Helpers::Text.bold("\nBreakpoint #{breakpoint.id}. ")
92
- @pry.output.puts (breakpoint.hit_count == 1 ?
93
- 'First hit.' :
94
- "Hit #{breakpoint.hit_count} times." )
95
- if (expr = breakpoint.expr)
96
- @pry.output.print Pry::Helpers::Text.bold("Condition: ")
97
- @pry.output.puts expr
98
- end
99
- end
81
+ expr = breakpoint.expr
82
+ return unless expr
100
83
 
101
- def at_catchpoint(context, exception)
102
- # TODO
84
+ @pry.output.print Pry::Helpers::Text.bold('Condition: ')
85
+ @pry.output.puts expr
103
86
  end
104
87
 
105
88
  private
106
89
 
107
- #
108
- # Resume an existing Pry REPL at the paused point.
109
- #
110
- def resume_pry(context)
111
- new_binding = context.frame_binding(0)
112
- Byebug.stop unless @always_enabled
113
-
114
- run(false) do
115
- @pry.repl new_binding
116
- end
117
- end
118
-
119
- # Cleanup when debugging is stopped and execution continues.
120
- def stop
121
- Byebug.stop if !@always_enabled && Byebug.started?
122
- if PryByebug.current_remote_server # Cleanup DRb remote if running
123
- PryByebug.current_remote_server.teardown
90
+ #
91
+ # Resume an existing Pry REPL at the paused point.
92
+ #
93
+ def resume_pry(context)
94
+ new_binding = context.frame_binding(0)
95
+
96
+ run(false) do
97
+ if @pry
98
+ @pry.repl(new_binding)
99
+ else
100
+ @pry = Pry.start_without_pry_byebug(new_binding)
124
101
  end
125
102
  end
103
+ end
126
104
  end
127
105
  end
@@ -1,21 +1,22 @@
1
1
  require 'pry-remote'
2
2
 
3
3
  module PryRemote
4
+ #
5
+ # Overrides PryRemote::Server
6
+ #
4
7
  class Server
8
+ #
5
9
  # Override the call to Pry.start to save off current Server, and not
6
10
  # teardown the server right after Pry.start finishes.
11
+ #
7
12
  def run
8
- if PryByebug.current_remote_server
9
- raise 'Already running a pry-remote session!'
10
- else
11
- PryByebug.current_remote_server = self
12
- end
13
+ fail('Already running a pry-remote session!') if
14
+ PryByebug.current_remote_server
15
+
16
+ PryByebug.current_remote_server = self
13
17
 
14
18
  setup
15
- Pry.start @object, {
16
- :input => client.input_proxy,
17
- :output => client.output
18
- }
19
+ Pry.start @object, input: client.input_proxy, output: client.output
19
20
  end
20
21
 
21
22
  # Override to reset our saved global current server session.
@@ -35,7 +36,5 @@ end
35
36
  # 'next' on the last line of a program won't hit PryByebug::Processor#run,
36
37
  # which normally handles cleanup.
37
38
  at_exit do
38
- if PryByebug.current_remote_server
39
- PryByebug.current_remote_server.teardown
40
- end
39
+ PryByebug.current_remote_server.teardown if PryByebug.current_remote_server
41
40
  end
@@ -1,3 +1,3 @@
1
1
  module PryByebug
2
- VERSION = '1.3.3'
2
+ VERSION = '2.0.0'
3
3
  end
@@ -8,8 +8,8 @@ Gem::Specification.new do |gem|
8
8
  gem.license = 'MIT'
9
9
  gem.homepage = 'https://github.com/deivid-rodriguez/pry-byebug'
10
10
  gem.summary = 'Fast debugging with Pry.'
11
- gem.description = %q{Combine 'pry' with 'byebug'. Adds 'step', 'next', and
12
- 'continue' commands to control execution.}
11
+ gem.description = "Combine 'pry' with 'byebug'. Adds 'step', 'next',
12
+ 'finish', 'continue' and 'break' commands to control execution."
13
13
 
14
14
  gem.files = `git ls-files`.split("\n")
15
15
  gem.test_files = `git ls-files -- test/*`.split("\n")
@@ -19,5 +19,5 @@ Gem::Specification.new do |gem|
19
19
  gem.required_ruby_version = '>= 2.0.0'
20
20
 
21
21
  gem.add_runtime_dependency 'pry', '~> 0.10'
22
- gem.add_runtime_dependency 'byebug', '~> 2.7'
22
+ gem.add_runtime_dependency 'byebug', '~> 3.4'
23
23
  end
@@ -1,14 +1,16 @@
1
1
  require 'test_helper'
2
2
 
3
+ #
4
+ # Checks current pry-byebug's context.
5
+ #
3
6
  class BaseTest < MiniTest::Spec
4
7
  def test_main_file_context
5
- Pry.stubs eval_path: "<main>"
8
+ Pry.stubs eval_path: '<main>'
6
9
  assert PryByebug.check_file_context(TOPLEVEL_BINDING)
7
10
  end
8
11
 
9
12
  def test_other_file_context
10
- Pry.stubs eval_path: "something"
13
+ Pry.stubs eval_path: 'something'
11
14
  refute PryByebug.check_file_context(TOPLEVEL_BINDING)
12
15
  end
13
16
  end
14
-
@@ -1,14 +1,20 @@
1
1
  require 'test_helper'
2
2
 
3
- class BreakpointsTest < MiniTest::Spec
3
+ #
4
+ # Tests for pry-byebug breakpoints.
5
+ #
6
+ class BreakpointsTestGeneral < MiniTest::Spec
4
7
  def test_add_file_raises_argument_error
5
- Pry.stubs eval_path: "something"
8
+ Pry.stubs eval_path: 'something'
6
9
  File.stubs :exist?
7
10
  assert_raises(ArgumentError) do
8
- PryByebug::Breakpoints.add_file("file", 1)
11
+ PryByebug::Breakpoints.add_file('file', 1)
9
12
  end
10
13
  end
11
14
 
15
+ #
16
+ # Minimal dummy example class.
17
+ #
12
18
  class Tester
13
19
  def self.class_method; end
14
20
  def instance_method; end
@@ -32,3 +38,96 @@ class BreakpointsTest < MiniTest::Spec
32
38
  end
33
39
  end
34
40
  end
41
+
42
+ #
43
+ # Some common specs for breakpoints
44
+ #
45
+ module BreakpointSpecs
46
+ def test_shows_breakpoint_enabled
47
+ @output.string.must_match @regexp
48
+ end
49
+
50
+ def test_shows_breakpoint_hit
51
+ match = @output.string.match(@regexp)
52
+ @output.string.must_match(/^Breakpoint #{match[:id]}\. First hit/)
53
+ end
54
+
55
+ def test_shows_breakpoint_line
56
+ @output.string.must_match(/\=> \s*#{@line}:/)
57
+ end
58
+ end
59
+
60
+ #
61
+ # Tests for breakpoint commands
62
+ #
63
+ class BreakpointsTestCommands < Minitest::Spec
64
+ let(:break_first_file) { test_file('break1') }
65
+ let(:break_second_file) { test_file('break2') }
66
+
67
+ before do
68
+ Pry.color, Pry.pager, Pry.hooks = false, false, Pry::DEFAULT_HOOKS
69
+ @output = StringIO.new
70
+ end
71
+
72
+ describe 'Set Breakpoints' do
73
+ before do
74
+ @input = InputTester.new 'break --delete-all'
75
+ redirect_pry_io(@input, @output) { load break_first_file }
76
+ end
77
+
78
+ describe 'set by line number' do
79
+ before do
80
+ @input = InputTester.new('break 7')
81
+ redirect_pry_io(@input, @output) { load break_first_file }
82
+ @line = 7
83
+ @regexp = /^Breakpoint (?<id>\d+): #{break_first_file} @ 7 \(Enabled\)/
84
+ end
85
+
86
+ include BreakpointSpecs
87
+ end
88
+
89
+ describe 'set by method_id' do
90
+ before do
91
+ @input = InputTester.new('break Break1Example#a')
92
+ redirect_pry_io(@input, @output) { load break_first_file }
93
+ @line = 7
94
+ @regexp = /Breakpoint (?<id>\d+): Break1Example#a \(Enabled\)/
95
+ end
96
+
97
+ include BreakpointSpecs
98
+ end
99
+
100
+ describe 'set by method_id when its a bang method' do
101
+ before do
102
+ @input = InputTester.new('break Break1Example#c!')
103
+ redirect_pry_io(@input, @output) { load break_first_file }
104
+ @line = 17
105
+ @regexp = /Breakpoint (?<id>\d+): Break1Example#c! \(Enabled\)/
106
+ end
107
+
108
+ include BreakpointSpecs
109
+ end
110
+
111
+ describe 'set by method_id within context' do
112
+ before do
113
+ @input = InputTester.new('break #b')
114
+ redirect_pry_io(@input, @output) { load break_second_file }
115
+ @line = 11
116
+ @regexp = /Breakpoint (?<id>\d+): Break2Example#b \(Enabled\)/
117
+ end
118
+
119
+ include BreakpointSpecs
120
+ end
121
+ end
122
+
123
+ describe 'List breakpoints' do
124
+ before do
125
+ @input = InputTester.new('break --delete-all', 'break #b', 'breakpoints')
126
+ redirect_pry_io(@input, @output) { load break_second_file }
127
+ end
128
+
129
+ it 'shows all breakpoints' do
130
+ @output.string.must_match(/Yes \s*Break2Example#b/)
131
+ end
132
+ end
133
+ end
@@ -1,178 +1,77 @@
1
1
  require 'test_helper'
2
2
 
3
- class CommandsTest < MiniTest::Spec
4
- let(:step_file) do
5
- (Pathname.new(__FILE__) + "../examples/stepping.rb").cleanpath.to_s
6
- end
7
-
8
- let(:break_first_file) do
9
- (Pathname.new(__FILE__) + "../examples/break1.rb").cleanpath.to_s
3
+ #
4
+ # Some common specs for stepping
5
+ #
6
+ module SteppingSpecs
7
+ def self.included(spec_class)
8
+ spec_class.class_eval do
9
+ it 'shows current line' do
10
+ @output.string.must_match(/\=> \s*#{@line}:/)
11
+ end
12
+ end
10
13
  end
14
+ end
11
15
 
12
- let(:break_second_file) do
13
- (Pathname.new(__FILE__) + "../examples/break2.rb").cleanpath.to_s
14
- end
16
+ #
17
+ # Tests for pry-byebug commands.
18
+ #
19
+ class CommandsTest < MiniTest::Spec
20
+ let(:step_file) { test_file('stepping') }
15
21
 
16
22
  before do
17
- Pry.color = false
18
- Pry.pager = false
19
- Pry.hooks = Pry::DEFAULT_HOOKS
23
+ Pry.color, Pry.pager, Pry.hooks = false, false, Pry::DEFAULT_HOOKS
20
24
  @output = StringIO.new
21
25
  end
22
26
 
23
27
  describe 'Step Command' do
24
28
  describe 'single step' do
25
29
  before do
26
- @input = InputTester.new 'step'
27
- redirect_pry_io(@input, @output) do
28
- load step_file
29
- end
30
+ @input, @line = InputTester.new('step'), 7
31
+ redirect_pry_io(@input, @output) { load step_file }
30
32
  end
31
33
 
32
- it 'shows current line' do
33
- @output.string.must_match /\=> 3:/
34
- end
34
+ include SteppingSpecs
35
35
  end
36
36
 
37
37
  describe 'multiple step' do
38
38
  before do
39
- @input = InputTester.new 'step 2'
40
- redirect_pry_io(@input, @output) do
41
- load step_file
42
- end
39
+ @input, @line = InputTester.new('step 2'), 12
40
+ redirect_pry_io(@input, @output) { load step_file }
43
41
  end
44
42
 
45
- it 'shows current line' do
46
- @output.string.must_match /\=> 4:/
47
- end
43
+ include SteppingSpecs
48
44
  end
49
45
  end
50
46
 
51
47
  describe 'Next Command' do
52
48
  describe 'single step' do
53
49
  before do
54
- @input = InputTester.new 'next'
55
- redirect_pry_io(@input, @output) do
56
- load step_file
57
- end
50
+ @input, @line = InputTester.new('break --delete-all', 'next'), 6
51
+ redirect_pry_io(@input, @output) { load step_file }
58
52
  end
59
53
 
60
- it 'shows current line' do
61
- @output.string.must_match /\=> 3:/
62
- end
54
+ include SteppingSpecs
63
55
  end
64
56
 
65
57
  describe 'multiple step' do
66
58
  before do
67
- @input = InputTester.new 'next 2'
68
- redirect_pry_io(@input, @output) do
69
- load step_file
70
- end
59
+ @input, @line = InputTester.new('break --delete-all', 'next 2'), 25
60
+ redirect_pry_io(@input, @output) { load step_file }
71
61
  end
72
62
 
73
- it 'shows current line' do
74
- @output.string.must_match /\=> 20:/
75
- end
63
+ include SteppingSpecs
76
64
  end
77
65
  end
78
66
 
79
- describe 'Set Breakpoints' do
67
+ describe 'Finish Command' do
80
68
  before do
81
- @input = InputTester.new 'break --delete-all'
82
- redirect_pry_io(@input, @output) do
83
- load break_first_file
84
- end
85
- @output = StringIO.new
86
- end
87
-
88
- describe 'set by line number' do
89
- before do
90
- @input = InputTester.new 'break 3'
91
- redirect_pry_io(@input, @output) do
92
- load break_first_file
93
- end
94
- end
95
-
96
- it 'shows breakpoint enabled' do
97
- @output.string.must_match /^Breakpoint [\d]+: #{break_first_file} @ 3 \(Enabled\)/
98
- end
99
-
100
- it 'shows breakpoint hit' do
101
- @output.string =~ /^Breakpoint ([\d]+): #{break_first_file} @ 3 \(Enabled\)/
102
- @output.string.must_match Regexp.new("^Breakpoint #{$1}\. First hit")
103
- end
104
-
105
- it 'shows breakpoint line' do
106
- @output.string.must_match /\=> 3:/
107
- end
108
- end
109
-
110
- describe 'set by method_id' do
111
- before do
112
- @input = InputTester.new 'break BreakExample#a'
113
- redirect_pry_io(@input, @output) do
114
- load break_first_file
115
- end
116
- end
117
-
118
- it 'shows breakpoint enabled' do
119
- @output.string.must_match /^Breakpoint [\d]+: BreakExample#a \(Enabled\)/
120
- end
121
-
122
- it 'shows breakpoint hit' do
123
- @output.string =~ /^Breakpoint ([\d]+): BreakExample#a \(Enabled\)/
124
- @output.string.must_match Regexp.new("^Breakpoint #{$1}\. First hit")
125
- end
126
-
127
- it 'shows breakpoint line' do
128
- @output.string.must_match /\=> 4:/
129
- end
130
-
131
- describe 'when its a bang method' do
132
- before do
133
- @input = InputTester.new 'break BreakExample#c!'
134
- redirect_pry_io(@input, @output) do
135
- load break_first_file
136
- end
137
- end
138
-
139
- it 'shows breakpoint enabled' do
140
- @output.string.must_match /^Breakpoint [\d]+: BreakExample#c! \(Enabled\)/
141
- end
142
-
143
- it 'shows breakpoint hit' do
144
- @output.string =~ /^Breakpoint ([\d]+): BreakExample#c! \(Enabled\)/
145
- @output.string.must_match Regexp.new("^Breakpoint #{$1}\. First hit")
146
- end
147
-
148
- it 'shows breakpoint line' do
149
- @output.string.must_match /\=> 14:/
150
- end
151
- end
152
- end
153
-
154
- describe 'set by method_id within context' do
155
- before do
156
- @input = InputTester.new 'break #b'
157
- redirect_pry_io(@input, @output) do
158
- load break_second_file
159
- end
160
- end
161
-
162
- it 'shows breakpoint enabled' do
163
- @output.string.must_match /^Breakpoint [\d]+: BreakExample#b \(Enabled\)/
164
- end
165
-
166
- it 'shows breakpoint hit' do
167
- @output.string =~ /^Breakpoint ([\d]+): BreakExample#b \(Enabled\)/
168
- @output.string.must_match Regexp.new("^Breakpoint #{$1}\. First hit")
169
- end
170
-
171
- it 'shows breakpoint line' do
172
- @output.string.must_match /\=> 8:/
173
- end
69
+ @input = \
70
+ InputTester.new 'break --delete-all', 'break 19', 'continue', 'finish'
71
+ redirect_pry_io(@input, @output) { load step_file }
72
+ @line = 15
174
73
  end
175
74
 
75
+ include SteppingSpecs
176
76
  end
177
77
  end
178
-