ruby exceptions

27
Исключения и Ruby Андрей Колешко @ka8725 [email protected]

Upload: -

Post on 22-Jun-2015

463 views

Category:

Documents


1 download

TRANSCRIPT

Page 1: Ruby exceptions

Исключения и Ruby

Андрей Колешко@[email protected]

Page 2: Ruby exceptions

Общие проблемы подхода к разработке

Программируйте не на языке, а с помощью языка.

С. Макконнелл

Page 3: Ruby exceptions

Проблемы исключений

Использование исключений в неисключительных ситуациях

Page 4: Ruby exceptions

Примерdef create @user = User.new params[:user] @user.save! redirect_to user_path(@user)rescue ActiveRecord::RecordNotSaved flash[:notice] = 'Unable to create user' render :action => :newend

Page 5: Ruby exceptions

Правильный подходdef create @user = User.new params[:user] if @user.save redirect_to user_path(@user) else flash[:notice] = 'Unable to create user' render :action => :new endend

Page 6: Ruby exceptions

Где использовать методы, генерирующие исключения

• Могут быть полезны в тестах для проверки валидаций

• В транзакциях для эмуляции отката

Page 7: Ruby exceptions

Где не использовать методы, генерирующие исключения

• По возможности везде!

• Так или иначе, нам не избавиться от случаев, когда без исключений не обойтись

Page 8: Ruby exceptions

За что мы любим Ruby?

File.open('testfile') do |file| while line = file.readline puts line endrescue EOFError returnend

Любили бы мы Ruby за это?

Page 9: Ruby exceptions

За что мы любим Ruby?

File.open('testfile') do |file| while line = file.gets puts line endend

Мы любим Ruby за это:

Page 10: Ruby exceptions

Примеры исключительных ситуаций• Потеря соединения с базой данных• Переполнение памяти• Ошибка чтения/записи сокетаСлучаи, возникающие вследствии пользовательского ввода НЕ являются исключительными ситуациями!

Page 11: Ruby exceptions

Должны ли мы отлавливать исключительные ситуации?

• Все зависит от типа приложения и его требований

• В большинстве случаев нет• Любая строчка в коде может вызвать исключение. Отлавливать все?

Page 12: Ruby exceptions

Не ловите все

user.address.street rescue ‘’

Page 13: Ruby exceptions

Не ловите все

user.address.street rescue ‘’

# а как насчет этого:user.address.bla_bla_bla rescue ‘’

Page 14: Ruby exceptions

Будьте выразительнее

if user.address user.address.streetend

Page 15: Ruby exceptions

Где может быть полезен inline rescue?

val_or_error = {}.fetch(:name) rescue $!val_or_error#=> #<KeyError: key not found: :name>

Ловим исключение и анализируем его:

Page 16: Ruby exceptions

Не перехватывайте Exceptionclass TaskProcessor def perform(id) task = Task.find(id) task.process rescue Exception => e task.log(e.message) raise endend

Page 17: Ruby exceptions
Page 18: Ruby exceptions

Результат

NoMethodError: undefined method `log' for nil:NilClassДействительный

ОжидаемыйActiveRecord::RecordNotFound: Couldn't find Task withid=1000

Page 19: Ruby exceptions

Фикс

class TaskProcessor def perform(id) task = Task.find(id) task.process rescue ProcessError => e task.log(e.message) raise endend

Page 20: Ruby exceptions
Page 21: Ruby exceptions

Пути обхода

• Предоставляйте стратегию отступления

• Применяйте паттерны проектирования

• Пишите тестыСложность написания теста укажет на плохо спроектированную систему

Page 22: Ruby exceptions

Hash#fetch

h = {}h.fetch(:name) # =>KeyError: key not found: :nameh.fetch(:name) { 'ka8725' } # => "ka8725"

Page 23: Ruby exceptions

Обратная связь

def run on_success do

# обработка успеха end on_failure do # обработка ошибки endend

http://goo.gl/lchi1K

Page 24: Ruby exceptions

Throw/catch

def invoke @res = catch(:halt) { yield } # дальше анализ resendinvoke { throw :halt, "response 1"}@res #=> "response 1"invoke { "response 2" }@res #=> "response 2"

http://goo.gl/qey41F - исходники sinatra

Page 25: Ruby exceptions

Правило выбрасывания исключений

Дейв Томас и Энди Хант, Прагматик-программист

Page 27: Ruby exceptions

Вопросы?

Андрей Колешко@[email protected]