Разные мелочи
3 недели в блог не писал и уже тяжело снова начинать. Так однажды я 2 года спортом не позанимался и тоже лень было возвращаться. Есть правда хорошое решение - нужно себя заставлять. И вот сегодня я хочу рассказать про разные мелочи, с которыми столкнулся в свое время.
Kernel.caller
Вы будете смеятся, но раньше, чтобы вывести стек вызова методов приложения я использовал конструкцию:
def some
begin
raise
rescue => e
p e.backtrace # => ["demo.rb:3:in `some'", "demo.rb:9:in `<main>'"]
end
end
some
После C++ мне казалось, что это вполне нормально (в C++ попробуйте вывести стек приложения в лог, там не побалуешь). Но это же руби,
здесь можно все, причем очень просто! Случайно в интернете обратил внимание на системный вызов Kernel.caller
.
Напечатать цепочку вызовов можно так:
def some
p caller # => ["demo.rb:5:in `<main>'"]
end
some
Добавление ошибки валидации на :base
Отображая ошибки валидации с помощью стандартного object.errors.full_messages
, мы иногда получаем такие сообщения:
"Password Укажите пожалуйста пароль". Чтобы быстро избавиться от обязательно названия атрибута в начале сообщения, можно добавлять
ошибки валидации следующим образом: object.errros.add(:base, 'Укажите пожалуйста пароль')
. full_message
не будет
добавлять название атрибута в этом случае - activemodel/lib/active_model/errors.rb#L287.
Rescue в одну строку
Этим шаблоном я еще не воспользовался, но он интригует. Все мы используем конструкции для установки значений по умолчанию:
a = some || "default"
b = other.presence || "start" # Rails only, обрабатывает nil? и blank?
Оказывается можно так же легко установить дефалтовое значение, если метод вызывает исключение:
a = another rescue "after exception"
Я обычно не вызываю эксепшенов в своем коде, которые где-то нужно обрабатывать. Но с внешними вызовами возможно пригодится.
IndexBy
Чего только не придумают руби-программисты, чтобы писать меньше кода. Недавно наткнулся на удивительный метод index_by в рейлс:
# Выдержка из документации:
# Convert an enumerable to a hash:
people.index_by(&:login)
# => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
Ассерты
В С++ очень активно используются ассерты для проверки входных параметров, при выполнении каких-то подозрительных действий, для проверки возвращаемых значений и т.д. Это является частным случаем программирования по контракту. В рейлс, для собственного спокойствия, я тоже часто вставляю такого рода проверки. Приведу несколько типовых случаев:
# 1.
# не обращайте внимание на цепочку if-elseif, не могу себя
# отучить в пользу case.
if mode == :some
# ...
elsif mode == :another
# ...
else
raise "unreacheable: #{mode}"
end
# 2.
options.assert_valid_keys(:key_a, :key_b)
# 3.
raise "wrong #{state}" unless %w[start finish].include?(state)
Я обычно не заморачиваюсь внятными сообщения в эксепшенах, так как если ошибка и случится, то по трейсу всегда легко отследить проблему. Данные конструкции призваны подсказывать программисту, что в коде возник какой-то случай, о котором раньше не позаботились. Также эти конструкции легко расширяются, когда появляются новые режимы, ключи или состояния.
Для первого раза думаю хватит. Рад возвращению в онлайн. Раньше мы работали над большим количеством маленьких проектов и я прежде всего оптимизировал скорость и стандартность разработки. Сейчас у нас есть парочку средних проектов, на несколько человеко-месяцев (мифических :-) каждый. При увеличении кодовой базы возникают проблемы другого сорта, с которыми я буду сталкиваться, осмыслять и рассказывать вам. До новых встреч!
Tweet