Как отловить класс Errno :: ECONNRESET в случае, когда?

Мое приложение (Ruby 1.9.2) может вызывать различные исключения, включая разрывы сетевых подключений. Я rescue Exception => e, затем делаю case/when, чтобы обрабатывать их разными способами, но несколько ошибок проходят через мои случаи прямо в else.

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

Печать:

Errno::ECONNRESET
3

person Nakilon    schedule 27.09.2010    source источник
comment
Спасите свои классы ошибок в блоке multi-rescue, и тогда вы сможете полностью избежать оператора case.   -  person Andy Triggs    schedule 03.02.2015


Ответы (2)


Это связано с тем, как оператор === работает с классом Class.

Оператор case внутренне вызывает === метод объекта, по которому вы оцениваете . Если вы хотите протестировать класс e, вы просто тестируете e, а не e.class. Это потому, что e.class попадет в случай when Class, потому что, ну, e.class - это класс.

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

Да, Ruby иногда может иметь странную семантику

person Chubas    schedule 27.09.2010
comment
Ага, странно. 1 === 1 = ›верно. Массив === Массив = ›ложь. - person Nakilon; 27.09.2010
comment
Эм-м-м. Бьюсь об заклад, Array === Class дал бы правду, но теперь я запутался. Благодаря вашему комментарию теперь я не могу спать: / - person Chubas; 27.09.2010
comment
Конечно, теперь это имеет смысл. === вызывается для элемента, с которым вы сравниваете. Итак, Class === Array, String === "foobar" и /foo/ === "foobar" все возвращают истину. - person Chubas; 27.09.2010

Ну, это зависит от того, ссылаетесь ли вы на класс или константу. Мне, например, пришлось использовать следующий оператор case, чтобы заставить работать определенный тип обнаружения

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

Но это потому, что я работаю с фактическим классом исключения, а не с константой. HTTPCLient поднимает фактический объект класса:

class TimeoutError < RuntimeError
end  
class ConnectTimeoutError < TimeoutError
end

Вот загадочный факт:

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

Не уверен, что с этим делать.

person Ashley Raiteri    schedule 25.10.2014
comment
в какой версии рубина был использован этот «загадочный факт»? - person David West; 29.09.2016