2010-09-27 25 views
28

Mon application (Ruby 1.9.2) peut générer différentes exceptions, y compris des interruptions de connexion réseau. I rescue Exception => e, puis faites case/when pour les traiter de différentes manières, mais plusieurs erreurs passent par mes cas directement à else.Comment faire pour attraper la classe Errno :: ECONNRESET dans "cas quand"?

rescue Exception => e 
    p e.class 
    case e.class 
     when Errno::ECONNRESET 
      p 1 
     when Errno::ECONNRESET,Errno::ECONNABORTED,Errno::ETIMEDOUT 
      p 2 
     else 
      p 3 
    end 
end 

Prints:

Errno::ECONNRESET 
3 
+1

Récupérez vos classes d'erreurs dans un bloc de secours multiple, puis évitez complètement l'instruction case. –

Répondre

49

Ceci est dû à la façon dont l'opérateur === travaille sur la classe Class

La déclaration caseinternally calls la méthode === sur l'objet que vous évaluez contre. Si vous voulez tester la classe e, il vous suffit de tester contre e, et non e.class. C'est parce que e.class tomberait dans le cas when Class, parce que, bien, e.class est une classe.

rescue Exception => e 
    case e 
     when Errno::ECONNRESET 
      p 1 
     when Errno::ECONNRESET,Errno::ECONNABORTED,Errno::ETIMEDOUT 
      p 2 
     else 
      p 3 
    end 
end 

Ouais, Ruby peut avoir une sémantique étrange parfois

+4

Ouais, bizarre. 1 === 1 => vrai. Tableau === Tableau => faux. – Nakilon

+0

Euh. Je parierais que 'Array === Class' donnerait vrai, mais maintenant je suis confus. Merci à votre commentaire maintenant je ne peux pas dormir:/ – Chubas

+4

Bien sûr, maintenant il est logique. Le '===' est appelé sur l'élément que vous comparez. Donc 'Class === Array',' String === "foobar" 'et'/foo/=== "foobar" 'tout retourne vrai. – Chubas

1

Eh bien cela dépend de si vous référence à la classe ou la constante. je par exemple dû utiliser l'instruction case suivante pour obtenir un certain type de détection de travail

def fail(exception_error) 
exception = exception_error 
case exception.class 
    when /HTTPClient::ConnectTimeoutError.new/ 
    status = 'CONNECTION TIMEOUT' 
    connection_status = 'DOWN' 
    else 
    status = 'UNKNOWN FAILURE' 
    connection_status = 'DOWN' 
end 

Mais c'est parce que je travaille avec la classe réelle d'exception et non la constante. HttpClient soulève un objet de classe réelle:

class TimeoutError < RuntimeError 
end 
class ConnectTimeoutError < TimeoutError 
end 

est ici un fait déconcertant:

error = HTTPClient::ConnectTimeoutError.new 
HTTPClient::ConnectTimeoutError === error 
#=> true 
error === HTTPClient::ConnectTimeoutError 
#=> false 

Je ne sais pas quoi faire de cela.

+0

quelle version de ruby ​​était le «fait curieux» exécuté? –