Ruby の retry はどこからリトライしているのか ?(Ruby 1.8系)
ちなみに
- 下記は、Ruby 1.9系では構文エラーになる。
知ってちょっとびっくりした
# # test.rb # class RetryTest def initialize @x = 0 puts "initialize!!" end def test x @x += 1 yield @x retry if x > @x end end puts RUBY_VERSION t = RetryTest.new t.test(3) { |i| puts "test - #{i}" }
$ ruby test.rb 1.8.7 initialize!! test - 1 test - 2 test - 3
RetryTest#test は
- @x をインクリメント
- ブロックを評価、その際に引数に @x を渡す
- @x が x を超えない場合は リトライ する
リトライってどこからしているの?
実行結果から、 #test が再実行されている事は明らかだが・・
# # test.rb # class RetryTest def initialize @x = 0 puts "initialize!!" end def test x @x += 1 yield @x retry if x > @x end end def hoge puts "#hoge called!" 3 end puts RUBY_VERSION t = RetryTest.new t.test(hoge) { |i| puts "test - #{i}" }
$ ruby test.rb 1.8.7 initialize!! #hoge called! test - 1 #hoge called! test - 2 #hoge called! test - 3
どうやら引数も再評価されている。これは予想の上だった。
更にびっくりした
インスタンス生成とメソッド呼び出しを1行で書いてみる
# # test.rb # class RetryTest def initialize @x = 0 puts "initialize!!" end def test x @x += 1 yield @x retry if x > @x end end def hoge puts "#hoge called!" 3 end puts RUBY_VERSION RetryTest.new.test(hoge) { |i| puts "test - #{i}" }
$ ruby test.rb 1.8.7 initialize!! #hoge called! test - 1 initialize!! #hoge called! test - 1 initialize!! #hoge called! test - 1 以下延々と続く・・・
リトライのたびにインスタンスが生成されている
引数の評価だけでなく、行全体が再度評価されている模様。
これは初見だとハマると思う。
Ruby 1.9 系ではこんなエラー
$ rvm 1.9.2 test.rb test.rb:9: Invalid retry test.rb: compile error (SyntaxError)