Как справиться с тем, что вы не знаете, какие исключения могут быть вызваны библиотечным методом в Ruby?

Это довольно широкий вопрос, но я продолжаю сталкиваться с ним при программировании на Ruby. У меня в основном опыт работы с C и Java, где, когда я использую библиотечную функцию или метод, я просматриваю документацию и вижу, что она возвращает при ошибке (обычно в C) или какие исключения она может генерировать (в Java).

В Ruby ситуация выглядит совершенно иначе. Сейчас мне нужно проанализировать некоторый JSON, который я получаю с сервера:

data = JSON.parse(response)

Естественно, первое, о чем я думаю после написания этого кода, это что, если ввод неправильный? Будет ли parse возвращать nil при ошибке или вызывать какое-то исключение, и если да, то какие?

Я проверяю документацию (http://flori.github.com/json/doc/JSON.html#M000022) и посмотрите просто:

«Разбери источник строки JSON в структуру данных Ruby и верни его».

Это всего лишь пример шаблона, с которым я неоднократно сталкивался в Ruby. Первоначально я полагал, что это был какой-то недостаток документации любой библиотеки, с которой я работал, но теперь я начинаю чувствовать, что это стандартная практика, и у меня несколько иное мышление, чем у программистов Ruby. Есть ли какое-то соглашение, о котором я не знаю?

Как с этим справляются разработчики?

(И да, я просмотрел код библиотечного метода и могу получить некоторое представление о том, какие исключения возникают, но я не могу быть уверен на 100%, и если он не задокументирован, мне неудобно полагаться на него.)

EDIT: просмотрев первые два ответа, позвольте мне продолжить приведенный выше пример синтаксического анализа JSON.

Я подозреваю, что не должен делать:

begin
  data = JSON.parse(response)
  raise "parse error" if data.nil?
rescue Exception => e
  # blahblah
end

потому что я могу посмотреть на код/тесты и увидеть, что он, кажется, вызывает ParserError при ошибке (возврат nil, кажется, не является стандартной практикой в ​​Ruby). Буду ли я прав, если скажу, что рекомендуемая практика заключается в следующем:

begin
  data = JSON.parse(response)
rescue JSON::ParserError => e
  # blahblah
end

...на основе того, что я узнал о ParserError, просматривая код и тесты?

(Я также отредактировал пример, чтобы уточнить, что это ответ сервера, который я анализирую.)


person user85509    schedule 08.09.2009    source источник


Ответы (5)


(И да, я просмотрел код библиотечного метода и могу получить некоторое представление о том, какие исключения возникают, но я не могу быть уверен на 100%, и если он не задокументирован, мне неудобно полагаться на него.)

Я предлагаю взглянуть на тесты, так как они покажут некоторые из «вероятных» сценариев и то, что может возникнуть. Не забывайте, что хорошие тесты — это тоже документация.

person theIV    schedule 08.09.2009
comment
согласился, напишите все возможные спецификации/тесты для ваших входных данных в свой метод и разработайте свое приложение для управления этими исключениями. - person Jirapong; 08.09.2009
comment
Это хороший момент, и теперь я буду смотреть на тесты. - person user85509; 09.09.2009

Если вы хотите удалить недопустимые данные JSON:

begin
  res = JSON.parse(string)
rescue JSON::ParserError => e
  # string was not valid
end
person pastullo    schedule 25.08.2015

Я предполагаю, что если документация не предоставлена, вам придется полагаться на что-то вроде этого:

begin
   # code goes here
rescue
   # fail reason is in $!
end
person Geo    schedule 08.09.2009
comment
это в основном то же самое, что и ответ Прита Сангхи stackoverflow.com/a/1392459/2658159. Кроме того, вы говорите, что если документация не предоставлена, как будто отсутствие документации по этому поводу является крайним случаем. но на самом деле отсутствие документации - или, по крайней мере, плохая документация о конкретных исключениях, вызываемых методами, - является нормой даже в основной и стандартной библиотеке. - person Aaron Thomas; 05.05.2020

Вы никогда не можете быть уверены, какие исключения могут быть вызваны, если только код библиотеки не перехватывает все, а затем оборачивает их. Лучше всего принять хороший ввод из вашего кода, санируя то, что входит, а затем использовать собственную обработку исключений более высокого уровня, чтобы поймать неверный ввод из ваших вводов.

person Preet Sangha    schedule 08.09.2009
comment
Я не думаю, что это реально. В данном конкретном случае я анализирую ответ от сервера. В редком случае, когда сервер отправил мне неверные данные, я хочу, по крайней мере, иметь возможность корректно завершить работу и сказать неправильный ответ от сервера. - person user85509; 08.09.2009
comment
В этом случае вам нужно поймать общее исключение из этого метода и повторно вызвать его с соответствующим сообщением. - person Preet Sangha; 08.09.2009

Ваш вопрос сводится в основном к двум вопросам: существует ли соглашение или стандарт для поиска возможных исключений, а также где документация, связанная с таким соглашением?

Что касается первого вопроса, то наиболее близким к соглашению или стандарту является расположение и существование файла exceptions.rb. Для библиотек или гемов, исходный код которых общедоступен, вы обычно можете найти типы исключений в этом файле. (См. здесь).

Если исходный код недоступен или легко доступен, документация — ваш следующий лучший источник информации. Это подводит нас ко второму вашему вопросу. К сожалению, документация не имеет единого формата относительно возможных исключений даже в стандартных библиотеках. Например, Net::Http документация не делает очевидным, какие исключения доступны, хотя, если вы покопаетесь в нем, вы обнаружите, что все исключения наследуются от Net::HTTPExceptions.

В качестве другого примера (опять же из документации стандартной библиотеки): JSON документации показан класс Exception (который действительно находится в файле exceptions.rb, хотя и в исходном коде по адресу json/lib/json/add/exceptions.rb). Дело в том, что это непоследовательно; документация для класса Exception не указана так же, как для Net::HTTPException.

Более того, в документации для большинства методов нет указания на исключение, которое может быть вызвано. Ссылка, например, parse, один из наиболее часто используемых методов уже упомянутого модуля JSON: исключения вообще не упоминаются.

Отсутствие стандарта и согласованности также наблюдается в основных модулях. Документация для Math не содержит ссылок на исключения.rb. То же самое с File и его родителем IO.

И так далее, и так далее.

Веб-поиск выдаст много информации о том, как спасать исключения, и даже несколько типов исключений (ref здесь, здесь, здесь, здесь и т. д.). Однако ни один из них не дает ответа на ваши вопросы о том, что является стандартом для поиска исключений, которые могут быть вызваны, и где находится документация для этого.

И последнее замечание: здесь было предложено, что если ничего не поможет, вы можете спасти StandardError. Во многих случаях это далеко не идеальная практика (ссылка этот ответ SO), хотя я предполагаю, что вы уже понять это, основываясь на вашем знакомстве с Java и на том, как вы задали этот вопрос. И, конечно же, из мира Java вам нужно помнить, что нужно спасать StandardError, а не Exception.

person Aaron Thomas    schedule 05.05.2020
comment
Между прочим, я добавляю этот ответ, потому что мне также задавался тот же вопрос, исходящий из фона .NET (аналогично Java), и я столкнулся с тем же разочарованием, написав код Ruby на стороне - person Aaron Thomas; 05.05.2020