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らしくて良いですね。:-)
さあ、みんなも自分だけのスタックトレースをつくってみよう!(少年誌風)