トップ «前の日記(2006-09-21) 最新 次の日記(2006-09-27)» 編集

Route 477



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らしくて良いですね。:-)

さあ、みんなも自分だけのスタックトレースをつくってみよう!(少年誌風)

*1 エラー表示のあとにgets()を呼んでキー入力を待つとか、ファイルにエラー内容を書き出すとか

*2 まだまじめにPython触ってないので、微妙に違ってるかも知れません