rubyで繰り返しの中で例外処理

[code]

    require 'open-uri'
    urls = %w(url1, url2, url3)
    urls.each do |url|
      res = open(url)
    end
    
[/code]

open(url)で例外が発生しないときは、その場でresを返し、  
例外が発生したら次のurlを試したいのですが、  
どう書いたらいいでしょうか？




使用文脈がわかりませんのでテストしてませんが、  
こんな感じでいいかと思います。

[code]

    urls = %w(url1 url2 url3)
    urls.each do |url|
        begin
            res = open(url)
            return res
        rescue
            next
        end
    end
    
[/code]




おそらくですが、やりたいことは「複数のURLの中から有効なURLを見つけたい」という処理ではないかと予想します。

僕が実装するなら、まずURLの有効無効をチェックするメソッドを定義します。

[code]

    require 'open-uri'
    
    def valid_url?(url)
      open(url)
    rescue SocketError, OpenURI::HTTPError 
      # サーバーが見つからない、もしくはページが見つからない場合はfalse
      false
    end
    
[/code]

例外クラスを指定せずにrescueしてしまうと、本来rescueすべきでない例外までrescueしてしまう恐れがあるため、目的に応じた例外クラスを指定する方がベターです。

次に、「URLを見つけたい」のであれば、「each + 変数に格納」ではなく、findやselectを使った方がシンプルかつ明示的なコードになります。

[code]

    urls = %w(url1 url2 url3)
    
    # 最初に見つかった1件を取得
    valid_url = urls.find{|url| valid_url?(url) }
    
    # 最後に見つかった1件を取得
    valid_url = urls.reverse.find{|url| valid_url?(url) }
    
    # 有効なURLをすべて配列として取得
    valid_urls = urls.select{|url| valid_url?(url) }
    
[/code]

まとめるとこんな実装になります。

[code]

    require 'open-uri'
    
    def valid_url?(url)
      open(url)
    rescue SocketError, OpenURI::HTTPError 
      false
    end
    
    urls = %w(url1 url2 url3)
    valid_urls = urls.select{|url| valid_url?(url) }
    
[/code]

質問内容とは若干視点の異なる回答になりましたが、コードの可読性、再利用性、拡張性、堅牢性といった点ではこうしたコードの方が良い結果をもたらすと思います。

以上、ご参考までに。

## 参考URL

  * [[初心者向け] RubyやRailsでリファクタリングに使えそうなイディオムとか便利メソッドとか - Qiita](http://qiita.com/jnchito/items/dedb3b889ab226933ccf)
  * [Ruby - Railsアプリケーションにおけるエラー処理（例外設計）の考え方 - Qiita](http://qiita.com/jnchito/items/3ef95ea144ed15df3637)

