pry-byebug 2.0.0 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 8123f22dc42ff24f284f47d77bdf74679b8025c2
4
- data.tar.gz: 1803eaf3cc4e019e64ce84835bb0a288cef8cebe
3
+ metadata.gz: c42e1d5a58d90aa640bcd1e79be383d78286fc66
4
+ data.tar.gz: 32cf706c69453f75a70729fa4caf95b023642379
5
5
  SHA512:
6
- metadata.gz: eecedab14af1c1eddfc82d5828a4418a239691b6ef27f67e4340458054e0646edd049ded5cde2dc1ef10efe72bf2abb70b4c759a1145710c2e25b9e59b3faeec
7
- data.tar.gz: 33135d020dc22bf50e1a8f57b39a5dce8f5e8c1373cd8f380500a210b8199bf05a5c90084f286c2d003b2379703e025fe63d80465b2007dfa3d10b68849a0495
6
+ metadata.gz: d4e5826a3e0d91869ff79953c45e475d0ecb5252e50171a5ad18f8a667625558690af3b00e09d0b8ccb68c55257e5bc0f285edb85334388fd7a4b8ea9c6ce826
7
+ data.tar.gz: e87f0c3fe28da82b42e2146c108ae73b0832b4bc10d1f1b54baaefccf639580d8874cc5c7a1149fbd46500969ce3b55bd4e13b81531f1d05913735ad389fd193
@@ -1,2 +1,12 @@
1
1
  Lint/Debugger:
2
+ Exclude:
3
+ - test/examples/*.rb
4
+
5
+ Style/FileName:
6
+ Exclude:
7
+ - lib/pry-byebug.rb
8
+ - lib/pry-byebug/cli.rb
9
+ - test/test_helper.rb
10
+
11
+ Style/ModuleFunction:
2
12
  Enabled: false
@@ -1,7 +1,9 @@
1
1
  rvm:
2
2
  - 2.0.0
3
3
  - 2.1
4
+ - 2.2
4
5
  - ruby-head
6
+
5
7
  matrix:
6
8
  allow_failures:
7
9
  - rvm: ruby-head
@@ -1,3 +1,18 @@
1
+ ## 3.0.0 (Unreleased)
2
+
3
+ - Improvements:
4
+ * Adds RuboCop to enforce a consistent code style.
5
+ * Several refactorings to keep code simpler.
6
+
7
+ - Bugfixes:
8
+ * `binding.pry` would not stop at the correct place when called at the last
9
+ line of a method/block.
10
+
11
+ - Removals:
12
+ * Stepping aliases for `next` (`n`), `step` (`s`), `finish` (`f`) and
13
+ `continue` (`c`). See #34.
14
+
15
+
1
16
  ## 2.0.0 (2014-01-09)
2
17
 
3
18
  - Improvements:
data/Gemfile CHANGED
@@ -5,7 +5,7 @@ gemspec
5
5
  gem 'rake', '~> 10.3'
6
6
 
7
7
  group :development do
8
- gem 'rubocop', '~> 0.25'
8
+ gem 'rubocop', '~> 0.26'
9
9
  end
10
10
 
11
11
  group :test do
data/README.md CHANGED
@@ -1,6 +1,7 @@
1
1
  # pry-byebug
2
2
  [![Version][VersionBadge]][VersionURL]
3
3
  [![Build][TravisBadge]][TravisURL]
4
+ [![Inline docs][InchCIBadge]](InchCIURL)
4
5
  [![Gittip][GittipBadge]][GittipURL]
5
6
 
6
7
  _Fast execution control in Pry_
@@ -9,12 +10,16 @@ Adds **step**, **next**, **finish** and **continue** commands and
9
10
  **breakpoints** to [Pry][pry] using [byebug][byebug].
10
11
 
11
12
  To use, invoke pry normally. No need to start your script or app differently.
13
+ Execution will stop in the first statement after your `binding.pry`.
12
14
 
13
15
  ```ruby
14
16
  def some_method
15
- binding.pry # Execution will stop here.
16
- puts 'Hello World' # Run 'step' or 'next' in the console to move here.
17
+ puts 'Hello World' # Run 'step' in the console to move here
17
18
  end
19
+
20
+ binding.pry
21
+ some_method # Execution will stop here.
22
+ puts 'Goodbye World' # Run 'next' in the console to move here.
18
23
  ```
19
24
 
20
25
 
@@ -37,14 +42,43 @@ to use it to debug your tests!_
37
42
  ## Execution Commands
38
43
 
39
44
  **step:** Step execution into the next line or method. Takes an optional numeric
40
- argument to step multiple times. Aliased to `s`
45
+ argument to step multiple times.
41
46
 
42
47
  **next:** Step over to the next line within the same frame. Also takes an
43
- optional numeric argument to step multiple lines. Aliased to `n`
48
+ optional numeric argument to step multiple lines.
49
+
50
+ **finish:** Execute until current stack frame returns.
51
+
52
+ **continue:** Continue program execution and end the Pry session.
53
+
44
54
 
45
- **finish:** Execute until current stack frame returns. Aliased to `f`
55
+ ## Matching Byebug Behaviour
46
56
 
47
- **continue:** Continue program execution and end the Pry session. Aliased to `c`
57
+ If you're coming from Byebug or from Pry-Byebug versions previous to 3.0, you
58
+ may be lacking the 'n', 's', 'c' and 'f' aliases for the stepping commands.
59
+ These aliases were removed by default because they usually conflict with
60
+ scratch variable names. But it's very easy to reenable them if you still want
61
+ them, just add the following shortcuts to your `~/.pryrc` file:
62
+
63
+ ```ruby
64
+ if defined?(PryByebug)
65
+ Pry.commands.alias_command 'c', 'continue'
66
+ Pry.commands.alias_command 's', 'step'
67
+ Pry.commands.alias_command 'n', 'next'
68
+ Pry.commands.alias_command 'f', 'finish'
69
+ end
70
+ ```
71
+
72
+ Also, you might find useful as well the repeat the last command by just hitting
73
+ the `Enter` key (e.g., with `step` or `next`). To achieve that, add this to
74
+ your `~/.pryrc` file:
75
+
76
+ ```ruby
77
+ # Hit Enter to repeat last command
78
+ Pry::Commands.command /^$/, "repeat last command" do
79
+ _pry_.run_command Pry.history.to_a.last
80
+ end
81
+ ```
48
82
 
49
83
 
50
84
  ## Breakpoints
@@ -70,7 +104,7 @@ break --condition 3 # Remove the condition on breakpoint #3.
70
104
  break --delete 5 # Delete breakpoint #5.
71
105
  break --disable-all # Disable all breakpoints.
72
106
 
73
- break # List all breakpoints. (Same as `breakpoints`)
107
+ breaks # List all breakpoints. (Same as `breakpoints`)
74
108
  break --show 2 # Show details about breakpoint #2.
75
109
  ```
76
110
 
@@ -99,9 +133,11 @@ Patches and bug reports are welcome.
99
133
  [byebug]: https://github.com/deivid-rodriguez/byebug
100
134
  [pry-debugger]: https://github.com/nixme/pry-debugger
101
135
  [pry-stack_explorer]: https://github.com/pry/pry-stack_explorer
102
- [VersionBadge]: https://badge.fury.io/rb/pry-byebug.png
136
+ [VersionBadge]: https://badge.fury.io/rb/pry-byebug.svg
103
137
  [VersionURL]: http://badge.fury.io/rb/pry-byebug
104
- [TravisBadge]: https://secure.travis-ci.org/deivid-rodriguez/pry-byebug.png
138
+ [TravisBadge]: https://secure.travis-ci.org/deivid-rodriguez/pry-byebug.svg
105
139
  [TravisURL]: http://travis-ci.org/deivid-rodriguez/pry-byebug
140
+ [InchCIBadge]: http://inch-ci.org/github/deivid-rodriguez/pry-byebug.svg?branch=master
141
+ [InchCIURL]: http://inch-ci.org/github/deivid-rodriguez/pry-byebug
106
142
  [GittipBadge]: http://img.shields.io/gittip/deivid-rodriguez.svg
107
143
  [GittipURL]: https://www.gittip.com/deivid-rodriguez
@@ -1,51 +1,55 @@
1
1
  require 'pry'
2
2
  require 'byebug'
3
3
 
4
- module PryByebug
4
+ module Byebug
5
5
  #
6
6
  # Extends raw byebug's processor.
7
7
  #
8
- class Processor < Byebug::Processor
8
+ class PryProcessor < Processor
9
9
  attr_accessor :pry
10
10
 
11
- def initialize(interface = Byebug::LocalInterface.new)
11
+ def initialize(interface = LocalInterface.new)
12
12
  super(interface)
13
13
 
14
14
  Byebug.handler = self
15
15
  end
16
16
 
17
+ def start
18
+ Byebug.start
19
+ Byebug.current_context.step_out(3, true)
20
+ end
21
+
22
+ #
17
23
  # Wrap a Pry REPL to catch navigational commands and act on them.
18
- def run(initial = false, &_block)
24
+ #
25
+ def run(&_block)
19
26
  return_value = nil
20
27
 
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
29
-
30
- times = (command[:times] || 1).to_i # Command argument
31
- times = 1 if times <= 0
28
+ command = catch(:breakout_nav) do # Throws from PryByebug::Commands
29
+ return_value = yield
30
+ {} # Nothing thrown == no navigational command
31
+ end
32
32
 
33
- if [:step, :next, :finish].include? command[:action]
34
- @pry = command[:pry] # Pry instance to resume after stepping
33
+ # Pry instance to resume after stepping
34
+ @pry = command[:pry]
35
35
 
36
- if :next == command[:action]
37
- Byebug.current_context.step_over(times, 0)
36
+ perform(command[:action], (command[:times] || '1').to_i)
38
37
 
39
- elsif :step == command[:action]
40
- Byebug.current_context.step_into(times)
38
+ return_value
39
+ end
41
40
 
42
- elsif :finish == command[:action]
43
- Byebug.current_context.step_out(times)
44
- end
45
- end
41
+ #
42
+ # Set up a number of navigational commands to be performed by Byebug.
43
+ #
44
+ def perform(action, times)
45
+ case action
46
+ when :next
47
+ Byebug.current_context.step_over(times, 0)
48
+ when :step
49
+ Byebug.current_context.step_into(times)
50
+ when :finish
51
+ Byebug.current_context.step_out(times)
46
52
  end
47
-
48
- return_value
49
53
  end
50
54
 
51
55
  # --- Callbacks from byebug C extension ---
@@ -93,7 +97,7 @@ module PryByebug
93
97
  def resume_pry(context)
94
98
  new_binding = context.frame_binding(0)
95
99
 
96
- run(false) do
100
+ run do
97
101
  if @pry
98
102
  @pry.repl(new_binding)
99
103
  else
@@ -1,3 +1,4 @@
1
1
  require 'pry-byebug/base'
2
2
  require 'pry-byebug/pry_ext'
3
- require 'pry-byebug/commands'
3
+ require 'pry/commands/stepping'
4
+ require 'pry/commands/breakpoint'
@@ -1,11 +1,23 @@
1
+ #
2
+ # Main container module for Pry-Byebug functionality
3
+ #
1
4
  module PryByebug
2
5
  #
3
- # Checks that a binding is in a local file context. Extracted from
6
+ # Checks that a target binding is in a local file context.
4
7
  #
5
- def check_file_context(target)
8
+ def file_context?(target)
6
9
  file = target.eval('__FILE__')
7
10
  file == Pry.eval_path || !Pry::Helpers::BaseHelpers.not_a_real_file?(file)
8
11
  end
12
+ module_function :file_context?
13
+
14
+ #
15
+ # Ensures that a command is executed in a local file context.
16
+ #
17
+ def check_file_context(target, e = nil)
18
+ e ||= 'Cannot find local context. Did you use `binding.pry`?'
19
+ fail(Pry::CommandError, e) unless file_context?(target)
20
+ end
9
21
  module_function :check_file_context
10
22
 
11
23
  # Reference to currently running pry-remote server. Used by the processor.
@@ -1,19 +1,16 @@
1
1
  require 'pry'
2
- require 'pry-byebug/processor'
2
+ require 'byebug/processors/pry_processor'
3
3
 
4
4
  class << Pry
5
5
  alias_method :start_without_pry_byebug, :start
6
6
  attr_reader :processor
7
7
 
8
8
  def start_with_pry_byebug(target = TOPLEVEL_BINDING, options = {})
9
- @processor ||= PryByebug::Processor.new
9
+ @processor ||= Byebug::PryProcessor.new
10
10
 
11
- if target.is_a?(Binding) && PryByebug.check_file_context(target)
12
- # Wrap the processor around the usual Pry.start to catch navigation
13
- # commands.
14
- @processor.run(true) do
15
- start_without_pry_byebug(target, options)
16
- end
11
+ if target.is_a?(Binding) && PryByebug.file_context?(target)
12
+ # Wrap processor around the usual Pry.start to catch navigation commands
13
+ @processor.start
17
14
  else
18
15
  # No need for the tracer unless we have a file context to step through
19
16
  start_without_pry_byebug(target, options)
@@ -19,7 +19,9 @@ module PryRemote
19
19
  Pry.start @object, input: client.input_proxy, output: client.output
20
20
  end
21
21
 
22
+ #
22
23
  # Override to reset our saved global current server session.
24
+ #
23
25
  alias_method :teardown_without_pry_byebug, :teardown
24
26
  def teardown_with_pry_byebug
25
27
  return if @torn
@@ -33,7 +35,7 @@ module PryRemote
33
35
  end
34
36
 
35
37
  # Ensure cleanup when a program finishes without another break. For example,
36
- # 'next' on the last line of a program won't hit PryByebug::Processor#run,
38
+ # 'next' on the last line of a program won't hit Byebug::PryProcessor#run,
37
39
  # which normally handles cleanup.
38
40
  at_exit do
39
41
  PryByebug.current_remote_server.teardown if PryByebug.current_remote_server
@@ -1,3 +1,6 @@
1
+ #
2
+ # Main container module for Pry-Byebug functionality
3
+ #
1
4
  module PryByebug
2
- VERSION = '2.0.0'
5
+ VERSION = '3.0.0'
3
6
  end
@@ -0,0 +1,157 @@
1
+ class Pry
2
+ module Byebug
3
+ #
4
+ # Wrapper for Byebug.breakpoints that respects our Processor and has better
5
+ # failure behavior. Acts as an Enumerable.
6
+ #
7
+ module Breakpoints
8
+ extend Enumerable
9
+ extend self
10
+
11
+ #
12
+ # Breakpoint in a file:line location
13
+ #
14
+ class FileBreakpoint < SimpleDelegator
15
+ def source_code
16
+ Pry::Code.from_file(source).around(pos, 3).with_marker(pos)
17
+ end
18
+
19
+ def to_s
20
+ "#{source} @ #{pos}"
21
+ end
22
+ end
23
+
24
+ #
25
+ # Breakpoint in a Class#method location
26
+ #
27
+ class MethodBreakpoint < SimpleDelegator
28
+ def initialize(byebug_bp, method)
29
+ __setobj__ byebug_bp
30
+ @method = method
31
+ end
32
+
33
+ def source_code
34
+ Pry::Code.from_method(Pry::Method.from_str(@method))
35
+ end
36
+
37
+ def to_s
38
+ @method
39
+ end
40
+ end
41
+
42
+ def breakpoints
43
+ @breakpoints ||= []
44
+ end
45
+
46
+ #
47
+ # Adds a method breakpoint.
48
+ #
49
+ def add_method(method, expression = nil)
50
+ validate_expression expression
51
+ owner, name = method.split(/[\.#]/)
52
+ byebug_bp = ::Byebug::Breakpoint.add(owner, name.to_sym, expression)
53
+ bp = MethodBreakpoint.new byebug_bp, method
54
+ breakpoints << bp
55
+ bp
56
+ end
57
+
58
+ #
59
+ # Adds a file breakpoint.
60
+ #
61
+ def add_file(file, line, expression = nil)
62
+ real_file = (file != Pry.eval_path)
63
+ fail(ArgumentError, 'Invalid file!') if real_file && !File.exist?(file)
64
+ validate_expression expression
65
+
66
+ path = (real_file ? File.expand_path(file) : file)
67
+ bp = FileBreakpoint.new ::Byebug::Breakpoint.add(path, line, expression)
68
+ breakpoints << bp
69
+ bp
70
+ end
71
+
72
+ #
73
+ # Changes the conditional expression for a breakpoint.
74
+ #
75
+ def change(id, expression = nil)
76
+ validate_expression expression
77
+
78
+ breakpoint = find_by_id(id)
79
+ breakpoint.expr = expression
80
+ breakpoint
81
+ end
82
+
83
+ #
84
+ # Deletes an existing breakpoint with the given ID.
85
+ #
86
+ def delete(id)
87
+ deleted = ::Byebug.started? &&
88
+ ::Byebug::Breakpoint.remove(id) && breakpoints.delete(find_by_id(id))
89
+ fail(ArgumentError, "No breakpoint ##{id}") unless deleted
90
+ end
91
+
92
+ #
93
+ # Deletes all breakpoints.
94
+ #
95
+ def delete_all
96
+ @breakpoints = []
97
+ ::Byebug.breakpoints.clear if ::Byebug.started?
98
+ end
99
+
100
+ #
101
+ # Enables a disabled breakpoint with the given ID.
102
+ #
103
+ def enable(id)
104
+ change_status id, true
105
+ end
106
+
107
+ #
108
+ # Disables a breakpoint with the given ID.
109
+ #
110
+ def disable(id)
111
+ change_status id, false
112
+ end
113
+
114
+ #
115
+ # Disables all breakpoints.
116
+ #
117
+ def disable_all
118
+ each do |breakpoint|
119
+ breakpoint.enabled = false
120
+ end
121
+ end
122
+
123
+ def to_a
124
+ breakpoints
125
+ end
126
+
127
+ def size
128
+ to_a.size
129
+ end
130
+
131
+ def each(&block)
132
+ to_a.each(&block)
133
+ end
134
+
135
+ def find_by_id(id)
136
+ breakpoint = find { |b| b.id == id }
137
+ fail(ArgumentError, "No breakpoint ##{id}!") unless breakpoint
138
+ breakpoint
139
+ end
140
+
141
+ private
142
+
143
+ def change_status(id, enabled = true)
144
+ breakpoint = find_by_id(id)
145
+ breakpoint.enabled = enabled
146
+ breakpoint
147
+ end
148
+
149
+ def validate_expression(exp)
150
+ return unless exp &&
151
+ (exp.empty? || !Pry::Code.complete_expression?(exp))
152
+
153
+ fail("Invalid breakpoint conditional: #{expression}")
154
+ end
155
+ end
156
+ end
157
+ end
@@ -1,86 +1,13 @@
1
1
  require 'pry'
2
- require 'pry-byebug/breakpoints'
2
+ require 'pry/byebug/breakpoints'
3
3
 
4
4
  #
5
- # Container for all of pry-byebug's functionality
5
+ # Main Pry class.
6
6
  #
7
- module PryByebug
8
- Commands = Pry::CommandSet.new do
9
- create_command 'step' do
10
- description 'Step execution into the next line or method.'
11
-
12
- banner <<-BANNER
13
- Usage: step [TIMES]
14
- Aliases: s
15
-
16
- Step execution forward. By default, moves a single step.
17
-
18
- Examples:
19
-
20
- step Move a single step forward.
21
- step 5 Execute the next 5 steps.
22
- BANNER
23
-
24
- def process
25
- check_file_context
26
- breakout_navigation :step, args.first
27
- end
28
- end
29
- alias_command 's', 'step'
30
-
31
- create_command 'next' do
32
- description 'Execute the next line within the current stack frame.'
33
-
34
- banner <<-BANNER
35
- Usage: next [LINES]
36
- Aliases: n
37
-
38
- Step over within the same frame. By default, moves forward a single
39
- line.
40
-
41
- Examples:
42
-
43
- next Move a single line forward.
44
- next 4 Execute the next 4 lines.
45
- BANNER
46
-
47
- def process
48
- check_file_context
49
- breakout_navigation :next, args.first
50
- end
51
- end
52
- alias_command 'n', 'next'
53
-
54
- create_command 'finish' do
55
- description 'Execute until current stack frame returns.'
56
-
57
- banner <<-BANNER
58
- Usage: finish
59
- Aliases: f
60
- BANNER
61
-
62
- def process
63
- check_file_context
64
- breakout_navigation :finish
65
- end
66
- end
67
- alias_command 'f', 'finish'
68
-
69
- create_command 'continue' do
70
- description 'Continue program execution and end the Pry session.'
71
-
72
- banner <<-BANNER
73
- Usage: continue
74
- Aliases: c
75
- BANNER
76
-
77
- def process
78
- check_file_context
79
- breakout_navigation :continue
80
- end
81
- end
82
- alias_command 'c', 'continue'
83
-
7
+ # We're going to add to it custom breakpoint commands for Pry-Byebug
8
+ #
9
+ class Pry
10
+ BreakpointCommands = CommandSet.new do
84
11
  create_command 'break' do
85
12
  description 'Set or edit a breakpoint.'
86
13
 
@@ -139,7 +66,7 @@ module PryByebug
139
66
 
140
67
  %w(delete disable enable).each do |command|
141
68
  define_method(:"process_#{command}") do
142
- Breakpoints.send(command, opts[command])
69
+ breakpoints.send(command, opts[command])
143
70
  run 'breakpoints'
144
71
  end
145
72
  end
@@ -147,18 +74,18 @@ module PryByebug
147
74
  %w(disable-all delete-all).each do |command|
148
75
  method_name = command.gsub('-', '_')
149
76
  define_method(:"process_#{method_name}") do
150
- Breakpoints.send(method_name)
77
+ breakpoints.send(method_name)
151
78
  run 'breakpoints'
152
79
  end
153
80
  end
154
81
 
155
82
  def process_show
156
- print_full_breakpoint(Breakpoints.find_by_id(opts[:show]))
83
+ print_full_breakpoint(breakpoints.find_by_id(opts[:show]))
157
84
  end
158
85
 
159
86
  def process_condition
160
87
  expr = args.empty? ? nil : args.join(' ')
161
- Breakpoints.change(opts[:condition], expr)
88
+ breakpoints.change(opts[:condition], expr)
162
89
  end
163
90
 
164
91
  def new_breakpoint
@@ -168,21 +95,21 @@ module PryByebug
168
95
  bp =
169
96
  case place
170
97
  when /^(\d+)$/
171
- line = Regexp.last_match[1]
172
98
  errmsg = 'Line number declaration valid only in a file context.'
173
- check_file_context(errmsg)
99
+ PryByebug.check_file_context(target, errmsg)
174
100
 
175
- Breakpoints.add_file(target.eval('__FILE__'), line.to_i, condition)
101
+ file, lineno = target.eval('__FILE__'), Regexp.last_match[1].to_i
102
+ breakpoints.add_file(file, lineno, condition)
176
103
  when /^(.+):(\d+)$/
177
104
  file, lineno = Regexp.last_match[1], Regexp.last_match[2].to_i
178
- Breakpoints.add_file(file, lineno, condition)
105
+ breakpoints.add_file(file, lineno, condition)
179
106
  when /^(.*)[.#].+$/ # Method or class name
180
107
  if Regexp.last_match[1].strip.empty?
181
108
  errmsg = 'Method name declaration valid only in a file context.'
182
- check_file_context(errmsg)
109
+ PryByebug.check_file_context(target, errmsg)
183
110
  place = target.eval('self.class.to_s') + place
184
111
  end
185
- Breakpoints.add_method(place, condition)
112
+ breakpoints.add_method(place, condition)
186
113
  else
187
114
  fail(ArgumentError, 'Cannot identify arguments as breakpoint')
188
115
  end
@@ -207,33 +134,33 @@ module PryByebug
207
134
  end
208
135
 
209
136
  def process
210
- errmsg = 'No breakpoints defined.'
211
- return output.puts text.bold(errmsg) unless Breakpoints.count > 0
137
+ if breakpoints.count == 0
138
+ return output.puts(text.bold('No breakpoints defined.'))
139
+ end
212
140
 
213
141
  if opts.verbose?
214
- Breakpoints.each { |b| print_full_breakpoint(b) }
142
+ breakpoints.each { |b| print_full_breakpoint(b) }
215
143
  else
216
- output.puts
217
144
  print_breakpoints_header
218
- Breakpoints.each { |b| print_short_breakpoint(b) }
219
- output.puts
145
+ breakpoints.each { |b| print_short_breakpoint(b) }
220
146
  end
221
147
  end
222
148
  end
223
149
  alias_command 'breaks', 'breakpoints'
224
150
 
225
151
  helpers do
226
- def breakout_navigation(action, times = nil)
227
- _pry_.binding_stack.clear # Clear the binding stack.
228
-
229
- # Break out of the REPL loop and signal tracer
230
- throw :breakout_nav, action: action, times: times, pry: _pry_
152
+ #
153
+ # Byebug's array of breakpoints.
154
+ #
155
+ def breakpoints
156
+ Byebug::Breakpoints
231
157
  end
232
158
 
233
- # Ensures that a command is executed in a local file context.
234
- def check_file_context(e = nil)
235
- e ||= 'Cannot find local context. Did you use `binding.pry`?'
236
- fail(Pry::CommandError, e) unless PryByebug.check_file_context(target)
159
+ #
160
+ # Prints a message with bold font.
161
+ #
162
+ def bold_puts(msg)
163
+ output.puts(text.bold(msg))
237
164
  end
238
165
 
239
166
  #
@@ -241,28 +168,24 @@ module PryByebug
241
168
  #
242
169
  # Includes surrounding code at that point.
243
170
  #
244
- def print_full_breakpoint(breakpoint)
245
- output.print text.bold("Breakpoint #{breakpoint.id}: ")
246
- output.print "#{breakpoint} "
247
- output.print breakpoint.enabled? ? '(Enabled)' : '(Disabled)'
248
- output.puts ' :'
249
- if (expr = breakpoint.expr)
250
- output.puts "#{text.bold('Condition:')} #{expr}"
251
- end
252
- output.puts
253
- output.puts breakpoint.source_code.with_line_numbers.to_s
254
- output.puts
171
+ def print_full_breakpoint(br)
172
+ header = text.bold("Breakpoint #{br.id}:")
173
+ status = br.enabled? ? '(Enabled)' : '(Disabled)'
174
+ code = br.source_code.with_line_numbers.to_s
175
+ condition = br.expr ? "#{text.bold('Condition:')} #{br.expr}\n" : ''
176
+
177
+ output.puts("#{header} #{br} #{status} :\n#{condition}#{code}\n")
255
178
  end
256
179
 
257
180
  #
258
181
  # Print out concise information about a breakpoint.
259
182
  #
260
183
  def print_short_breakpoint(breakpoint)
261
- output.printf "%#{max_width}d ", breakpoint.id
262
- output.print breakpoint.enabled? ? 'Yes ' : 'No '
263
- output.print breakpoint.to_s
264
- output.print " (if #{breakpoint.expr})" if breakpoint.expr
265
- output.puts
184
+ id = sprintf('%*d ', max_width, breakpoint.id)
185
+ status = breakpoint.enabled? ? 'Yes' : 'No'
186
+ expr = breakpoint.expr ? breakpoint.expr : ''
187
+
188
+ output.puts("#{id} #{status} #{breakpoint} #{expr}")
266
189
  end
267
190
 
268
191
  #
@@ -271,18 +194,22 @@ module PryByebug
271
194
  def print_breakpoints_header
272
195
  header = "#{' ' * (max_width - 1)}# Enabled At "
273
196
 
274
- output.puts text.bold(header)
275
- output.puts text.bold('-' * header.size)
197
+ output.puts <<-EOP
198
+
199
+ #{text.bold(header)}
200
+ #{text.bold('-' * header.size)}
201
+
202
+ EOP
276
203
  end
277
204
 
278
205
  #
279
206
  # Max width of breakpoints id column
280
207
  #
281
208
  def max_width
282
- [Math.log10(Breakpoints.count).ceil, 1].max
209
+ [Math.log10(breakpoints.count).ceil, 1].max
283
210
  end
284
211
  end
285
212
  end
286
- end
287
213
 
288
- Pry.commands.import PryByebug::Commands
214
+ Pry.commands.import(BreakpointCommands)
215
+ end
@@ -0,0 +1,90 @@
1
+ require 'pry'
2
+
3
+ #
4
+ # Main Pry class.
5
+ #
6
+ # We're going to add to it custom stepping commands for Pry-Byebug
7
+ #
8
+ class Pry
9
+ SteppingCommands = CommandSet.new do
10
+ create_command 'step' do
11
+ description 'Step execution into the next line or method.'
12
+
13
+ banner <<-BANNER
14
+ Usage: step [TIMES]
15
+
16
+ Step execution forward. By default, moves a single step.
17
+
18
+ Examples:
19
+ step #=> Move a single step forward.
20
+ step 5 #=> Execute the next 5 steps.
21
+ BANNER
22
+
23
+ def process
24
+ PryByebug.check_file_context(target)
25
+
26
+ breakout_navigation :step, args.first
27
+ end
28
+ end
29
+
30
+ create_command 'next' do
31
+ description 'Execute the next line within the current stack frame.'
32
+
33
+ banner <<-BANNER
34
+ Usage: next [LINES]
35
+
36
+ Step over within the same frame. By default, moves forward a single
37
+ line.
38
+
39
+ Examples:
40
+ next #=> Move a single line forward.
41
+ next 4 #=> Execute the next 4 lines.
42
+ BANNER
43
+
44
+ def process
45
+ PryByebug.check_file_context(target)
46
+
47
+ breakout_navigation :next, args.first
48
+ end
49
+ end
50
+
51
+ create_command 'finish' do
52
+ description 'Execute until current stack frame returns.'
53
+
54
+ banner <<-BANNER
55
+ Usage: finish
56
+ BANNER
57
+
58
+ def process
59
+ PryByebug.check_file_context(target)
60
+
61
+ breakout_navigation :finish
62
+ end
63
+ end
64
+
65
+ create_command 'continue' do
66
+ description 'Continue program execution and end the Pry session.'
67
+
68
+ banner <<-BANNER
69
+ Usage: continue
70
+ BANNER
71
+
72
+ def process
73
+ PryByebug.check_file_context(target)
74
+
75
+ breakout_navigation :continue
76
+ end
77
+ end
78
+
79
+ helpers do
80
+ def breakout_navigation(action, times = nil)
81
+ _pry_.binding_stack.clear # Clear the binding stack.
82
+
83
+ # Break out of the REPL loop and signal tracer
84
+ throw :breakout_nav, action: action, times: times, pry: _pry_
85
+ end
86
+ end
87
+ end
88
+
89
+ Pry.commands.import(SteppingCommands)
90
+ end
@@ -6,11 +6,11 @@ require 'test_helper'
6
6
  class BaseTest < MiniTest::Spec
7
7
  def test_main_file_context
8
8
  Pry.stubs eval_path: '<main>'
9
- assert PryByebug.check_file_context(TOPLEVEL_BINDING)
9
+ assert PryByebug.file_context?(TOPLEVEL_BINDING)
10
10
  end
11
11
 
12
12
  def test_other_file_context
13
13
  Pry.stubs eval_path: 'something'
14
- refute PryByebug.check_file_context(TOPLEVEL_BINDING)
14
+ refute PryByebug.file_context?(TOPLEVEL_BINDING)
15
15
  end
16
16
  end
@@ -4,14 +4,6 @@ require 'test_helper'
4
4
  # Tests for pry-byebug breakpoints.
5
5
  #
6
6
  class BreakpointsTestGeneral < MiniTest::Spec
7
- def test_add_file_raises_argument_error
8
- Pry.stubs eval_path: 'something'
9
- File.stubs :exist?
10
- assert_raises(ArgumentError) do
11
- PryByebug::Breakpoints.add_file('file', 1)
12
- end
13
- end
14
-
15
7
  #
16
8
  # Minimal dummy example class.
17
9
  #
@@ -20,9 +12,21 @@ class BreakpointsTestGeneral < MiniTest::Spec
20
12
  def instance_method; end
21
13
  end
22
14
 
15
+ def breakpoints_class
16
+ Pry::Byebug::Breakpoints
17
+ end
18
+
19
+ def test_add_file_raises_argument_error
20
+ Pry.stubs eval_path: 'something'
21
+ File.stubs :exist?
22
+ assert_raises(ArgumentError) do
23
+ breakpoints_class.add_file('file', 1)
24
+ end
25
+ end
26
+
23
27
  def test_add_method_adds_instance_method_breakpoint
24
- Pry.stub :processor, PryByebug::Processor.new do
25
- PryByebug::Breakpoints.add_method 'BreakpointsTest::Tester#instance_method'
28
+ Pry.stub :processor, Byebug::PryProcessor.new do
29
+ breakpoints_class.add_method 'BreakpointsTest::Tester#instance_method'
26
30
  bp = Byebug.breakpoints.last
27
31
  assert_equal 'BreakpointsTest::Tester', bp.source
28
32
  assert_equal 'instance_method', bp.pos
@@ -30,8 +34,8 @@ class BreakpointsTestGeneral < MiniTest::Spec
30
34
  end
31
35
 
32
36
  def test_add_method_adds_class_method_breakpoint
33
- Pry.stub :processor, PryByebug::Processor.new do
34
- PryByebug::Breakpoints.add_method 'BreakpointsTest::Tester.class_method'
37
+ Pry.stub :processor, Byebug::PryProcessor.new do
38
+ breakpoints_class.add_method 'BreakpointsTest::Tester.class_method'
35
39
  bp = Byebug.breakpoints.last
36
40
  assert_equal 'BreakpointsTest::Tester', bp.source
37
41
  assert_equal 'class_method', bp.pos
@@ -0,0 +1,9 @@
1
+ #
2
+ # Toy program for testing binding.pry initialization
3
+ #
4
+
5
+ new_str = 'string'.gsub!(/str/) do |_|
6
+ binding.pry
7
+ end
8
+
9
+ new_str
@@ -23,4 +23,17 @@ class ProcessorTest < Minitest::Spec
23
23
  @output.string.must_match(/\=> 6:/)
24
24
  end
25
25
  end
26
+
27
+ describe 'Initialization at the end of block/method call' do
28
+ let(:step_file) { test_file('deep_stepping') }
29
+
30
+ before do
31
+ @input, @output = InputTester.new, StringIO.new
32
+ redirect_pry_io(@input, @output) { load step_file }
33
+ end
34
+
35
+ it 'stops execution at the first line after binding.pry' do
36
+ @output.string.must_match(/\=> 7:/)
37
+ end
38
+ end
26
39
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: pry-byebug
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.0.0
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - David Rodríguez
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2014-09-01 00:00:00.000000000 Z
12
+ date: 2015-02-02 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: pry
@@ -55,21 +55,23 @@ files:
55
55
  - LICENSE
56
56
  - README.md
57
57
  - Rakefile
58
+ - lib/byebug/processors/pry_processor.rb
58
59
  - lib/pry-byebug.rb
59
60
  - lib/pry-byebug/base.rb
60
- - lib/pry-byebug/breakpoints.rb
61
61
  - lib/pry-byebug/cli.rb
62
- - lib/pry-byebug/commands.rb
63
- - lib/pry-byebug/processor.rb
64
62
  - lib/pry-byebug/pry_ext.rb
65
63
  - lib/pry-byebug/pry_remote_ext.rb
66
64
  - lib/pry-byebug/version.rb
65
+ - lib/pry/byebug/breakpoints.rb
66
+ - lib/pry/commands/breakpoint.rb
67
+ - lib/pry/commands/stepping.rb
67
68
  - pry-byebug.gemspec
68
69
  - test/base_test.rb
69
70
  - test/breakpoints_test.rb
70
71
  - test/commands_test.rb
71
72
  - test/examples/break1.rb
72
73
  - test/examples/break2.rb
74
+ - test/examples/deep_stepping.rb
73
75
  - test/examples/stepping.rb
74
76
  - test/processor_test.rb
75
77
  - test/pry_ext_test.rb
@@ -95,7 +97,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
95
97
  version: '0'
96
98
  requirements: []
97
99
  rubyforge_project:
98
- rubygems_version: 2.4.1
100
+ rubygems_version: 2.4.5
99
101
  signing_key:
100
102
  specification_version: 4
101
103
  summary: Fast debugging with Pry.
@@ -105,6 +107,7 @@ test_files:
105
107
  - test/commands_test.rb
106
108
  - test/examples/break1.rb
107
109
  - test/examples/break2.rb
110
+ - test/examples/deep_stepping.rb
108
111
  - test/examples/stepping.rb
109
112
  - test/processor_test.rb
110
113
  - test/pry_ext_test.rb
@@ -1,154 +0,0 @@
1
- module PryByebug
2
- #
3
- # Wrapper for Byebug.breakpoints that respects our Processor and has better
4
- # failure behavior. Acts as an Enumerable.
5
- #
6
- module Breakpoints
7
- extend Enumerable
8
- extend self
9
-
10
- #
11
- # Breakpoint in a file:line location
12
- #
13
- class FileBreakpoint < SimpleDelegator
14
- def source_code
15
- Pry::Code.from_file(source).around(pos, 3).with_marker(pos)
16
- end
17
-
18
- def to_s
19
- "#{source} @ #{pos}"
20
- end
21
- end
22
-
23
- #
24
- # Breakpoint in a Class#method location
25
- #
26
- class MethodBreakpoint < SimpleDelegator
27
- def initialize(byebug_bp, method)
28
- __setobj__ byebug_bp
29
- @method = method
30
- end
31
-
32
- def source_code
33
- Pry::Code.from_method(Pry::Method.from_str(@method))
34
- end
35
-
36
- def to_s
37
- @method
38
- end
39
- end
40
-
41
- def breakpoints
42
- @breakpoints ||= []
43
- end
44
-
45
- #
46
- # Adds a method breakpoint.
47
- #
48
- def add_method(method, expression = nil)
49
- validate_expression expression
50
- owner, name = method.split(/[\.#]/)
51
- byebug_bp = Byebug::Breakpoint.add(owner, name.to_sym, expression)
52
- bp = MethodBreakpoint.new byebug_bp, method
53
- breakpoints << bp
54
- bp
55
- end
56
-
57
- #
58
- # Adds a file breakpoint.
59
- #
60
- def add_file(file, line, expression = nil)
61
- real_file = (file != Pry.eval_path)
62
- fail(ArgumentError, 'Invalid file!') if real_file && !File.exist?(file)
63
- validate_expression expression
64
-
65
- path = (real_file ? File.expand_path(file) : file)
66
- bp = FileBreakpoint.new Byebug::Breakpoint.add(path, line, expression)
67
- breakpoints << bp
68
- bp
69
- end
70
-
71
- #
72
- # Changes the conditional expression for a breakpoint.
73
- #
74
- def change(id, expression = nil)
75
- validate_expression expression
76
-
77
- breakpoint = find_by_id(id)
78
- breakpoint.expr = expression
79
- breakpoint
80
- end
81
-
82
- #
83
- # Deletes an existing breakpoint with the given ID.
84
- #
85
- def delete(id)
86
- deleted = Byebug.started? &&
87
- Byebug::Breakpoint.remove(id) && breakpoints.delete(find_by_id(id))
88
- fail(ArgumentError, "No breakpoint ##{id}") unless deleted
89
- end
90
-
91
- #
92
- # Deletes all breakpoints.
93
- #
94
- def delete_all
95
- @breakpoints = []
96
- Byebug.breakpoints.clear if Byebug.started?
97
- end
98
-
99
- #
100
- # Enables a disabled breakpoint with the given ID.
101
- #
102
- def enable(id)
103
- change_status id, true
104
- end
105
-
106
- #
107
- # Disables a breakpoint with the given ID.
108
- #
109
- def disable(id)
110
- change_status id, false
111
- end
112
-
113
- #
114
- # Disables all breakpoints.
115
- #
116
- def disable_all
117
- each do |breakpoint|
118
- breakpoint.enabled = false
119
- end
120
- end
121
-
122
- def to_a
123
- breakpoints
124
- end
125
-
126
- def size
127
- to_a.size
128
- end
129
-
130
- def each(&block)
131
- to_a.each(&block)
132
- end
133
-
134
- def find_by_id(id)
135
- breakpoint = find { |b| b.id == id }
136
- fail(ArgumentError, "No breakpoint ##{id}!") unless breakpoint
137
- breakpoint
138
- end
139
-
140
- private
141
-
142
- def change_status(id, enabled = true)
143
- breakpoint = find_by_id(id)
144
- breakpoint.enabled = enabled
145
- breakpoint
146
- end
147
-
148
- def validate_expression(exp)
149
- return unless exp && (exp.empty? || !Pry::Code.complete_expression?(exp))
150
-
151
- fail("Invalid breakpoint conditional: #{expression}")
152
- end
153
- end
154
- end