tddium-ruby-debug-base19 0.12.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,304 @@
1
+ require 'ruby_debug.so'
2
+ require 'rubygems'
3
+ require 'linecache19'
4
+
5
+ module Debugger
6
+
7
+ # Default options to Debugger.start
8
+ DEFAULT_START_SETTINGS = {
9
+ :init => true, # Set $0 and save ARGV?
10
+ :post_mortem => false, # post-mortem debugging on uncaught exception?
11
+ :tracing => nil # Debugger.tracing value. true/false resets,
12
+ # nil keeps the prior value
13
+ } unless defined?(DEFAULT_START_SETTINGS)
14
+
15
+ class Context
16
+ def interrupt
17
+ self.stop_next = 1
18
+ end
19
+
20
+ alias __c_frame_binding frame_binding
21
+ def frame_binding(frame)
22
+ __c_frame_binding(frame) || hbinding(frame)
23
+ end
24
+
25
+ private
26
+
27
+ def hbinding(frame)
28
+ hash = frame_locals(frame)
29
+ code = hash.keys.map{|k| "#{k} = hash['#{k}']" unless k=='self' }.compact.join(';') + ';binding'
30
+ if obj = frame_self(frame)
31
+ obj.instance_eval code
32
+ else
33
+ eval code, TOPLEVEL_BINDING
34
+ end
35
+ end
36
+
37
+ def handler
38
+ Debugger.handler or raise 'No interface loaded'
39
+ end
40
+
41
+ def at_breakpoint(breakpoint)
42
+ handler.at_breakpoint(self, breakpoint)
43
+ end
44
+
45
+ def at_catchpoint(excpt)
46
+ handler.at_catchpoint(self, excpt)
47
+ end
48
+
49
+ def at_tracing(file, line)
50
+ @tracing_started = true if File.identical?(file, File.join(Debugger::INITIAL_DIR, Debugger::PROG_SCRIPT))
51
+ handler.at_tracing(self, file, line) if @tracing_started
52
+ end
53
+
54
+ def at_line(file, line)
55
+ handler.at_line(self, file, line)
56
+ end
57
+
58
+ def at_return(file, line)
59
+ handler.at_return(self, file, line)
60
+ end
61
+ end
62
+
63
+ @reload_source_on_change = false
64
+ @tracing_started = false
65
+
66
+ class << self
67
+ # interface modules provide +handler+ object
68
+ attr_accessor :handler
69
+
70
+ # if <tt>true</tt>, checks the modification time of source files and reloads if it was modified
71
+ attr_accessor :reload_source_on_change
72
+
73
+ attr_accessor :last_exception
74
+ Debugger.last_exception = nil
75
+
76
+ #
77
+ # Interrupts the current thread
78
+ #
79
+ def interrupt
80
+ current_context.interrupt
81
+ end
82
+
83
+ #
84
+ # Interrupts the last debugged thread
85
+ #
86
+ def interrupt_last
87
+ if context = last_context
88
+ return nil unless context.thread.alive?
89
+ context.interrupt
90
+ end
91
+ context
92
+ end
93
+
94
+ def source_reload
95
+ LineCache::clear_file_cache
96
+ end
97
+
98
+ # Get line +line_number+ from file named +filename+. Return "\n"
99
+ # there was a problem. Leaking blanks are stripped off.
100
+ def line_at(filename, line_number) # :nodoc:
101
+ @reload_on_change=nil unless defined?(@reload_on_change)
102
+ line = LineCache::getline(filename, line_number, @reload_on_change)
103
+ return "\n" unless line
104
+ return "#{line.gsub(/^\s+/, '').chomp}\n"
105
+ end
106
+
107
+ #
108
+ # Activates the post-mortem mode. There are two ways of using it:
109
+ #
110
+ # == Global post-mortem mode
111
+ # By calling Debugger.post_mortem method without a block, you install
112
+ # at_exit hook that intercepts any unhandled by your script exceptions
113
+ # and enables post-mortem mode.
114
+ #
115
+ # == Local post-mortem mode
116
+ #
117
+ # If you know that a particular block of code raises an exception you can
118
+ # enable post-mortem mode by wrapping this block with Debugger.post_mortem, e.g.
119
+ #
120
+ # def offender
121
+ # raise 'error'
122
+ # end
123
+ # Debugger.post_mortem do
124
+ # ...
125
+ # offender
126
+ # ...
127
+ # end
128
+ def post_mortem
129
+ if block_given?
130
+ old_post_mortem = self.post_mortem?
131
+ begin
132
+ self.post_mortem = true
133
+ yield
134
+ rescue Exception => exp
135
+ handle_post_mortem(exp)
136
+ raise
137
+ ensure
138
+ self.post_mortem = old_post_mortem
139
+ end
140
+ else
141
+ return if post_mortem?
142
+ self.post_mortem = true
143
+ debug_at_exit do
144
+ handle_post_mortem($!) if $! && post_mortem?
145
+ end
146
+ end
147
+ end
148
+
149
+ def handle_post_mortem(exp)
150
+ return if !exp || !exp.__debug_context ||
151
+ exp.__debug_context.stack_size == 0
152
+ Debugger.suspend
153
+ orig_tracing = Debugger.tracing, Debugger.current_context.tracing
154
+ Debugger.tracing = Debugger.current_context.tracing = false
155
+ Debugger.last_exception = exp
156
+ handler.at_line(exp.__debug_context, exp.__debug_file, exp.__debug_line)
157
+ ensure
158
+ Debugger.tracing, Debugger.current_context.tracing = orig_tracing
159
+ Debugger.resume
160
+ end
161
+ # private :handle_post_mortem
162
+ end
163
+
164
+ class DebugThread # :nodoc:
165
+ end
166
+
167
+ class ThreadsTable # :nodoc:
168
+ end
169
+
170
+ # Debugger.start(options) -> bool
171
+ # Debugger.start(options) { ... } -> obj
172
+ #
173
+ # If it's called without a block it returns +true+, unless debugger
174
+ # was already started. If a block is given, it starts debugger and
175
+ # yields to block. When the block is finished executing it stops
176
+ # the debugger with Debugger.stop method.
177
+ #
178
+ # If a block is given, it starts debugger and yields to block. When
179
+ # the block is finished executing it stops the debugger with
180
+ # Debugger.stop method. Inside the block you will probably want to
181
+ # have a call to Debugger.debugger. For example:
182
+ #
183
+ # Debugger.start{debugger; foo} # Stop inside of foo
184
+ #
185
+ # Also, ruby-debug only allows
186
+ # one invocation of debugger at a time; nested Debugger.start's
187
+ # have no effect and you can't use this inside the debugger itself.
188
+ #
189
+ # <i>Note that if you want to stop debugger, you must call
190
+ # Debugger.stop as many time as you called Debugger.start
191
+ # method.</i>
192
+ #
193
+ # +options+ is a hash used to set various debugging options.
194
+ # Set :init true if you want to save ARGV and some variables which
195
+ # make a debugger restart possible. Only the first time :init is set true
196
+ # will values get set. Since ARGV is saved, you should make sure
197
+ # it hasn't been changed before the (first) call.
198
+ # Set :post_mortem true if you want to enter post-mortem debugging
199
+ # on an uncaught exception. Once post-mortem debugging is set, it can't
200
+ # be unset.
201
+ def start(options={}, &block)
202
+ options = Debugger::DEFAULT_START_SETTINGS.merge(options)
203
+ if options[:init]
204
+ Debugger.const_set('ARGV', ARGV.clone) unless
205
+ defined? Debugger::ARGV
206
+ Debugger.const_set('PROG_SCRIPT', $0) unless
207
+ defined? Debugger::PROG_SCRIPT
208
+ Debugger.const_set('INITIAL_DIR', Dir.pwd) unless
209
+ defined? Debugger::INITIAL_DIR
210
+ end
211
+ Debugger.tracing = options[:tracing] unless options[:tracing].nil?
212
+ retval = Debugger.started? ? block && block.call(self) : Debugger.start_(&block)
213
+ if options[:post_mortem]
214
+ post_mortem
215
+ end
216
+ return retval
217
+ end
218
+ module_function :start
219
+ end
220
+
221
+ module Kernel
222
+
223
+ # Enters the debugger in the current thread after _steps_ line events occur.
224
+ # Before entering the debugger startup script is read.
225
+ #
226
+ # Setting _steps_ to 0 will cause a break in the debugger subroutine
227
+ # and not wait for a line event to occur. You will have to go "up 1"
228
+ # in order to be back in your debugged program rather than the
229
+ # debugger. Settings _steps_ to 0 could be useful you want to stop
230
+ # right after the last statement in some scope, because the next
231
+ # step will take you out of some scope.
232
+
233
+ # If a block is given (and the debugger hasn't been started, we run the
234
+ # block under the debugger. Alas, when a block is given, we can't support
235
+ # running the startup script or support the steps option. FIXME.
236
+ def debugger(steps = 1, &block)
237
+ if block
238
+ Debugger.start({}, &block)
239
+ else
240
+ Debugger.start
241
+ Debugger.run_init_script(StringIO.new)
242
+ if 0 == steps
243
+ Debugger.current_context.stop_frame = 0
244
+ else
245
+ Debugger.current_context.stop_next = steps
246
+ end
247
+ end
248
+ end
249
+ alias breakpoint debugger unless respond_to?(:breakpoint)
250
+
251
+ #
252
+ # Returns a binding of n-th call frame
253
+ #
254
+ def binding_n(n = 0)
255
+ Debugger.skip do
256
+ if RUBY_VERSION < "1.9"
257
+ Debugger.current_context.frame_binding(n+2)
258
+ else
259
+ Debugger.current_context.frame_binding(n)
260
+ end
261
+ end
262
+ end
263
+ end
264
+
265
+ class Exception # :nodoc:
266
+ attr_reader :__debug_file, :__debug_line, :__debug_binding, :__debug_context
267
+ end
268
+
269
+ class Module
270
+ #
271
+ # Wraps the +meth+ method with Debugger.start {...} block.
272
+ #
273
+ def debug_method(meth)
274
+ old_meth = "__debugee_#{meth}"
275
+ old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
276
+ alias_method old_meth.to_sym, meth
277
+ class_eval <<-EOD
278
+ def #{meth}(*args, &block)
279
+ Debugger.start do
280
+ debugger 2
281
+ #{old_meth}(*args, &block)
282
+ end
283
+ end
284
+ EOD
285
+ end
286
+
287
+ #
288
+ # Wraps the +meth+ method with Debugger.post_mortem {...} block.
289
+ #
290
+ def post_mortem_method(meth)
291
+ old_meth = "__postmortem_#{meth}"
292
+ old_meth = "#{$1}_set" if old_meth =~ /^(.+)=$/
293
+ alias_method old_meth.to_sym, meth
294
+ class_eval <<-EOD
295
+ def #{meth}(*args, &block)
296
+ Debugger.start do |dbg|
297
+ dbg.post_mortem do
298
+ #{old_meth}(*args, &block)
299
+ end
300
+ end
301
+ end
302
+ EOD
303
+ end
304
+ end
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+
4
+ # Some tests of Debugger module in C extension ruby_debug
5
+ class TestRubyDebug < Test::Unit::TestCase
6
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'ext')
7
+ require 'ruby_debug'
8
+ $:.shift
9
+
10
+ # test current_context
11
+ def test_current_context
12
+ assert(Debugger.started?,
13
+ 'debugger should now be started.')
14
+ assert_equal(__LINE__, Debugger.current_context.frame_line)
15
+ assert_equal(Debugger.current_context.frame_file,
16
+ Debugger.current_context.frame_file(0))
17
+ assert_equal(File.basename(__FILE__),
18
+ File.basename(Debugger.current_context.frame_file))
19
+ assert_raises(ArgumentError) {Debugger.current_context.frame_file(1, 2)}
20
+ assert_raises(ArgumentError) {Debugger.current_context.frame_file(10)}
21
+ assert_equal(7, Debugger.current_context.stack_size)
22
+ assert_equal(TestRubyDebug, Debugger.current_context.frame_class)
23
+ assert_equal(false, Debugger.current_context.dead?, 'Not dead yet!')
24
+ end
25
+
26
+ # Test initial variables and setting/getting state.
27
+ def test_debugger_base
28
+ assert(Debugger.started?,
29
+ 'Debugger should now be started.')
30
+ assert_equal(false, Debugger.debug,
31
+ 'Debug variable should not be set.')
32
+ a = Debugger.contexts
33
+ assert_equal(1, a.size,
34
+ 'There should only be one context.')
35
+ assert_equal(Array, a.class,
36
+ 'Context should be an array.')
37
+ end
38
+
39
+ # Test breakpoint handling
40
+ def test_breakpoints
41
+ assert_equal(0, Debugger.breakpoints.size,
42
+ 'There should not be any breakpoints set.')
43
+ brk = Debugger.add_breakpoint(__FILE__, 1)
44
+ assert_equal(Debugger::Breakpoint, brk.class,
45
+ 'Breakpoint should have been set and returned.')
46
+ assert_equal(1, Debugger.breakpoints.size,
47
+ 'There should now be one breakpoint set.')
48
+ Debugger.remove_breakpoint(0)
49
+ assert_equal(1, Debugger.breakpoints.size,
50
+ 'There should still be one breakpoint set.')
51
+ Debugger.remove_breakpoint(1)
52
+ assert_equal(0, Debugger.breakpoints.size,
53
+ 'There should no longer be any breakpoints set.')
54
+ end
55
+ end
56
+
@@ -0,0 +1,31 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'test/unit'
4
+
5
+ # Test binding_n command
6
+ class TestBinding < Test::Unit::TestCase
7
+
8
+ SRC_DIR = File.expand_path(File.dirname(__FILE__)) unless
9
+ defined?(SRC_DIR)
10
+ %w(ext lib).each do |dir|
11
+ $:.unshift File.join(SRC_DIR, '..', '..', dir)
12
+ end
13
+ require File.join(SRC_DIR, '..', '..', 'lib', 'ruby-debug-base')
14
+ $:.shift; $:.shift
15
+
16
+ def test_basic
17
+ def inside_fn
18
+ s = 'some other string'
19
+ b2 = Kernel::binding_n(1)
20
+ y2 = eval('s', b2)
21
+ assert_equal('this is a test', y2)
22
+ end
23
+ s = 'this is a test'
24
+ Debugger.start
25
+ b = Kernel::binding_n(0)
26
+ y = eval('s', b)
27
+ assert_equal(y, s)
28
+ inside_fn
29
+ Debugger.stop
30
+ end
31
+ end
@@ -0,0 +1,23 @@
1
+ #!/usr/bin/env ruby
2
+ require 'test/unit'
3
+
4
+ # Test catchpoint in C ruby_debug extension.
5
+
6
+ class TestRubyDebugCatchpoint < Test::Unit::TestCase
7
+
8
+ $:.unshift File.join(File.dirname(__FILE__), '..', '..', 'ext')
9
+ require 'ruby_debug'
10
+ $:.shift
11
+
12
+ # test current_context
13
+ def test_catchpoints
14
+ assert_equal({}, Debugger.catchpoints)
15
+ Debugger.add_catchpoint('ZeroDivisionError')
16
+ assert_equal({'ZeroDivisionError' => 0}, Debugger.catchpoints)
17
+ Debugger.add_catchpoint('RuntimeError')
18
+ assert_equal(['RuntimeError', 'ZeroDivisionError'],
19
+ Debugger.catchpoints.keys.sort)
20
+ end
21
+
22
+ end
23
+
metadata ADDED
@@ -0,0 +1,108 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: tddium-ruby-debug-base19
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.12.1
5
+ prerelease:
6
+ platform: ruby
7
+ authors:
8
+ - Kent Sibilev
9
+ - Mark Moseley
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2009-09-08 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: columnize
17
+ requirement: &74522530 !ruby/object:Gem::Requirement
18
+ none: false
19
+ requirements:
20
+ - - ! '>='
21
+ - !ruby/object:Gem::Version
22
+ version: 0.3.1
23
+ type: :runtime
24
+ prerelease: false
25
+ version_requirements: *74522530
26
+ - !ruby/object:Gem::Dependency
27
+ name: ruby_core_source
28
+ requirement: &74522290 !ruby/object:Gem::Requirement
29
+ none: false
30
+ requirements:
31
+ - - ! '>='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.1.4
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: *74522290
37
+ - !ruby/object:Gem::Dependency
38
+ name: tddium-linecache19
39
+ requirement: &74522040 !ruby/object:Gem::Requirement
40
+ none: false
41
+ requirements:
42
+ - - ! '>='
43
+ - !ruby/object:Gem::Version
44
+ version: 0.5.13
45
+ type: :runtime
46
+ prerelease: false
47
+ version_requirements: *74522040
48
+ description: ! 'ruby-debug is a fast implementation of the standard Ruby debugger
49
+ debug.rb.
50
+
51
+ It is implemented by utilizing a new Ruby C API hook. The core component
52
+
53
+ provides support that front-ends can build on. It provides breakpoint
54
+
55
+ handling, bindings for stack frames among other things.
56
+
57
+ '
58
+ email: mark@fast-software.com
59
+ executables: []
60
+ extensions:
61
+ - ext/ruby_debug/extconf.rb
62
+ extra_rdoc_files:
63
+ - README
64
+ - ext/ruby_debug/ruby_debug.c
65
+ files:
66
+ - AUTHORS
67
+ - CHANGES
68
+ - LICENSE
69
+ - README
70
+ - Rakefile
71
+ - ext/ruby_debug/extconf.rb
72
+ - ext/ruby_debug/breakpoint.c
73
+ - ext/ruby_debug/ruby_debug.h
74
+ - ext/ruby_debug/ruby_debug.c
75
+ - lib/ruby-debug-base.rb
76
+ - lib/ChangeLog
77
+ - test/base/base.rb
78
+ - test/base/binding.rb
79
+ - test/base/catchpoint.rb
80
+ homepage: http://rubyforge.org/projects/ruby-debug19/
81
+ licenses: []
82
+ post_install_message:
83
+ rdoc_options:
84
+ - --charset=UTF-8
85
+ require_paths:
86
+ - lib
87
+ required_ruby_version: !ruby/object:Gem::Requirement
88
+ none: false
89
+ requirements:
90
+ - - ! '>='
91
+ - !ruby/object:Gem::Version
92
+ version: 1.8.2
93
+ required_rubygems_version: !ruby/object:Gem::Requirement
94
+ none: false
95
+ requirements:
96
+ - - ! '>='
97
+ - !ruby/object:Gem::Version
98
+ version: '0'
99
+ requirements: []
100
+ rubyforge_project: ruby-debug19
101
+ rubygems_version: 1.8.11
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: Fast Ruby debugger - core component
105
+ test_files:
106
+ - test/base/base.rb
107
+ - test/base/binding.rb
108
+ - test/base/catchpoint.rb