ruby-debug-base193 0.0.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,127 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ruby-debug-base193
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 1
9
+ version: 0.0.1
10
+ platform: ruby
11
+ authors:
12
+ - Kent Sibilev
13
+ - Mark Moseley
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2009-09-08 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: columnize
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ requirements:
26
+ - - ">="
27
+ - !ruby/object:Gem::Version
28
+ segments:
29
+ - 0
30
+ - 3
31
+ - 1
32
+ version: 0.3.1
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ - !ruby/object:Gem::Dependency
36
+ name: ruby_core_source
37
+ prerelease: false
38
+ requirement: &id002 !ruby/object:Gem::Requirement
39
+ requirements:
40
+ - - ">="
41
+ - !ruby/object:Gem::Version
42
+ segments:
43
+ - 0
44
+ - 1
45
+ - 4
46
+ version: 0.1.4
47
+ type: :runtime
48
+ version_requirements: *id002
49
+ - !ruby/object:Gem::Dependency
50
+ name: linecache193
51
+ prerelease: false
52
+ requirement: &id003 !ruby/object:Gem::Requirement
53
+ requirements:
54
+ - - ">="
55
+ - !ruby/object:Gem::Version
56
+ segments:
57
+ - 0
58
+ - 0
59
+ - 1
60
+ version: 0.0.1
61
+ type: :runtime
62
+ version_requirements: *id003
63
+ description: |
64
+ ruby-debug is a fast implementation of the standard Ruby debugger debug.rb.
65
+ It is implemented by utilizing a new Ruby C API hook. The core component
66
+ provides support that front-ends can build on. It provides breakpoint
67
+ handling, bindings for stack frames among other things.
68
+
69
+ email: mark@fast-software.com
70
+ executables: []
71
+
72
+ extensions:
73
+ - ext/ruby_debug/extconf.rb
74
+ extra_rdoc_files:
75
+ - README
76
+ - ext/ruby_debug/ruby_debug.c
77
+ files:
78
+ - AUTHORS
79
+ - CHANGES
80
+ - LICENSE
81
+ - README
82
+ - Rakefile
83
+ - ext/ruby_debug/extconf.rb
84
+ - ext/ruby_debug/breakpoint.c
85
+ - ext/ruby_debug/ruby_debug.h
86
+ - ext/ruby_debug/ruby_debug.c
87
+ - lib/ruby-debug-base.rb
88
+ - lib/ChangeLog
89
+ - test/base/base.rb
90
+ - test/base/binding.rb
91
+ - test/base/catchpoint.rb
92
+ has_rdoc: true
93
+ homepage: http://rubyforge.org/projects/ruby-debug19/
94
+ licenses: []
95
+
96
+ post_install_message:
97
+ rdoc_options:
98
+ - --charset=UTF-8
99
+ require_paths:
100
+ - lib
101
+ required_ruby_version: !ruby/object:Gem::Requirement
102
+ requirements:
103
+ - - ">="
104
+ - !ruby/object:Gem::Version
105
+ segments:
106
+ - 1
107
+ - 8
108
+ - 2
109
+ version: 1.8.2
110
+ required_rubygems_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ segments:
115
+ - 0
116
+ version: "0"
117
+ requirements: []
118
+
119
+ rubyforge_project: ruby-debug19
120
+ rubygems_version: 1.3.6
121
+ signing_key:
122
+ specification_version: 3
123
+ summary: Fast Ruby debugger - core component
124
+ test_files:
125
+ - test/base/base.rb
126
+ - test/base/binding.rb
127
+ - test/base/catchpoint.rb