ruby-debug 0.7.5 → 0.8

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/lib/ruby-debug.rb DELETED
@@ -1,330 +0,0 @@
1
- require 'pp'
2
- require 'stringio'
3
- require "socket"
4
- require 'thread'
5
- require 'ruby_debug.so'
6
- require 'ruby-debug/processor'
7
-
8
- SCRIPT_LINES__ = {} unless defined? SCRIPT_LINES__
9
- SCRIPT_TIMESTAMPS__ = {} unless defined? SCRIPT_TIMESTAMPS__
10
-
11
- module Debugger
12
- PORT = 8989
13
-
14
- @processor = CommandProcessor.new
15
- @reload_source_on_change = false
16
-
17
- class Context
18
- def interrupt
19
- self.stop_next = 1
20
- end
21
-
22
- private
23
-
24
- def processor
25
- Debugger.processor
26
- end
27
-
28
- def at_breakpoint(breakpoint)
29
- processor.at_breakpoint(self, breakpoint)
30
- end
31
-
32
- def at_catchpoint(excpt)
33
- processor.at_catchpoint(self, excpt)
34
- end
35
-
36
- def at_tracing(file, line)
37
- processor.at_tracing(self, file, line)
38
- end
39
-
40
- def at_line(file, line)
41
- processor.at_line(self, file, line)
42
- end
43
- end
44
-
45
- class << self
46
- attr_accessor :processor
47
-
48
- # stop main thread when remote connection established
49
- attr_accessor :stop_on_connect
50
-
51
- # in remote mode, wait for the remote connection
52
- attr_accessor :wait_connection
53
-
54
- # if <tt>true</tt>, checks the modification time of source files and reloads if it was modified
55
- attr_accessor :reload_source_on_change
56
-
57
- attr_reader :thread, :control_thread
58
-
59
- #
60
- # Interrupts the current thread
61
- #
62
- def interrupt
63
- current_context.interrupt
64
- end
65
-
66
- #
67
- # Interrupts the last debugged thread
68
- #
69
- def interrupt_last
70
- if context = last_context
71
- return nil unless context.thread.alive?
72
- context.interrupt
73
- end
74
- context
75
- end
76
-
77
- def interface=(value) # :nodoc:
78
- processor.interface = value
79
- end
80
-
81
- #
82
- # Starts a remote debugger.
83
- #
84
- def start_remote(host = nil, port = PORT, post_mortem = false)
85
- return if @thread
86
- return if started?
87
-
88
- self.interface = nil
89
- start
90
- self.post_mortem if post_mortem
91
-
92
- if port.kind_of?(Array)
93
- cmd_port, ctrl_port = port
94
- else
95
- cmd_port, ctrl_port = port, port + 1
96
- end
97
-
98
- start_control(host, ctrl_port)
99
-
100
- mutex = Mutex.new
101
- proceed = ConditionVariable.new
102
-
103
- @thread = DebugThread.new do
104
- server = TCPServer.new(host, cmd_port)
105
- while (session = server.accept)
106
- self.interface = RemoteInterface.new(session)
107
- if wait_connection
108
- mutex.synchronize do
109
- proceed.signal
110
- end
111
- else
112
- stop_main_thread
113
- end
114
- end
115
- end
116
- if wait_connection
117
- mutex.synchronize do
118
- proceed.wait(mutex)
119
- end
120
- stop_main_thread
121
- end
122
- end
123
- alias start_server start_remote
124
-
125
- def start_control(host = nil, ctrl_port = PORT + 1)
126
- raise "Debugger is not started" unless started?
127
- return if @control_thread
128
- @control_thread = DebugThread.new do
129
- server = TCPServer.new(host, ctrl_port)
130
- while (session = server.accept)
131
- interface = RemoteInterface.new(session)
132
- processor = ControlCommandProcessor.new(interface)
133
- processor.process_commands
134
- end
135
- end
136
- end
137
-
138
- #
139
- # Connects to the remote debugger
140
- #
141
- def start_client(host = 'localhost', port = PORT)
142
- require "socket"
143
- interface = Debugger::LocalInterface.new
144
- socket = TCPSocket.new(host, port)
145
- puts "Connected."
146
-
147
- catch(:exit) do
148
- while (line = socket.gets)
149
- case line
150
- when /^PROMPT (.*)$/
151
- input = interface.read_command($1)
152
- throw :exit unless input
153
- socket.puts input
154
- when /^CONFIRM (.*)$/
155
- input = interface.confirm($1)
156
- throw :exit unless input
157
- socket.puts input
158
- else
159
- print line
160
- end
161
- end
162
- end
163
- socket.close
164
- end
165
-
166
- def stop_main_thread # :nodoc:
167
- return unless stop_on_connect
168
-
169
- context = thread_context(Thread.main)
170
- context.stop_next = 2
171
- end
172
- private :stop_main_thread
173
-
174
- def source_for(file) # :nodoc:
175
- finder = lambda do
176
- if File.exists?(file)
177
- if SCRIPT_LINES__[file].nil? || SCRIPT_LINES__[file] == true
178
- SCRIPT_LINES__[file] = File.readlines(file)
179
- end
180
-
181
- change_time = test(?M, file)
182
- SCRIPT_TIMESTAMPS__[file] ||= change_time
183
- if @reload_source_on_change && SCRIPT_TIMESTAMPS__[file] < change_time
184
- SCRIPT_LINES__[file] = File.readlines(file)
185
- end
186
-
187
- SCRIPT_LINES__[file]
188
- end
189
- end
190
-
191
- Dir.chdir(File.dirname($0)){finder.call} || finder.call ||
192
- (SCRIPT_LINES__[file] == true ? nil : SCRIPT_LINES__[file])
193
- end
194
-
195
- def source_reload
196
- SCRIPT_LINES__.keys.each do |file|
197
- next unless File.exists?(file)
198
- SCRIPT_LINES__[file] = nil
199
- end
200
- end
201
-
202
- def line_at(file, line) # :nodoc:
203
- lines = source_for(file)
204
- if lines
205
- line = lines[line-1]
206
- return "\n" unless line
207
- return "#{line.gsub(/^\s+/, '').chomp}\n"
208
- end
209
- return "\n"
210
- end
211
-
212
- #
213
- # Runs a script file
214
- #
215
- def run_script(file, out = processor.interface)
216
- interface = ScriptInterface.new(file, out)
217
- processor = ControlCommandProcessor.new(interface)
218
- processor.process_commands
219
- end
220
-
221
- #
222
- # Activates the post-mortem mode. There are two ways of using it:
223
- #
224
- # == Global post-mortem mode
225
- # By calling Debugger.post_mortem method without a block, you install
226
- # at_exit hook that intercepts any unhandled by your script exceptions
227
- # and enables post-mortem mode.
228
- #
229
- # == Local post-mortem mode
230
- #
231
- # If you know that a particular block of code raises an exception you can
232
- # enable post-mortem mode by wrapping this block with Debugger.post_mortem, e.g.
233
- #
234
- # def offender
235
- # raise 'error'
236
- # end
237
- # Debugger.post_mortem do
238
- # ...
239
- # offender
240
- # ...
241
- # end
242
- def post_mortem
243
- raise "Post-mortem is already activated" if self.post_mortem?
244
- self.post_mortem = true
245
- if block_given?
246
- begin
247
- yield
248
- rescue Exception => exp
249
- handle_post_mortem(exp)
250
- raise
251
- ensure
252
- self.post_mortem = false
253
- end
254
- else
255
- debug_at_exit do
256
- handle_post_mortem($!) if $! && post_mortem?
257
- end
258
- end
259
- end
260
-
261
- def handle_post_mortem(exp)
262
- return if exp.__debug_context.stack_size == 0
263
- Debugger.suspend
264
- orig_tracing = Debugger.tracing, Debugger.current_context.tracing
265
- Debugger.tracing = Debugger.current_context.tracing = false
266
- processor.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
267
- ensure
268
- Debugger.tracing, Debugger.current_context.tracing = orig_tracing
269
- Debugger.resume
270
- end
271
- private :handle_post_mortem
272
- end
273
- end
274
-
275
- class Exception # :nodoc:
276
- attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
277
- end
278
-
279
- module Kernel
280
- #
281
- # Stops the current thread after a number of _steps_ made.
282
- #
283
- def debugger(steps = 1)
284
- Debugger.current_context.stop_next = steps
285
- end
286
-
287
- #
288
- # Returns a binding of n-th call frame
289
- #
290
- def binding_n(n = 0)
291
- Debugger.current_context.frame_binding[n+1]
292
- end
293
- end
294
-
295
- class Module
296
- #
297
- # Wraps the +meth+ method with Debugger.start {...} block.
298
- #
299
- def debug_method(meth)
300
- old_meth = "__debugee_#{meth}"
301
- old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
302
- alias_method old_meth.to_sym, meth
303
- class_eval <<-EOD
304
- def #{meth}(*args, &block)
305
- Debugger.start do
306
- debugger 2
307
- #{old_meth}(*args, &block)
308
- end
309
- end
310
- EOD
311
- end
312
-
313
- #
314
- # Wraps the +meth+ method with Debugger.post_mortem {...} block.
315
- #
316
- def post_mortem_method(meth)
317
- old_meth = "__postmortem_#{meth}"
318
- old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
319
- alias_method old_meth.to_sym, meth
320
- class_eval <<-EOD
321
- def #{meth}(*args, &block)
322
- Debugger.start do |dbg|
323
- dbg.post_mortem do
324
- #{old_meth}(*args, &block)
325
- end
326
- end
327
- end
328
- EOD
329
- end
330
- end