pry-byebug 1.3.3 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
-