いちいち拡張しなくても

nil に対する each で「何もしない」のが論理的に正しいっつうのは正直よくわからん。Duck typing としても筋が悪いような気がする。
てか、こんなの適当にヘルパメソッド追加すればいいだろ。

def safe_select(reads, writes = nil, expects = nil, timeout = nil)
   r = select(reads, writes, expects, timeout)
   return r || [[], [], []]
end

もしくは block を受け取るメソッドを書くとか。

def select(reads, writes = nil, expects = nil, timeout = nil)
   r = IO.select(reads, writes, expects, timeout)
   if block_given? and r
      yield *r
   else
      r
   end
end

ここの問題は配列がくることを期待しているのに実は配列以外になるケースがあることなんだな。だったらどういうシチュエーションでも配列が戻るようにするという方法をとるのが筋じゃないかなぁ。
つか、Enumerate を include せずに each だけ定義してもなぁ。NoMethodError で発覚するところが発覚しにくくなるデメリットのほうが怖いけどなぁ。