znzの日記

 | 

2006-10-11

ENDat_exitの違い

http://www.atdot.net/~ko1/diary/200610.html#d10 を見てENDat_exitの違いが気になったので調べてみる。

3.times {|n|
  at_exit {
    puts "at_exit #{n}"
    3.times {|m|
      at_exit {
        puts "at_exit #{n} at_exit #{m}"
      }
    }
  }
  END {
    puts "END #{n}"
    3.times {|m|
      END {
        puts "END #{n} END #{m}"
      }
    }
  }
}

実行結果:

ruby 1.8.2 (2005-04-11) [i386-linux]
at_exit 2
at_exit 1
END 0
at_exit 0
at_exit 0 at_exit 2
at_exit 0 at_exit 1
at_exit 0 at_exit 0
END 0 END 0
at_exit 1 at_exit 2
at_exit 1 at_exit 1
at_exit 1 at_exit 0
at_exit 2 at_exit 2
at_exit 2 at_exit 1
at_exit 2 at_exit 0

他にはENDはメソッドの中では使えないとか。

rubyソースを読んだ編

  • まず grep END *.* してみたらヒットしすぎ。
  • grep END lex.c parse.yというあたりで探してみるとklENDらしいとわかる。
  • parse.yのklENDのところをページャーで見てNEW_POSTEXEがポイントっぽい気がしたので、
  • grep NEW_POSTEXE *.*で「node.h:#define NEW_POSTEXE() NEW_NODE(NODE_POSTEXE,0,0,0)」
  • grep NODE_POSTEXE *.*eval.cを見れば良さそうと気づく。
  • eval.cのcase NODE_POSTEXEでrb_f_END()が実際の処理っぽい。
  • grep rb_f_END *.*してみたら、eval.cの中にrb_f_ENDがあった。
  • 肝はrb_set_end_procっぽい。すぐ下にrb_f_at_exit()があって、その中でもrb_set_end_procを呼んでいる。
  • rb_set_end_procの仲まで見ずにENDat_exitで登録したブロックは別々のリストではなく混ざったリストで実行されるらしいとわかる。

ENDが使えないところ

class END # syntax error
end
END() # syntax error

ENDが使えるところ

class Hoge
  def END
    puts "END method"
  end
end
Hoge.new.END() # レシーバがないと呼べない
 |