2014-12-15 3 views
3

나는 내 코드는 다음을 수행 할 :어떻게 디버깅 목적으로 스택 추적 높이를 추적 할 수 있습니까?

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는 debug_backtrace에 해당하는 루비가 없다고 말할 수 있습니다. 역 추적 (backtrace)을 통과하기 위해 노력하고있는 코드 기반의 수많은 메소드의 호출을 수정하고 싶지는 않습니다. 이것은 불필요하게 번거롭고 되돌리기 어렵습니다.

여기서 추적 할 때 사용할 수있는 글로벌 미디어가 있습니까?

답변

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) ? [email protected] : @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 = [email protected] 
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) 
+0

놀라운 대답, 내가 두 가지를 받아 들일 수 있다면. 제가 제안 할 수 있을까요? ''temp_user_id : # {user_id} ''와 같은 것을 전달할 수 있도록 기본 디버그 문자열을 덮어 쓰는 문자열 인 디버그에 선택적 매개 변수를 추가하고 멋진 형식을 유지하십시오. –

+1

Deven, 내가 제안한 변경을했습니다. 좋은 사람 이었어. 답장이 지연되어 죄송합니다. –

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 
+0

이것은 뛰어난 작품! 깊이가 너무 컸기 때문에 길이에서 약 45를 뺀 것이므로 코드가 매우 읽기 쉽습니다. 감사. –

+0

귀하의 솔루션이 확실히 받아 들여질만한 가치가 있었지만, CarySwoveland의 대답은 앞으로 나아가고 미래의 독자들에게 풍부한 자원을 제공하므로 나는 그를 받아들이기로 바꾸고 있습니다. 죄송합니다! –