当我得到异常时,它通常来自调用堆栈中的深层.当发生这种情况时,通常会对我隐藏实际有问题的代码行:
tmp.rb:7:in `t': undefined method `bar' for nil:NilClass (NoMethodError)
from tmp.rb:10:in `s'
from tmp.rb:13:in `r'
from tmp.rb:16:in `q'
from tmp.rb:19:in `p'
from tmp.rb:22:in `o'
from tmp.rb:25:in `n'
from tmp.rb:28:in `m'
from tmp.rb:31:in `l'
... 8 levels...
from tmp.rb:58:in `c'
from tmp.rb:61:in `b'
from tmp.rb:64:in `a'
from tmp.rb:67
那个"... 8级......"截断给我带来了很多麻烦.我在这方面没有太大的成功:我怎么告诉ruby我想要转储包含完整的堆栈?
异常#backtrace包含整个堆栈:
def do_division_by_zero; 5 / 0; end begin do_division_by_zero rescue => exception puts exception.backtrace raise # always reraise end
(灵感来自Peter Cooper的Ruby Inside博客)
如果你想要一个简单的单行程,你也可以这样做:
puts caller
这会产生错误描述和漂亮的干净,缩进的堆栈跟踪:
begin # Some exception throwing code rescue => e puts "Error during processing: #{$!}" puts "Backtrace:\n\t#{e.backtrace.join("\n\t")}" end
IRB设置了这个可怕的"功能",您可以自定义.
创建一个名为~/.irbrc
包含以下行的文件:
IRB.conf[:BACK_TRACE_LIMIT] = 100
这将允许您irb
至少看到100个堆栈帧.我无法找到非交互式运行时的等效设置.
有关IRB定制的详细信息可以在Pickaxe书中找到.
一个用于callstack的班轮:
begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace; end
没有所有宝石的一个用于callstack的班轮:
begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//); end
一个没有所有宝石和相对于当前目录的callstack的衬垫
begin; Whatever.you.want; rescue => e; puts e.message; puts; puts e.backtrace.grep_v(/\/gems\//).map { |l| l.gsub(`pwd`.strip + '/', '') }; end
如果这对你很重要,那就模仿官方的Ruby跟踪.
begin 0/0 # or some other nonsense rescue => e puts e.backtrace.join("\n\t") .sub("\n\t", ": #{e}#{e.class ? " (#{e.class})" : ''}\n\t") end
有趣的是,它没有正确处理'未处理的异常',将其报告为'RuntimeError',但位置是正确的.