S
Simon Strandgaard
A debug keyword which enables debug-output for a specific method.
I have found its useful when there is many testcases which fails
at the same time, letting me faster identify where the problem is.
I think this would be a good idea to have distributed with Ruby?
I am thinking of submitting an RCR, should I do this?
Its syntax is
debug :method [, :method]*
What it does is to enable the global flag $debug.
If we type 'debug :test_a1', then we get the following output
server> ruby example.rb
Loaded suite TestA
Started
test_a1(TestA): before #test_a1
A#compute, begin
A#dostuff, begin
A#dostuff, end
A#compute, end
after #test_a1
..
Finished in 0.002609 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
server>
However if we doesn't type it, then we get our normal output.
server> ruby example.rb
Loaded suite TestA
Started
test_a1(TestA): .
Finished in 0.001572 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
server>
Its a bit hackish, but it works.
server> expand -t2 debug_keyword.rb
BEGIN {
$debug = false
}
# purpose:
# make it easy to enable/disable debugging
#
# if $debug == nil then output are disabled
# if $debug != nil then output are enabled
module Debuggable
def printx(*args)
if $debug
super(*args)
end
end
def puts(*args)
if $debug
super(*args)
end
end
def p(*args)
if $debug
super(*args)
end
end
def print(*args)
if $debug
super(*args)
end
end
end
# purpose:
# enable $debug flag inside a method
#
# class Test
# include Debuggable
# def test_x; p 42; end
# debug :test_x
# end
# Test.new.test_x #-> (before 'test_x') 42 (after 'test_x')
#
class Module
# enable the global debug flag for just a single method
def debug(*args)
debug_methods = private_instance_methods(true)
args.each do |symbol|
name = symbol.id2name
org = "_debug_"+name
if debug_methods.include?(org)
$stderr.puts "ERROR: already debugging method: #{name}"
next
end
begin
meth = instance_method(symbol)
rescue => e
$stderr.puts "ERROR: symbol2method failure, " + e.inspect
next
end
arguments = (meth.arity != 0) ? "(*a,&b)" : "(&b)"
alias_method org, name
module_eval %{
def #{name}#{arguments}
$stdout.puts("before ##{name}")
debug, $debug = $debug, true
result = #{org}#{arguments}
$stdout.puts("after ##{name}")
result
ensure
$debug = debug
end
private :#{org}
}
end
end
end
server>
server> expand -t2 example.rb
require 'debug_keyword'
class A
include Debuggable
def dostuff
puts "A#dostuff, begin"
puts "A#dostuff, end"
end
def compute
puts "A#compute, begin"
dostuff
puts "A#compute, end"
42
end
end
require 'test/unit'
class TestA < Test::Unit::TestCase
def test_a1
assert_equal(42, A.new.compute)
end
debug :test_a1 # enable/disable debugging
end
require 'test/unit/ui/console/testrunner'
Test::Unit::UI::Console::TestRunner.run(TestA, Test::Unit::UI::VERBOSE)
server>
I have found its useful when there is many testcases which fails
at the same time, letting me faster identify where the problem is.
I think this would be a good idea to have distributed with Ruby?
I am thinking of submitting an RCR, should I do this?
Its syntax is
debug :method [, :method]*
What it does is to enable the global flag $debug.
If we type 'debug :test_a1', then we get the following output
server> ruby example.rb
Loaded suite TestA
Started
test_a1(TestA): before #test_a1
A#compute, begin
A#dostuff, begin
A#dostuff, end
A#compute, end
after #test_a1
..
Finished in 0.002609 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
server>
However if we doesn't type it, then we get our normal output.
server> ruby example.rb
Loaded suite TestA
Started
test_a1(TestA): .
Finished in 0.001572 seconds.
1 tests, 1 assertions, 0 failures, 0 errors
server>
Its a bit hackish, but it works.
server> expand -t2 debug_keyword.rb
BEGIN {
$debug = false
}
# purpose:
# make it easy to enable/disable debugging
#
# if $debug == nil then output are disabled
# if $debug != nil then output are enabled
module Debuggable
def printx(*args)
if $debug
super(*args)
end
end
def puts(*args)
if $debug
super(*args)
end
end
def p(*args)
if $debug
super(*args)
end
end
def print(*args)
if $debug
super(*args)
end
end
end
# purpose:
# enable $debug flag inside a method
#
# class Test
# include Debuggable
# def test_x; p 42; end
# debug :test_x
# end
# Test.new.test_x #-> (before 'test_x') 42 (after 'test_x')
#
class Module
# enable the global debug flag for just a single method
def debug(*args)
debug_methods = private_instance_methods(true)
args.each do |symbol|
name = symbol.id2name
org = "_debug_"+name
if debug_methods.include?(org)
$stderr.puts "ERROR: already debugging method: #{name}"
next
end
begin
meth = instance_method(symbol)
rescue => e
$stderr.puts "ERROR: symbol2method failure, " + e.inspect
next
end
arguments = (meth.arity != 0) ? "(*a,&b)" : "(&b)"
alias_method org, name
module_eval %{
def #{name}#{arguments}
$stdout.puts("before ##{name}")
debug, $debug = $debug, true
result = #{org}#{arguments}
$stdout.puts("after ##{name}")
result
ensure
$debug = debug
end
private :#{org}
}
end
end
end
server>
server> expand -t2 example.rb
require 'debug_keyword'
class A
include Debuggable
def dostuff
puts "A#dostuff, begin"
puts "A#dostuff, end"
end
def compute
puts "A#compute, begin"
dostuff
puts "A#compute, end"
42
end
end
require 'test/unit'
class TestA < Test::Unit::TestCase
def test_a1
assert_equal(42, A.new.compute)
end
debug :test_a1 # enable/disable debugging
end
require 'test/unit/ui/console/testrunner'
Test::Unit::UI::Console::TestRunner.run(TestA, Test::Unit::UI::VERBOSE)
server>