2006-09-25
■ [misc] 帰宅しました
せっかくsvkのセットアップができたのに、結局ノートPCを触る暇がなかったという…(笑)。
そのかわり、移動時間を利用して買ったままになっていた「みんなのPython」を読みきりました。
■ [ruby] 例外表示を自分でやってみる
Rubyスクリプトの実行中に例外が発生すると、Rubyインタプリタはエラーの内容を表示して終了します。
例えば
./tobi/tobi.rb:236:in `initialize': undefined method `<<' for nil:NilClass (NoMethodError)
from ./tobi/tobi.rb:235:in `initialize'
from ./tobi/tobi.rb:419:in `initialize'
from ./main.rb:11
from tobi_debug.rb:5
こんな感じに。
以下のようにすると、この例外表示を「自前で」行うことができます。
begin
#ここに例外の発生しそうなコードを書く
rescue Exception => e
bt = e.backtrace
puts "#{bt.shift}: #{e.message} (#{e.class})"
print bt.map{|s| "\tfrom #{s}"}.join("\n")
end
全体をbegin〜rescue〜endで囲み、Exceptionの子クラス(つまり、全ての種類の例外)を変数eに捕捉しています。 eのもつメソッドについてはExceptionを 参照。
実行結果は以下のような感じになります(って、上と同じなんですけど)。
./tobi/tobi.rb:236:in `initialize': undefined method `<<' for nil:NilClass (NoMethodError)
from ./tobi/tobi.rb:235:in `initialize'
from ./tobi/tobi.rb:419:in `initialize'
from ./main.rb:11
from tobi_debug.rb:2
これが何の役に立つのかというと…あんまり使う機会は無さそうな気もしますが(笑)、例えば CGIのテスト中、例外が出るたびにapacheのログを読むのは面倒なので、上のコードを使って エラー画面をブラウザに表示するようにする…というのはありそうな場面です。 またExerbで固めたexeを作るときにこのコードを仕込んでおけば、「例外が出てるんだけど、 DOS窓が一瞬で閉じるんで読めなかった」という罠を回避することができます。 *1。
他には、日本語表示にしてみるとか、
begin
#ここに例外の発生しそうなコードを書く
rescue Exception => e
bt = e.backtrace
puts "「#{e.message}」っていう #{e.class} だよ!"
puts "場所は #{bt.shift} で、"
puts bt.map{|s| "その前は #{s} "}.join("で、\n") + "だよ!"
end
「undefined method `<<' for nil:NilClass」っていう NoMethodError だよ! 場所は ./tobi/tobi.rb:236:in `initialize' で、 その前は ./tobi/tobi.rb:235:in `initialize' で、 その前は ./tobi/tobi.rb:419:in `initialize' で、 その前は ./main.rb:11 で、 その前は tobi_debug.rb:2 だよ!
Python風に表示してみるとか。*2
begin
#ここに例外の発生しそうなコードを書く
rescue Exception => e
puts "Traceback (most recent call last):"
e.backtrace.reverse.each do |s|
if /(.+):(\d+)(:in `(.+)')?/ =~ s
puts %< File "#{$1}", line #{$2}, in #{$4 or "?"}>
puts " " + File.read($1).to_a.at($2.to_i-1).lstrip
else
puts s
end
end
puts "#{e.class}: #{e.message}"
end
Traceback (most recent call last):
File "tobi_debug.rb", line 2, in ?
require 'main.rb'
File "./main.rb", line 11, in ?
Tobi.new(false).run
File "./tobi/tobi.rb", line 419, in initialize
@map = Map.new(@unit,30,12)
File "./tobi/tobi.rb", line 235, in initialize
umax.times{|u|
File "./tobi/tobi.rb", line 236, in initialize
@data << []
NoMethodError: undefined method `<<' for nil:NilClass
「ファイルのn行目を取ってくる」が「File.read(fname).to_a.at(n-1)」で 書けてしまうあたりがLLらしくて良いですね。:-)
さあ、みんなも自分だけのスタックトレースをつくってみよう!(少年誌風)
[ツッコミを入れる]