Skip to content

Commit f311c91

Browse files
authored
Minor fixes on debug command (#447)
* Minor fixes on debug command * Update lib/irb/cmd/debug.rb
1 parent 30faa13 commit f311c91

File tree

2 files changed

+59
-20
lines changed

2 files changed

+59
-20
lines changed

lib/irb.rb

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -393,8 +393,6 @@ def IRB.irb_abort(irb, exception = Abort)
393393
end
394394

395395
class Irb
396-
DIR_NAME = __dir__
397-
398396
ASSIGNMENT_NODE_TYPES = [
399397
# Local, instance, global, class, constant, instance, and index assignment:
400398
# "foo = bar",
@@ -436,13 +434,14 @@ def initialize(workspace = nil, input_method = nil)
436434
@scanner = RubyLex.new
437435
end
438436

437+
# A hook point for `debug` command's TracePoint after :IRB_EXIT as well as its clean-up
439438
def debug_break
440439
# it means the debug command is executed
441-
if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:original_capture_frames)
440+
if defined?(DEBUGGER__) && DEBUGGER__.respond_to?(:capture_frames_without_irb)
442441
# after leaving this initial breakpoint, revert the capture_frames patch
443-
DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :original_capture_frames)
442+
DEBUGGER__.singleton_class.send(:alias_method, :capture_frames, :capture_frames_without_irb)
444443
# and remove the redundant method
445-
DEBUGGER__.singleton_class.send(:undef_method, :original_capture_frames)
444+
DEBUGGER__.singleton_class.send(:undef_method, :capture_frames_without_irb)
446445
end
447446
end
448447

lib/irb/cmd/debug.rb

Lines changed: 55 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -5,28 +5,68 @@ module IRB
55

66
module ExtendCommand
77
class Debug < Nop
8+
BINDING_IRB_FRAME_REGEXPS = [
9+
'<internal:prelude>',
10+
binding.method(:irb).source_location.first,
11+
].map { |file| /\A#{Regexp.escape(file)}:\d+:in `irb'\z/ }
12+
IRB_DIR = File.expand_path('..', __dir__)
13+
814
def execute(*args)
9-
require "debug/session"
10-
DEBUGGER__.start(nonstop: true)
11-
DEBUGGER__.singleton_class.send(:alias_method, :original_capture_frames, :capture_frames)
12-
13-
def DEBUGGER__.capture_frames(skip_path_prefix)
14-
frames = original_capture_frames(skip_path_prefix)
15-
frames.reject! do |frame|
16-
frame.realpath&.start_with?(::IRB::Irb::DIR_NAME) || frame.path.match?(/internal:prelude/)
17-
end
18-
frames
15+
unless binding_irb?
16+
puts "`debug` command is only available when IRB is started with binding.irb"
17+
return
1918
end
2019

20+
unless setup_debugger
21+
puts <<~MSG
22+
You need to install the debug gem before using this command.
23+
If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
24+
MSG
25+
return
26+
end
27+
28+
# To make debugger commands like `next` or `continue` work without asking
29+
# the user to quit IRB after that, we need to exit IRB first and then hit
30+
# a TracePoint on #debug_break.
2131
file, lineno = IRB::Irb.instance_method(:debug_break).source_location
2232
DEBUGGER__::SESSION.add_line_breakpoint(file, lineno + 1, oneshot: true, hook_call: false)
2333
# exit current Irb#run call
2434
throw :IRB_EXIT
25-
rescue LoadError => e
26-
puts <<~MSG
27-
You need to install the debug gem before using this command.
28-
If you use `bundle exec`, please add `gem "debug"` into your Gemfile.
29-
MSG
35+
end
36+
37+
private
38+
39+
def binding_irb?
40+
caller.any? do |frame|
41+
BINDING_IRB_FRAME_REGEXPS.any? do |regexp|
42+
frame.match?(regexp)
43+
end
44+
end
45+
end
46+
47+
def setup_debugger
48+
unless defined?(DEBUGGER__::SESSION)
49+
begin
50+
require "debug/session"
51+
rescue LoadError
52+
return false
53+
end
54+
DEBUGGER__.start(nonstop: true)
55+
end
56+
57+
unless DEBUGGER__.respond_to?(:capture_frames_without_irb)
58+
DEBUGGER__.singleton_class.send(:alias_method, :capture_frames_without_irb, :capture_frames)
59+
60+
def DEBUGGER__.capture_frames(*args)
61+
frames = capture_frames_without_irb(*args)
62+
frames.reject! do |frame|
63+
frame.realpath&.start_with?(IRB_DIR) || frame.path == "<internal:prelude>"
64+
end
65+
frames
66+
end
67+
end
68+
69+
true
3070
end
3171
end
3272
end

0 commit comments

Comments
 (0)