追記 (2016/01/11)
現在の mruby の master の挙動がここで書いている対策が必要ないような動作になっているため、
この記事に書いてある様なことをする必要はなくなっているかと思います。
本文
mruby で以下の様なコードを実行すると
def g
raise "test"
end
def f
begin
g
rescue => e
raise e
end
end
begin
f
rescue => e
puts "e.backtrace"
puts "#{e.backtrace.map{|v| " " + v}.join("\n")}"
end
以下のように出力されます。
e.backtrace
exception_default.rb:18
backtrace を出力するところの rescue 節の中を指し示しています。
rubyだと以下のように出力されます。
e.backtrace
exception_default.rb:3:in `g'
exception_default.rb:8:in `f'
exception_default.rb:15:in `<main>'
以下を見ると現状の mruby の挙動のようです。
https://github.com/mruby/mruby/issues/1661
http://qiita.com/seanchas_t/items/ca293f9dd4454cd6cb6d
デバッグ時などは ruby の挙動のほうが
例外が起こった場所がわかりやすいので
mruby本体は書き換えずにrubyのような出力が
出来る方法を考えました。
以下の処理を追加すると、
mruby での backtrace が ruby と同じようなものになります。
class Exception
alias_method :old_initialize, :initialize
alias_method :old_backtrace, :backtrace
@@initializing = false
@@current_backtrace = nil
def initialize(*args)
old_initialize(*args)
unless @@initializing
# not thread safe
@@initializing = true
begin
raise ""
rescue => e
@stored_backtrace = e.backtrace[2..-1]
end
@@initializing = false
else
end
end
def backtrace
if @stored_backtrace
@stored_backtrace
else
self.old_backtrace
end
end
end
先ほどのコードの先頭にこのコードを挿入すると、mrubyでの出力は以下のようになります。
e.backtrace
exception_better_backtrace.rb:37:in Object.g
exception_better_backtrace.rb:42:in Object.f
exception_better_backtrace.rb:49
コード及び確認用コードは以下においてあります。
追記 (2015/11/29)
mrbgems を作りました。
https://github.com/dycoon/mruby-ruby-like-backtrace