byebug 0.0.1
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.
- data/.gitignore +10 -0
- data/.travis.yml +8 -0
- data/AUTHORS +10 -0
- data/CHANGELOG.md +2 -0
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +3 -0
- data/LICENSE +20 -0
- data/README.md +5 -0
- data/Rakefile +28 -0
- data/bin/byebug +395 -0
- data/byebug.gemspec +29 -0
- data/doc/hanoi.rb +35 -0
- data/doc/primes.rb +28 -0
- data/doc/rdebug-emacs.texi +1030 -0
- data/doc/test-tri2.rb +18 -0
- data/doc/tri3.rb +8 -0
- data/doc/triangle.rb +12 -0
- data/ext/byebug/breakpoint.c +476 -0
- data/ext/byebug/byebug.c +512 -0
- data/ext/byebug/byebug.h +131 -0
- data/ext/byebug/context.c +424 -0
- data/ext/byebug/extconf.rb +21 -0
- data/ext/byebug/locker.c +53 -0
- data/lib/byebug.rb +404 -0
- data/lib/byebug/command.rb +232 -0
- data/lib/byebug/commands/breakpoints.rb +153 -0
- data/lib/byebug/commands/catchpoint.rb +56 -0
- data/lib/byebug/commands/condition.rb +49 -0
- data/lib/byebug/commands/continue.rb +38 -0
- data/lib/byebug/commands/control.rb +110 -0
- data/lib/byebug/commands/display.rb +122 -0
- data/lib/byebug/commands/edit.rb +48 -0
- data/lib/byebug/commands/enable.rb +202 -0
- data/lib/byebug/commands/eval.rb +176 -0
- data/lib/byebug/commands/finish.rb +43 -0
- data/lib/byebug/commands/frame.rb +303 -0
- data/lib/byebug/commands/help.rb +56 -0
- data/lib/byebug/commands/info.rb +462 -0
- data/lib/byebug/commands/irb.rb +123 -0
- data/lib/byebug/commands/jump.rb +66 -0
- data/lib/byebug/commands/kill.rb +51 -0
- data/lib/byebug/commands/list.rb +94 -0
- data/lib/byebug/commands/method.rb +84 -0
- data/lib/byebug/commands/quit.rb +39 -0
- data/lib/byebug/commands/reload.rb +40 -0
- data/lib/byebug/commands/save.rb +90 -0
- data/lib/byebug/commands/set.rb +210 -0
- data/lib/byebug/commands/show.rb +246 -0
- data/lib/byebug/commands/skip.rb +35 -0
- data/lib/byebug/commands/source.rb +36 -0
- data/lib/byebug/commands/stepping.rb +83 -0
- data/lib/byebug/commands/threads.rb +189 -0
- data/lib/byebug/commands/tmate.rb +36 -0
- data/lib/byebug/commands/trace.rb +56 -0
- data/lib/byebug/commands/variables.rb +199 -0
- data/lib/byebug/context.rb +58 -0
- data/lib/byebug/helper.rb +69 -0
- data/lib/byebug/interface.rb +223 -0
- data/lib/byebug/processor.rb +468 -0
- data/lib/byebug/version.rb +3 -0
- data/man/rdebug.1 +241 -0
- data/test/breakpoints_test.rb +357 -0
- data/test/conditions_test.rb +77 -0
- data/test/continue_test.rb +44 -0
- data/test/display_test.rb +141 -0
- data/test/edit_test.rb +56 -0
- data/test/eval_test.rb +92 -0
- data/test/examples/breakpoint1.rb +15 -0
- data/test/examples/breakpoint2.rb +7 -0
- data/test/examples/conditions.rb +4 -0
- data/test/examples/continue.rb +4 -0
- data/test/examples/display.rb +5 -0
- data/test/examples/edit.rb +3 -0
- data/test/examples/edit2.rb +3 -0
- data/test/examples/eval.rb +4 -0
- data/test/examples/finish.rb +20 -0
- data/test/examples/frame.rb +20 -0
- data/test/examples/frame_threads.rb +31 -0
- data/test/examples/help.rb +2 -0
- data/test/examples/info.rb +38 -0
- data/test/examples/info2.rb +3 -0
- data/test/examples/info_threads.rb +48 -0
- data/test/examples/irb.rb +6 -0
- data/test/examples/jump.rb +14 -0
- data/test/examples/kill.rb +2 -0
- data/test/examples/list.rb +12 -0
- data/test/examples/method.rb +15 -0
- data/test/examples/post_mortem.rb +19 -0
- data/test/examples/quit.rb +2 -0
- data/test/examples/reload.rb +6 -0
- data/test/examples/restart.rb +6 -0
- data/test/examples/save.rb +3 -0
- data/test/examples/set.rb +3 -0
- data/test/examples/set_annotate.rb +12 -0
- data/test/examples/settings.rb +1 -0
- data/test/examples/show.rb +2 -0
- data/test/examples/source.rb +3 -0
- data/test/examples/stepping.rb +21 -0
- data/test/examples/thread.rb +32 -0
- data/test/examples/tmate.rb +10 -0
- data/test/examples/trace.rb +7 -0
- data/test/examples/trace_threads.rb +20 -0
- data/test/examples/variables.rb +26 -0
- data/test/finish_test.rb +48 -0
- data/test/frame_test.rb +143 -0
- data/test/help_test.rb +50 -0
- data/test/info_test.rb +313 -0
- data/test/irb_test.rb +81 -0
- data/test/jump_test.rb +70 -0
- data/test/kill_test.rb +48 -0
- data/test/list_test.rb +145 -0
- data/test/method_test.rb +70 -0
- data/test/post_mortem_test.rb +27 -0
- data/test/quit_test.rb +56 -0
- data/test/reload_test.rb +44 -0
- data/test/restart_test.rb +164 -0
- data/test/save_test.rb +92 -0
- data/test/set_test.rb +177 -0
- data/test/show_test.rb +293 -0
- data/test/source_test.rb +45 -0
- data/test/stepping_test.rb +130 -0
- data/test/support/breakpoint.rb +13 -0
- data/test/support/context.rb +14 -0
- data/test/support/matchers.rb +67 -0
- data/test/support/mocha_extensions.rb +72 -0
- data/test/support/processor.rb +7 -0
- data/test/support/test_dsl.rb +206 -0
- data/test/support/test_interface.rb +68 -0
- data/test/test_helper.rb +10 -0
- data/test/tmate_test.rb +44 -0
- data/test/trace_test.rb +159 -0
- data/test/variables_test.rb +119 -0
- metadata +265 -0
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'mkmf'
|
2
|
+
|
3
|
+
if RUBY_VERSION < "2.0"
|
4
|
+
STDERR.print("Ruby version is too old\n")
|
5
|
+
exit(1)
|
6
|
+
end
|
7
|
+
|
8
|
+
$CFLAGS = '-Wall -Werror'
|
9
|
+
$CFLAGS += ' -g3' if ENV['debug']
|
10
|
+
|
11
|
+
dir_config("ruby")
|
12
|
+
create_makefile("byebug")
|
13
|
+
|
14
|
+
#if !Byebug::RubyCoreSource.create_makefile_with_core(hdrs, "ruby_debug")
|
15
|
+
# STDERR.print("Makefile creation failed\n")
|
16
|
+
# STDERR.print("*************************************************************\n\n")
|
17
|
+
# STDERR.print(" NOTE: If your headers were not found, try passing\n")
|
18
|
+
# STDERR.print(" --with-ruby-include=PATH_TO_HEADERS \n\n")
|
19
|
+
# STDERR.print("*************************************************************\n\n")
|
20
|
+
# exit(1)
|
21
|
+
#end
|
data/ext/byebug/locker.c
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
#include <byebug.h>
|
2
|
+
|
3
|
+
static locked_thread_t *locked_head = NULL;
|
4
|
+
static locked_thread_t *locked_tail = NULL;
|
5
|
+
|
6
|
+
extern int
|
7
|
+
is_in_locked(VALUE thread)
|
8
|
+
{
|
9
|
+
locked_thread_t *node;
|
10
|
+
|
11
|
+
if(!locked_head) return 0;
|
12
|
+
|
13
|
+
for(node = locked_head; node != locked_tail; node = node->next)
|
14
|
+
{
|
15
|
+
if(node->thread == thread) return 1;
|
16
|
+
}
|
17
|
+
return 0;
|
18
|
+
}
|
19
|
+
|
20
|
+
extern void
|
21
|
+
add_to_locked(VALUE thread)
|
22
|
+
{
|
23
|
+
locked_thread_t *node;
|
24
|
+
|
25
|
+
if(is_in_locked(thread)) return;
|
26
|
+
|
27
|
+
node = ALLOC(locked_thread_t);
|
28
|
+
node->thread = thread;
|
29
|
+
node->next = NULL;
|
30
|
+
if(locked_tail)
|
31
|
+
locked_tail->next = node;
|
32
|
+
locked_tail = node;
|
33
|
+
if(!locked_head)
|
34
|
+
locked_head = node;
|
35
|
+
}
|
36
|
+
|
37
|
+
extern VALUE
|
38
|
+
remove_from_locked()
|
39
|
+
{
|
40
|
+
VALUE thread;
|
41
|
+
locked_thread_t *node;
|
42
|
+
|
43
|
+
if(locked_head == NULL)
|
44
|
+
return Qnil;
|
45
|
+
|
46
|
+
node = locked_head;
|
47
|
+
locked_head = locked_head->next;
|
48
|
+
if(locked_tail == node)
|
49
|
+
locked_tail = NULL;
|
50
|
+
thread = node->thread;
|
51
|
+
xfree(node);
|
52
|
+
return thread;
|
53
|
+
}
|
data/lib/byebug.rb
ADDED
@@ -0,0 +1,404 @@
|
|
1
|
+
require_relative 'byebug.so'
|
2
|
+
require_relative 'byebug/version'
|
3
|
+
require_relative 'byebug/context'
|
4
|
+
require_relative 'byebug/processor'
|
5
|
+
require 'pp'
|
6
|
+
require 'stringio'
|
7
|
+
require 'socket'
|
8
|
+
require 'thread'
|
9
|
+
require 'linecache19'
|
10
|
+
|
11
|
+
module Byebug
|
12
|
+
|
13
|
+
@reload_source_on_change = false
|
14
|
+
@tracing_started = false
|
15
|
+
|
16
|
+
self.handler = CommandProcessor.new
|
17
|
+
|
18
|
+
# Default options to Byebug.start
|
19
|
+
DEFAULT_START_SETTINGS = {
|
20
|
+
:init => true, # Set $0 and save ARGV?
|
21
|
+
:post_mortem => false, # post-mortem debugging on uncaught exception?
|
22
|
+
:tracing => nil # Byebug.tracing value. true/false resets,
|
23
|
+
} unless defined?(DEFAULT_START_SETTINGS)
|
24
|
+
|
25
|
+
# the port number used for remote debugging
|
26
|
+
PORT = 8989 unless defined?(PORT)
|
27
|
+
|
28
|
+
# What file is used for byebug startup commands.
|
29
|
+
unless defined?(INITFILE)
|
30
|
+
INITFILE = '.rdebugrc'
|
31
|
+
HOME_DIR = ENV['HOME'].to_s
|
32
|
+
end
|
33
|
+
|
34
|
+
class << self
|
35
|
+
|
36
|
+
# if true, checks the modification time of source files and reloads if it was modified
|
37
|
+
attr_accessor :reload_source_on_change
|
38
|
+
|
39
|
+
attr_accessor :last_exception
|
40
|
+
Byebug.last_exception = nil
|
41
|
+
|
42
|
+
# gdb-style annotation mode. Used in GNU Emacs interface
|
43
|
+
attr_accessor :annotate
|
44
|
+
|
45
|
+
# in remote mode, wait for the remote connection
|
46
|
+
attr_accessor :wait_connection
|
47
|
+
|
48
|
+
# If set, a string to look for in caller() and is used to see
|
49
|
+
# if the call stack is truncated.
|
50
|
+
attr_accessor :start_sentinal
|
51
|
+
|
52
|
+
attr_reader :thread, :control_thread, :cmd_port, :ctrl_port
|
53
|
+
|
54
|
+
#
|
55
|
+
# Interrupts the current thread
|
56
|
+
#
|
57
|
+
def interrupt
|
58
|
+
current_context.interrupt
|
59
|
+
end
|
60
|
+
|
61
|
+
#
|
62
|
+
# Interrupts the last debugged thread
|
63
|
+
#
|
64
|
+
def interrupt_last
|
65
|
+
if context = last_context
|
66
|
+
return nil unless context.thread.alive?
|
67
|
+
context.interrupt
|
68
|
+
end
|
69
|
+
context
|
70
|
+
end
|
71
|
+
|
72
|
+
def source_reload
|
73
|
+
Object.send(:remove_const, "SCRIPT_LINES__") if Object.const_defined?("SCRIPT_LINES__")
|
74
|
+
Object.const_set("SCRIPT_LINES__", {})
|
75
|
+
LineCache::clear_file_cache
|
76
|
+
end
|
77
|
+
|
78
|
+
# Get line +line_number+ from file named +filename+. Return "\n" if
|
79
|
+
# there was a problem. Leaking blanks are stripped off.
|
80
|
+
def line_at(filename, line_number) # :nodoc:
|
81
|
+
@reload_on_change=nil unless defined?(@reload_on_change)
|
82
|
+
line = LineCache::getline(filename, line_number, @reload_on_change)
|
83
|
+
return "\n" unless line
|
84
|
+
return "#{line.gsub(/^\s+/, '').chomp}\n"
|
85
|
+
end
|
86
|
+
|
87
|
+
alias stop remove_tracepoints
|
88
|
+
|
89
|
+
# @param [String] file
|
90
|
+
# @param [Fixnum] line
|
91
|
+
# @param [String] expr
|
92
|
+
def add_breakpoint(file, line, expr=nil)
|
93
|
+
breakpoint = Breakpoint.new(file, line, expr)
|
94
|
+
breakpoints << breakpoint
|
95
|
+
breakpoint
|
96
|
+
end
|
97
|
+
|
98
|
+
def remove_breakpoint(id)
|
99
|
+
Breakpoint.remove breakpoints, id
|
100
|
+
end
|
101
|
+
|
102
|
+
def interface=(value) # :nodoc:
|
103
|
+
handler.interface = value
|
104
|
+
end
|
105
|
+
|
106
|
+
#
|
107
|
+
# Byebug.start(options) -> bool
|
108
|
+
# Byebug.start(options) { ... } -> obj
|
109
|
+
#
|
110
|
+
# If it's called without a block it returns +true+, unless byebug was
|
111
|
+
# already started.
|
112
|
+
#
|
113
|
+
# If a block is given, it starts byebug and yields to block. When the
|
114
|
+
# block is finished executing it stops the byebug with Byebug.stop
|
115
|
+
# method. Inside the block you will probably want to have a call to
|
116
|
+
# Byebug.byebug. For example:
|
117
|
+
#
|
118
|
+
# Byebug.start{byebug; foo} # Stop inside of foo
|
119
|
+
#
|
120
|
+
# Also, byebug only allows one invocation of byebug at a time; nested
|
121
|
+
# Byebug.start's have no effect and you can't use this inside the byebug
|
122
|
+
# itself.
|
123
|
+
#
|
124
|
+
# <i>Note that if you want to stop byebug, you must call Byebug.stop as
|
125
|
+
# many times as you called Byebug.start method.</i>
|
126
|
+
#
|
127
|
+
# +options+ is a hash used to set various debugging options.
|
128
|
+
# :init - true if you want to save ARGV and some other variables to
|
129
|
+
# make a byebug restart possible. Only the first time :init
|
130
|
+
# is set to true the values will get set. Since ARGV is
|
131
|
+
# saved, you should make sure it hasn't been changed before
|
132
|
+
# the (first) call.
|
133
|
+
# :post_mortem - true if you want to enter post-mortem debugging on an
|
134
|
+
# uncaught exception. Once post-mortem debugging is set, it
|
135
|
+
# can't be unset.
|
136
|
+
#
|
137
|
+
def start(options={}, &block)
|
138
|
+
options = Byebug::DEFAULT_START_SETTINGS.merge(options)
|
139
|
+
if options[:init]
|
140
|
+
Byebug.const_set('ARGV', ARGV.clone) unless defined? Byebug::ARGV
|
141
|
+
Byebug.const_set('PROG_SCRIPT', $0) unless defined? Byebug::PROG_SCRIPT
|
142
|
+
Byebug.const_set('INITIAL_DIR', Dir.pwd) unless defined? Byebug::INITIAL_DIR
|
143
|
+
end
|
144
|
+
#Byebug.tracing = options[:tracing] unless options[:tracing].nil?
|
145
|
+
if Byebug.started?
|
146
|
+
retval = block && block.call(self)
|
147
|
+
else
|
148
|
+
retval = Byebug._start(&block)
|
149
|
+
end
|
150
|
+
if options[:post_mortem]
|
151
|
+
post_mortem
|
152
|
+
end
|
153
|
+
return retval
|
154
|
+
end
|
155
|
+
|
156
|
+
#
|
157
|
+
# Starts a remote byebug.
|
158
|
+
#
|
159
|
+
def start_remote(host = nil, port = PORT)
|
160
|
+
return if @thread
|
161
|
+
|
162
|
+
self.interface = nil
|
163
|
+
start
|
164
|
+
|
165
|
+
if port.kind_of?(Array)
|
166
|
+
cmd_port, ctrl_port = port
|
167
|
+
else
|
168
|
+
cmd_port, ctrl_port = port, port + 1
|
169
|
+
end
|
170
|
+
|
171
|
+
ctrl_port = start_control(host, ctrl_port)
|
172
|
+
|
173
|
+
yield if block_given?
|
174
|
+
|
175
|
+
mutex = Mutex.new
|
176
|
+
proceed = ConditionVariable.new
|
177
|
+
|
178
|
+
server = TCPServer.new(host, cmd_port)
|
179
|
+
@cmd_port = cmd_port = server.addr[1]
|
180
|
+
@thread = DebugThread.new do
|
181
|
+
while (session = server.accept)
|
182
|
+
self.interface = RemoteInterface.new(session)
|
183
|
+
if wait_connection
|
184
|
+
mutex.synchronize do
|
185
|
+
proceed.signal
|
186
|
+
end
|
187
|
+
end
|
188
|
+
end
|
189
|
+
end
|
190
|
+
if wait_connection
|
191
|
+
mutex.synchronize do
|
192
|
+
proceed.wait(mutex)
|
193
|
+
end
|
194
|
+
end
|
195
|
+
end
|
196
|
+
alias start_server start_remote
|
197
|
+
|
198
|
+
def start_control(host = nil, ctrl_port = PORT + 1) # :nodoc:
|
199
|
+
return @ctrl_port if defined?(@control_thread) && @control_thread
|
200
|
+
server = TCPServer.new(host, ctrl_port)
|
201
|
+
@ctrl_port = server.addr[1]
|
202
|
+
@control_thread = DebugThread.new do
|
203
|
+
while (session = server.accept)
|
204
|
+
interface = RemoteInterface.new(session)
|
205
|
+
processor = ControlCommandProcessor.new(interface)
|
206
|
+
processor.process_commands
|
207
|
+
end
|
208
|
+
end
|
209
|
+
@ctrl_port
|
210
|
+
end
|
211
|
+
|
212
|
+
#
|
213
|
+
# Connects to the remote byebug
|
214
|
+
#
|
215
|
+
def start_client(host = 'localhost', port = PORT)
|
216
|
+
require "socket"
|
217
|
+
interface = Byebug::LocalInterface.new
|
218
|
+
socket = TCPSocket.new(host, port)
|
219
|
+
puts "Connected."
|
220
|
+
|
221
|
+
catch(:exit) do
|
222
|
+
while (line = socket.gets)
|
223
|
+
case line
|
224
|
+
when /^PROMPT (.*)$/
|
225
|
+
input = interface.read_command($1)
|
226
|
+
throw :exit unless input
|
227
|
+
socket.puts input
|
228
|
+
when /^CONFIRM (.*)$/
|
229
|
+
input = interface.confirm($1)
|
230
|
+
throw :exit unless input
|
231
|
+
socket.puts input
|
232
|
+
else
|
233
|
+
print line
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
socket.close
|
238
|
+
end
|
239
|
+
|
240
|
+
#
|
241
|
+
# Runs normal byebug initialization scripts.
|
242
|
+
#
|
243
|
+
# Reads and executes the commands from init file (if any) in the current
|
244
|
+
# working directory. This is only done if the current directory is
|
245
|
+
# different from your home directory. Thus, you can have more than one init
|
246
|
+
# file, one generic in your home directory, and another, specific to the
|
247
|
+
# program you are debugging, in the directory where you invoke byebug.
|
248
|
+
#
|
249
|
+
def run_init_script(out = handler.interface)
|
250
|
+
cwd_script_file = File.expand_path(File.join(".", INITFILE))
|
251
|
+
run_script(cwd_script_file, out) if File.exists?(cwd_script_file)
|
252
|
+
|
253
|
+
home_script_file = File.expand_path(File.join(HOME_DIR, INITFILE))
|
254
|
+
run_script(home_script_file, out) if File.exists?(home_script_file) and
|
255
|
+
cwd_script_file != home_script_file
|
256
|
+
end
|
257
|
+
|
258
|
+
#
|
259
|
+
# Runs a script file
|
260
|
+
#
|
261
|
+
def run_script(file, out = handler.interface, verbose=false)
|
262
|
+
interface = ScriptInterface.new(File.expand_path(file), out)
|
263
|
+
processor = ControlCommandProcessor.new(interface)
|
264
|
+
processor.process_commands(verbose)
|
265
|
+
end
|
266
|
+
|
267
|
+
# XXX: Implement
|
268
|
+
|
269
|
+
# # Activates the post-mortem mode. There are two ways of using it:
|
270
|
+
# #
|
271
|
+
# # == Global post-mortem mode
|
272
|
+
# # By calling Byebug.post_mortem method without a block, you install
|
273
|
+
# # at_exit hook that intercepts any unhandled by your script exceptions
|
274
|
+
# # and enables post-mortem mode.
|
275
|
+
# #
|
276
|
+
# # == Local post-mortem mode
|
277
|
+
# #
|
278
|
+
# # If you know that a particular block of code raises an exception you can
|
279
|
+
# # enable post-mortem mode by wrapping this block with Byebug.post_mortem, e.g.
|
280
|
+
# #
|
281
|
+
# # def offender
|
282
|
+
# # raise 'error'
|
283
|
+
# # end
|
284
|
+
# # Byebug.post_mortem do
|
285
|
+
# # ...
|
286
|
+
# # offender
|
287
|
+
# # ...
|
288
|
+
# # end
|
289
|
+
# def post_mortem
|
290
|
+
# if block_given?
|
291
|
+
# old_post_mortem = self.post_mortem?
|
292
|
+
# begin
|
293
|
+
# self.post_mortem = true
|
294
|
+
# yield
|
295
|
+
# rescue Exception => exp
|
296
|
+
# handle_post_mortem(exp)
|
297
|
+
# raise
|
298
|
+
# ensure
|
299
|
+
# self.post_mortem = old_post_mortem
|
300
|
+
# end
|
301
|
+
# else
|
302
|
+
# return if post_mortem?
|
303
|
+
# self.post_mortem = true
|
304
|
+
# debug_at_exit do
|
305
|
+
# handle_post_mortem($!) if $! && post_mortem?
|
306
|
+
# end
|
307
|
+
# end
|
308
|
+
# end
|
309
|
+
|
310
|
+
# def handle_post_mortem(exp)
|
311
|
+
# return if !exp || !exp.__debug_context ||
|
312
|
+
# exp.__debug_context.stack_size == 0
|
313
|
+
# Byebug.suspend
|
314
|
+
# orig_tracing = Byebug.tracing, Byebug.current_context.tracing
|
315
|
+
# Byebug.tracing = Byebug.current_context.tracing = false
|
316
|
+
# Byebug.last_exception = exp
|
317
|
+
# handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
|
318
|
+
# ensure
|
319
|
+
# Byebug.tracing, Byebug.current_context.tracing = orig_tracing
|
320
|
+
# Byebug.resume
|
321
|
+
# end
|
322
|
+
# # private :handle_post_mortem
|
323
|
+
|
324
|
+
end
|
325
|
+
|
326
|
+
class DebugThread # :nodoc:
|
327
|
+
end
|
328
|
+
|
329
|
+
class ThreadsTable # :nodoc:
|
330
|
+
end
|
331
|
+
|
332
|
+
end
|
333
|
+
|
334
|
+
class Exception # :nodoc:
|
335
|
+
attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
|
336
|
+
end
|
337
|
+
|
338
|
+
class Module
|
339
|
+
#
|
340
|
+
# Wraps the +meth+ method with Byebug.start {...} block.
|
341
|
+
#
|
342
|
+
def debug_method(meth)
|
343
|
+
old_meth = "__debugee_#{meth}"
|
344
|
+
old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
|
345
|
+
alias_method old_meth.to_sym, meth
|
346
|
+
class_eval <<-EOD
|
347
|
+
def #{meth}(*args, &block)
|
348
|
+
Byebug.start do
|
349
|
+
byebug 2
|
350
|
+
#{old_meth}(*args, &block)
|
351
|
+
end
|
352
|
+
end
|
353
|
+
EOD
|
354
|
+
end
|
355
|
+
|
356
|
+
# XXX: Implement
|
357
|
+
# #
|
358
|
+
# # Wraps the +meth+ method with Byebug.post_mortem {...} block.
|
359
|
+
# #
|
360
|
+
# def post_mortem_method(meth)
|
361
|
+
# old_meth = "__postmortem_#{meth}"
|
362
|
+
# old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
|
363
|
+
# alias_method old_meth.to_sym, meth
|
364
|
+
# class_eval <<-EOD
|
365
|
+
# def #{meth}(*args, &block)
|
366
|
+
# Byebug.start do |dbg|
|
367
|
+
# dbg.post_mortem do
|
368
|
+
# #{old_meth}(*args, &block)
|
369
|
+
# end
|
370
|
+
# end
|
371
|
+
# end
|
372
|
+
# EOD
|
373
|
+
# end
|
374
|
+
end
|
375
|
+
module Kernel
|
376
|
+
|
377
|
+
# Enters byebug in the current thread after _steps_ line events occur.
|
378
|
+
#
|
379
|
+
# Before entering byebug startup, the init script is read. Setting _steps_ to 0
|
380
|
+
# will cause a break in the byebug subroutine and not wait for a line event to
|
381
|
+
# occur. You will have to go "up 1" in order to be back to your debugged program
|
382
|
+
# from byebug program. Setting _steps_ to 0 could be useful if you want to stop
|
383
|
+
# right after the last statement in some scope, because the next step will take
|
384
|
+
# you out of some scope.
|
385
|
+
def byebug(steps = 1)
|
386
|
+
Byebug.start
|
387
|
+
Byebug.run_init_script(StringIO.new)
|
388
|
+
if 0 == steps
|
389
|
+
Byebug.current_context.stop_frame = 0
|
390
|
+
else
|
391
|
+
Byebug.current_context.stop_next = steps
|
392
|
+
end
|
393
|
+
end
|
394
|
+
alias breakpoint byebug unless respond_to?(:breakpoint)
|
395
|
+
|
396
|
+
#
|
397
|
+
# Returns a binding of n-th call frame
|
398
|
+
#
|
399
|
+
def binding_n(n = 0)
|
400
|
+
Byebug.skip do
|
401
|
+
Byebug.current_context.frame_binding(n+1)
|
402
|
+
end
|
403
|
+
end
|
404
|
+
end
|