我希望我的代码执行以下操作:
def debug (message)
puts message.rjust(message.length + (stack_trace-1 * 2)) # -1 for the call to debug
end
def a
debug "in a"
b
debug "end a"
end
def b
debug "in b"
c
debug "end b"
end
def c
debug "in c"
meaningful_work
debug "end c"
end
输出:
in a
in b
in c
end c
end b
end a
我以前在PHP中做过这样的事情,比如:
function echon($string){
$nest_level = count(debug_backtrace()) - 1; // minus one to ignore the call to *this* function
echo str_repeat(" ", $nest_level) . $string . "\n";
}
就我的google-fu而言,没有Ruby等同于debug_backtrace
。我不想修改我正在工作的代码库中的所有众多方法的调用以传递回溯 - 这是不必要的繁琐且难以还原。
我可以使用一些全局跟踪吗?
答案 0 :(得分:3)
只需将Kernel#caller
与.length
一起使用即可。 caller(0).length
将为您提供当前的堆栈深度。
示例:
irb(main):001:0> caller(0)
=> ["(irb):1:in `irb_binding'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86:in `eval'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/workspace.rb:86:in `evaluate'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/context.rb:380:in `evaluate'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:492:in `block (2 levels) in eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:624:in `signal_status'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:489:in `block in eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:247:in `block (2 levels) in each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:233:in `loop'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:233:in `block in each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:232:in `catch'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb/ruby-lex.rb:232:in `each_top_level_statement'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:488:in `eval_input'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:397:in `block in start'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:396:in `catch'", "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/irb.rb:396:in `start'", "/usr/bin/irb:12:in `<main>'"]
irb(main):002:0> caller(0).length
=> 17
答案 1 :(得分:1)
这是实现@nneonneo优秀建议的一种方法。
<强>代码强>
INDENT = 2
def debug(msg=nil)
@prev_arr_size ||= 1
@arrived ||= false
arr = caller(1)
indent = ' '*(arr.size-2)*INDENT
if msg
puts indent + msg
return
end
meth, call_meth = method_str(arr[0]), method_str(arr[1])
entering = (@prev_arr_size==arr.size) ? !@arrived : @prev_arr_size < arr.size
msg1, msg2 = entering ? ["in ", "called from "] : ["end", "returning to"]
puts indent + "%s %s, %s %s" % [msg1, meth, msg2, call_meth]
@prev_arr_size = arr.size
@arrived = !@arrived
end
def method_str(str)
file, _, meth = str.partition(/:.*?in\s+/)
"#{meth[1..-2]} (#{file})"
end
示例强>
def a
debug
# frivolous work
b
debug
end
def b
debug
c
x = 5
debug "It seems that x is now #{x}"
# more frivolous work
c
debug
end
def c
debug
# meaningful_work
debug
end
a
#=> in a (t.rb), called from <main> (t.rb)
# in b (t.rb), called from a (t.rb)
# in c (t.rb), called from b (t.rb)
# end c (t.rb), returning to b (t.rb)
# It seems that x is now 5
# in c (t.rb), called from b (t.rb)
# end c (t.rb), returning to b (t.rb)
# end b (t.rb), returning to a (t.rb)
# end a (t.rb), returning to <main> (t.rb)