pry-byebug-reloaded 3.10.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,167 @@
1
+ # frozen_string_literal: true
2
+
3
+ class Pry
4
+ module Byebug
5
+ #
6
+ # Wrapper for Byebug.breakpoints that respects our Processor and has better
7
+ # failure behavior. Acts as an Enumerable.
8
+ #
9
+ module Breakpoints
10
+ extend Enumerable
11
+ extend self
12
+
13
+ #
14
+ # Breakpoint in a file:line location
15
+ #
16
+ class FileBreakpoint < SimpleDelegator
17
+ def source_code
18
+ Pry::Code.from_file(source).around(pos, 3).with_marker(pos)
19
+ end
20
+
21
+ def to_s
22
+ "#{source} @ #{pos}"
23
+ end
24
+ end
25
+
26
+ #
27
+ # Breakpoint in a Class#method location
28
+ #
29
+ class MethodBreakpoint < SimpleDelegator
30
+ def initialize(byebug_bp, method)
31
+ __setobj__ byebug_bp
32
+ @method = method
33
+ end
34
+
35
+ def source_code
36
+ Pry::Code.from_method(Pry::Method.from_str(@method))
37
+ end
38
+
39
+ def to_s
40
+ @method
41
+ end
42
+ end
43
+
44
+ def breakpoints
45
+ @breakpoints ||= []
46
+ end
47
+
48
+ #
49
+ # Adds a method breakpoint.
50
+ #
51
+ def add_method(method, expression = nil)
52
+ validate_expression expression
53
+ owner, name = method.split(/[\.#]/)
54
+ byebug_bp = ::Byebug::Breakpoint.add(owner, name.to_sym, expression)
55
+ bp = MethodBreakpoint.new byebug_bp, method
56
+ breakpoints << bp
57
+ bp
58
+ end
59
+
60
+ #
61
+ # Adds a file breakpoint.
62
+ #
63
+ def add_file(file, line, expression = nil)
64
+ real_file = (file != Pry.eval_path)
65
+ raise(ArgumentError, "Invalid file!") if real_file && !File.exist?(file)
66
+
67
+ validate_expression expression
68
+
69
+ path = (real_file ? File.expand_path(file) : file)
70
+ bp = FileBreakpoint.new ::Byebug::Breakpoint.add(path, line, expression)
71
+ breakpoints << bp
72
+ bp
73
+ end
74
+
75
+ #
76
+ # Changes the conditional expression for a breakpoint.
77
+ #
78
+ def change(id, expression = nil)
79
+ validate_expression expression
80
+
81
+ breakpoint = find_by_id(id)
82
+ breakpoint.expr = expression
83
+ breakpoint
84
+ end
85
+
86
+ #
87
+ # Deletes an existing breakpoint with the given ID.
88
+ #
89
+ def delete(id)
90
+ deleted =
91
+ ::Byebug::Breakpoint.remove(id) &&
92
+ breakpoints.delete(find_by_id(id))
93
+
94
+ raise(ArgumentError, "No breakpoint ##{id}") unless deleted
95
+ end
96
+
97
+ #
98
+ # Deletes all breakpoints.
99
+ #
100
+ def delete_all
101
+ @breakpoints = []
102
+ ::Byebug.breakpoints.clear
103
+ end
104
+
105
+ #
106
+ # Enables a disabled breakpoint with the given ID.
107
+ #
108
+ def enable(id)
109
+ change_status id, true
110
+ end
111
+
112
+ #
113
+ # Disables a breakpoint with the given ID.
114
+ #
115
+ def disable(id)
116
+ change_status id, false
117
+ end
118
+
119
+ #
120
+ # Disables all breakpoints.
121
+ #
122
+ def disable_all
123
+ each do |breakpoint|
124
+ breakpoint.enabled = false
125
+ end
126
+ end
127
+
128
+ def to_a
129
+ breakpoints
130
+ end
131
+
132
+ def size
133
+ to_a.size
134
+ end
135
+
136
+ def each(&block)
137
+ to_a.each(&block)
138
+ end
139
+
140
+ def last
141
+ to_a.last
142
+ end
143
+
144
+ def find_by_id(id)
145
+ breakpoint = find { |b| b.id == id }
146
+ raise(ArgumentError, "No breakpoint ##{id}!") unless breakpoint
147
+
148
+ breakpoint
149
+ end
150
+
151
+ private
152
+
153
+ def change_status(id, enabled = true)
154
+ breakpoint = find_by_id(id)
155
+ breakpoint.enabled = enabled
156
+ breakpoint
157
+ end
158
+
159
+ def validate_expression(exp)
160
+ valid = exp && (exp.empty? || !Pry::Code.complete_expression?(exp))
161
+ return unless valid
162
+
163
+ raise("Invalid breakpoint conditional: #{expression}")
164
+ end
165
+ end
166
+ end
167
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/location"
4
+
5
+ #
6
+ # Main container module for Pry-Byebug functionality
7
+ #
8
+ module PryByebug
9
+ # Reference to currently running pry-remote server. Used by the processor.
10
+ attr_accessor :current_remote_server
11
+
12
+ module_function
13
+
14
+ #
15
+ # Checks that a target binding is in a local file context.
16
+ #
17
+ def file_context?(target)
18
+ file = Helpers::Location.current_file(target)
19
+ file == Pry.eval_path || !Pry::Helpers::BaseHelpers.not_a_real_file?(file)
20
+ end
21
+
22
+ #
23
+ # Ensures that a command is executed in a local file context.
24
+ #
25
+ def check_file_context(target, msg = nil)
26
+ msg ||= "Cannot find local context. Did you use `binding.pry`?"
27
+ raise(Pry::CommandError, msg) unless file_context?(target)
28
+ end
29
+ end
@@ -0,0 +1,6 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/base"
4
+ require "pry-byebug/pry_ext"
5
+ require "pry-byebug/commands"
6
+ require "pry-byebug/control_d_handler"
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+
5
+ module PryByebug
6
+ #
7
+ # Display the current stack
8
+ #
9
+ class BacktraceCommand < Pry::ClassCommand
10
+ include Helpers::Navigation
11
+
12
+ match "backtrace"
13
+ group "Byebug"
14
+
15
+ description "Display the current stack."
16
+
17
+ banner <<-BANNER
18
+ Usage: backtrace
19
+
20
+ Display the current stack.
21
+ BANNER
22
+
23
+ def process
24
+ PryByebug.check_file_context(target)
25
+
26
+ breakout_navigation :backtrace
27
+ end
28
+ end
29
+ end
30
+
31
+ Pry::Commands.add_command(PryByebug::BacktraceCommand)
@@ -0,0 +1,137 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry/byebug/breakpoints"
4
+ require "pry-byebug/helpers/breakpoints"
5
+ require "pry-byebug/helpers/location"
6
+ require "pry-byebug/helpers/multiline"
7
+
8
+ module PryByebug
9
+ #
10
+ # Add, show and remove breakpoints
11
+ #
12
+ class BreakCommand < Pry::ClassCommand
13
+ include Helpers::Breakpoints
14
+ include Helpers::Location
15
+ include Helpers::Multiline
16
+
17
+ match "break"
18
+ group "Byebug"
19
+ description "Set or edit a breakpoint."
20
+
21
+ banner <<-BANNER
22
+ Usage: break <METHOD | FILE:LINE | LINE> [if CONDITION]
23
+ break --condition N [CONDITION]
24
+ break [--show | --delete | --enable | --disable] N
25
+ break [--delete-all | --disable-all]
26
+ break
27
+
28
+ Set a breakpoint. Accepts a line number in the current file, a file and
29
+ line number, or a method, and an optional condition.
30
+
31
+ Pass appropriate flags to manipulate existing breakpoints.
32
+
33
+ Examples:
34
+
35
+ break SomeClass#run Break at the start of `SomeClass#run`.
36
+ break Foo#bar if baz? Break at `Foo#bar` only if `baz?`.
37
+ break app/models/user.rb:15 Break at line 15 in user.rb.
38
+ break 14 Break at line 14 in the current file.
39
+
40
+ break --condition 4 x > 2 Add/change condition on breakpoint #4.
41
+ break --condition 3 Remove the condition on breakpoint #3.
42
+
43
+ break --delete 5 Delete breakpoint #5.
44
+ break --disable-all Disable all breakpoints.
45
+
46
+ break --show 2 Show details about breakpoint #2.
47
+ break List all breakpoints.
48
+ BANNER
49
+
50
+ def options(opt)
51
+ defaults = { argument: true, as: Integer }
52
+
53
+ opt.on :c, :condition, "Change condition of a breakpoint.", defaults
54
+ opt.on :s, :show, "Show breakpoint details and source.", defaults
55
+ opt.on :D, :delete, "Delete a breakpoint.", defaults
56
+ opt.on :d, :disable, "Disable a breakpoint.", defaults
57
+ opt.on :e, :enable, "Enable a disabled breakpoint.", defaults
58
+ opt.on :'disable-all', "Disable all breakpoints."
59
+ opt.on :'delete-all', "Delete all breakpoints."
60
+ end
61
+
62
+ def process
63
+ return if check_multiline_context
64
+
65
+ PryByebug.check_file_context(target)
66
+
67
+ option, = opts.to_hash.find { |key, _value| opts.present?(key) }
68
+ return send(option_to_method(option)) if option
69
+
70
+ return new_breakpoint unless args.empty?
71
+
72
+ print_all
73
+ end
74
+
75
+ private
76
+
77
+ %w[delete disable enable disable_all delete_all].each do |command|
78
+ define_method(:"process_#{command}") do
79
+ breakpoints.send(*[command, opts[command]].compact)
80
+ print_all
81
+ end
82
+ end
83
+
84
+ def process_show
85
+ print_full_breakpoint(breakpoints.find_by_id(opts[:show]))
86
+ end
87
+
88
+ def process_condition
89
+ expr = args.empty? ? nil : args.join(" ")
90
+ breakpoints.change(opts[:condition], expr)
91
+ end
92
+
93
+ def new_breakpoint
94
+ place = args.shift
95
+ condition = args.join(" ") if args.shift == "if"
96
+
97
+ bp = add_breakpoint(place, condition)
98
+
99
+ print_full_breakpoint(bp)
100
+ end
101
+
102
+ def option_to_method(option)
103
+ "process_#{option.to_s.tr('-', '_')}"
104
+ end
105
+
106
+ def print_all
107
+ print_breakpoints_header
108
+ breakpoints.each { |b| print_short_breakpoint(b) }
109
+ end
110
+
111
+ def add_breakpoint(place, condition)
112
+ case place
113
+ when /^(\d+)$/
114
+ errmsg = "Line number declaration valid only in a file context."
115
+ PryByebug.check_file_context(target, errmsg)
116
+
117
+ lineno = Regexp.last_match[1].to_i
118
+ breakpoints.add_file(current_file, lineno, condition)
119
+ when /^(.+):(\d+)$/
120
+ file = Regexp.last_match[1]
121
+ lineno = Regexp.last_match[2].to_i
122
+ breakpoints.add_file(file, lineno, condition)
123
+ when /^(.*)[.#].+$/ # Method or class name
124
+ if Regexp.last_match[1].strip.empty?
125
+ errmsg = "Method name declaration valid only in a file context."
126
+ PryByebug.check_file_context(target, errmsg)
127
+ place = target.eval("self.class.to_s") + place
128
+ end
129
+ breakpoints.add_method(place, condition)
130
+ else
131
+ raise(ArgumentError, "Cannot identify arguments as breakpoint")
132
+ end
133
+ end
134
+ end
135
+ end
136
+
137
+ Pry::Commands.add_command(PryByebug::BreakCommand)
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+ require "pry-byebug/helpers/breakpoints"
5
+ require "pry-byebug/helpers/location"
6
+
7
+ module PryByebug
8
+ #
9
+ # Continue program execution until the next breakpoint
10
+ #
11
+ class ContinueCommand < Pry::ClassCommand
12
+ include Helpers::Navigation
13
+ include Helpers::Breakpoints
14
+ include Helpers::Location
15
+
16
+ match "continue"
17
+ group "Byebug"
18
+ description "Continue program execution and end the Pry session."
19
+
20
+ banner <<-BANNER
21
+ Usage: continue [LINE]
22
+
23
+ Continue program execution until the next breakpoint, or the program
24
+ ends. Optionally continue to the specified line number.
25
+
26
+ Examples:
27
+ continue #=> Continue until the next breakpoint.
28
+ continue 4 #=> Continue to line number 4.
29
+ BANNER
30
+
31
+ def process
32
+ PryByebug.check_file_context(target)
33
+
34
+ breakpoints.add_file(current_file, args.first.to_i) if args.first
35
+
36
+ breakout_navigation :continue
37
+ ensure
38
+ Byebug.stop if Byebug.stoppable?
39
+ end
40
+ end
41
+ end
42
+
43
+ Pry::Commands.add_command(PryByebug::ContinueCommand)
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+
5
+ module PryByebug
6
+ #
7
+ # Travel down the frame stack
8
+ #
9
+ class DownCommand < Pry::ClassCommand
10
+ include Helpers::Navigation
11
+
12
+ match "down"
13
+ group "Byebug"
14
+
15
+ description "Move current frame down."
16
+
17
+ banner <<-BANNER
18
+ Usage: down [TIMES]
19
+
20
+ Move current frame down. By default, moves by 1 frame.
21
+
22
+ Examples:
23
+ down #=> Move down 1 frame.
24
+ down 5 #=> Move down 5 frames.
25
+ BANNER
26
+
27
+ def process
28
+ PryByebug.check_file_context(target)
29
+
30
+ breakout_navigation :down, times: args.first
31
+ end
32
+ end
33
+ end
34
+
35
+ Pry::Commands.add_command(PryByebug::DownCommand)
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry/commands/exit_all"
4
+
5
+ module PryByebug
6
+ #
7
+ # Exit pry REPL with Byebug.stop
8
+ #
9
+ class ExitAllCommand < Pry::Command::ExitAll
10
+ def process
11
+ super
12
+ ensure
13
+ Byebug.stop if Byebug.stoppable?
14
+ end
15
+ end
16
+ end
17
+
18
+ Pry::Commands.add_command(PryByebug::ExitAllCommand)
@@ -0,0 +1,28 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+
5
+ module PryByebug
6
+ #
7
+ # Run until the end of current frame
8
+ #
9
+ class FinishCommand < Pry::ClassCommand
10
+ include PryByebug::Helpers::Navigation
11
+
12
+ match "finish"
13
+ group "Byebug"
14
+ description "Execute until current stack frame returns."
15
+
16
+ banner <<-BANNER
17
+ Usage: finish
18
+ BANNER
19
+
20
+ def process
21
+ PryByebug.check_file_context(target)
22
+
23
+ breakout_navigation :finish
24
+ end
25
+ end
26
+ end
27
+
28
+ Pry::Commands.add_command(PryByebug::FinishCommand)
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+
5
+ module PryByebug
6
+ #
7
+ # Move to a specific frame in the callstack
8
+ #
9
+ class FrameCommand < Pry::ClassCommand
10
+ include Helpers::Navigation
11
+
12
+ match "frame"
13
+ group "Byebug"
14
+
15
+ description "Move to specified frame #."
16
+
17
+ banner <<-BANNER
18
+ Usage: frame [TIMES]
19
+
20
+ Move to specified frame #.
21
+
22
+ Examples:
23
+ frame #=> Show current frame #.
24
+ frame 5 #=> Move to frame 5.
25
+ BANNER
26
+
27
+ def process
28
+ PryByebug.check_file_context(target)
29
+
30
+ breakout_navigation :frame, index: args.first
31
+ end
32
+ end
33
+ end
34
+
35
+ Pry::Commands.add_command(PryByebug::FrameCommand)
@@ -0,0 +1,39 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+ require "pry-byebug/helpers/multiline"
5
+
6
+ module PryByebug
7
+ #
8
+ # Run a number of lines and then stop again
9
+ #
10
+ class NextCommand < Pry::ClassCommand
11
+ include Helpers::Navigation
12
+ include Helpers::Multiline
13
+
14
+ match "next"
15
+ group "Byebug"
16
+ description "Execute the next line within the current stack frame."
17
+
18
+ banner <<-BANNER
19
+ Usage: next [LINES]
20
+
21
+ Step over within the same frame. By default, moves forward a single
22
+ line.
23
+
24
+ Examples:
25
+ next #=> Move a single line forward.
26
+ next 4 #=> Execute the next 4 lines.
27
+ BANNER
28
+
29
+ def process
30
+ return if check_multiline_context
31
+
32
+ PryByebug.check_file_context(target)
33
+
34
+ breakout_navigation :next, lines: args.first
35
+ end
36
+ end
37
+ end
38
+
39
+ Pry::Commands.add_command(PryByebug::NextCommand)
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+
5
+ module PryByebug
6
+ #
7
+ # Run a number of Ruby statements and then stop again
8
+ #
9
+ class StepCommand < Pry::ClassCommand
10
+ include Helpers::Navigation
11
+
12
+ match "step"
13
+ group "Byebug"
14
+ description "Step execution into the next line or method."
15
+
16
+ banner <<-BANNER
17
+ Usage: step [TIMES]
18
+
19
+ Step execution forward. By default, moves a single step.
20
+
21
+ Examples:
22
+ step #=> Move a single step forward.
23
+ step 5 #=> Execute the next 5 steps.
24
+ BANNER
25
+
26
+ def process
27
+ PryByebug.check_file_context(target)
28
+
29
+ breakout_navigation :step, times: args.first
30
+ end
31
+ end
32
+ end
33
+
34
+ Pry::Commands.add_command(PryByebug::StepCommand)
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/helpers/navigation"
4
+
5
+ module PryByebug
6
+ #
7
+ # Travel up the frame stack
8
+ #
9
+ class UpCommand < Pry::ClassCommand
10
+ include Helpers::Navigation
11
+
12
+ match "up"
13
+ group "Byebug"
14
+
15
+ description "Move current frame up."
16
+
17
+ banner <<-BANNER
18
+ Usage: up [TIMES]
19
+
20
+ Move current frame up. By default, moves by 1 frame.
21
+
22
+ Examples:
23
+ up #=> Move up 1 frame.
24
+ up 5 #=> Move up 5 frames.
25
+ BANNER
26
+
27
+ def process
28
+ PryByebug.check_file_context(target)
29
+
30
+ breakout_navigation :up, times: args.first
31
+ end
32
+ end
33
+ end
34
+
35
+ Pry::Commands.add_command(PryByebug::UpCommand)
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "pry-byebug/commands/backtrace"
4
+ require "pry-byebug/commands/next"
5
+ require "pry-byebug/commands/step"
6
+ require "pry-byebug/commands/continue"
7
+ require "pry-byebug/commands/finish"
8
+ require "pry-byebug/commands/up"
9
+ require "pry-byebug/commands/down"
10
+ require "pry-byebug/commands/frame"
11
+ require "pry-byebug/commands/breakpoint"
12
+ require "pry-byebug/commands/exit_all"
@@ -0,0 +1,9 @@
1
+ # frozen_string_literal: true
2
+
3
+ original_handler = Pry.config.control_d_handler
4
+
5
+ Pry.config.control_d_handler = proc do |pry_instance|
6
+ Byebug.stop if Byebug.stoppable?
7
+
8
+ original_handler.call(pry_instance)
9
+ end