元ネタにコメントが書けないのでこっちに。
rescue修飾子とは
逆引きRubyの例外の項を見るとわかるけど、中置rescue(=rescue修飾子)は 左辺で例外発生時、右辺を実行するという意味 なので、serialport.read rescue EOFError
とは、なんか例外が発生したら定数EOFErrorを評価して、その結果EOFErrorクラスを返すという意味になる。なので
rescueで拾ったEOFErrorがreturnされてた
のではなくて、EOFErrorクラスが返されているのであって、発生した例外が返されているわけではない。
serialport.read rescue nil
としたら想定の動作になる。
そもそも
rescue修飾子を忘れてたので、以下のワンライナーでログファイルが一部存在しない場合IOエラーになったので、ググってた。
$ ruby -e 'ARGV.each{|x|puts "***#{x}***";puts IO.read(x)}' pre_process.log process1.log process2.log post_process.log
***pre_process.log***
これから処理するよ…
***process1.log***
一個目処理してるよ…
***process2.log***
-e:1:in `read': No such file or directory @ rb_sysopen - process2.log (Errno::ENOENT)
from -e:1:in `block in <main>'
from -e:1:in `each'
from -e:1:in `<main>'
単純に直したらこう。
$ ruby -e 'ARGV.each{|x|puts "***#{x}***";puts IO.read(x) rescue puts "not found"}' pre_process.log process1.log process2.log post_process.log
***pre_process.log***
これから処理するよ…
***process1.log***
一個目処理してるよ…
***process2.log***
not found
***post_process.log***
処理終わったよ
しかし2個めのputsが冗長な気がして以下に書き換えると文法エラーになる。イケてもよさそうな気もするけど、カッコの中にはrescue修飾子が書けない様子。
puts(IO.read(x) rescue "not found")
まあ手抜きしないでファイルチェックせーよっていう話だけども。
ARGV.each do |x|
puts "***#{x}***"
puts File.exists?(x) ? IO.read(x) : "not found"
end
パーミッション無かったりするとこれでも落ちるけど。
FileTest::readable?のほうが適切か。
しかし
rescue修飾子の評価順は左辺→右辺だけど、(if|unless|while|until)修飾子は 右辺の評価が先 なので、やや迷う気もする。よく次のように書くけど、この場合は右がtrueなら左を実行。
There.do_something if My.foo_enabled?
あとwhile(until)修飾子で、いわゆる後置while(do..while)が実現されているのだが、知らんかったけど、どうも 左辺にbegin - endがある場合は左辺が先、なければ右辺が先 らしい。やや気持ち悪い?
do whileは入力ループなんかで使うと思う。begin x=gets;end while x =~ /on|off/i
とか。Rubyのbegin-endは変数スコープを導入しないので、これでも問題なく動く。評価順が変わることでハマるパターンとかないのかな?(例が思いつかないのでなさそう)