Изящный разбор дат в Ruby - PullRequest
19 голосов
/ 26 апреля 2011

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

К сожалению, кажется, что DateTime.strptime выдает исключениеесли синтаксический анализ не удался, это заставляет меня написать это чудовище:

starting = if params[:starting].present?
  begin
    DateTime.strptime(params[:starting], "%Y-%m-%d")
  rescue
    @meeting_range.first
  end
else
  @meeting_range.first
end

Чувствует себя плохим человеком.Есть ли способ проанализировать дату с помощью Ruby stdlib, который не требует блока begin...rescue? Хронический в этой ситуации кажется излишним.

Ответы [ 2 ]

21 голосов
/ 10 января 2014

В общем, я не могу согласиться с другим решением, поэтому использование rescue - плохая практика. Я думаю, что стоит упомянуть, если кто-то еще попытается применить концепцию к другой реализации.

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

Следующее относится к Date, а не DateTime, но вы поймете:

Date.parse(home.build_time) # where build_time does not exist or home is nil
Date.parse(calculated_time) # with any exception in calculated_time

Столкнувшись с той же проблемой, я в итоге обезьяной исправил Ruby следующим образом:

# date.rb
class Date
  def self.safe_parse(value, default = nil)
    Date.parse(value.to_s)
  rescue ArgumentError
    default
  end
end

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

Единственное правильное использование inline rescue - это что-то похожее на это:

f(x) rescue handle($!)

Обновление

В эти дни я предпочитаю , а не обезьяний патч Ruby. Вместо этого я обертываю Date в модуль Rich, который я вставил в lib/rich, и затем вызываю его с помощью:

Rich::Date.safe_parse(date)
19 голосов
/ 26 апреля 2011

Почему бы просто:

starting = DateTime.strptime(params[:starting], '%Y-%m-%d') rescue @meeting_range.first
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...