# Ошибки

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

## Отлов ошибок

Но одно дело натыкаться на эти ошибки во время разработки, а другое дело, когда эти ошбки видит наш конечный пользователь. Для того, чтобы нам защититься от неожиданного поведения программы существует понятие `отлов ошибок`. В Ruby для этого мы можем воспользоваться конструкцией `begin ... end`.

```ruby
user_input = gets.chomp.to_i
puts 10 % user_input
```

простейшая программа, которая получает пользовательский ввод и делит 10 на полученное число. Но вот не задача, пользователь вводит 0, а как мы знаем, делить на 0 нельзя. В итоге получим ошибку `ZeroDivisionError`. Давайте исправим ситуацию:

```ruby
user_input = gets.chomp.to_i
# все что находится между begin и rescue будет проверяться на ошибки
# если ошибка срабатывает, то начинает работать логика между rescue и end 
begin
  puts 10 % user_input
# после rescue мы указываем ошибку, которую мытаемся отловить
# err - объект класса ошибки которую отлавливаем
rescue ZeroDivisionError => error
  # Важно в случае ошибок не просто обработать и дать корректный ответ
  # но и не потерять информацию об ошибке, например написать ее в консоль
  p error
  puts 0
# количество отлавлиемых ошибок может быть сколько угодно
# Если ошибка не является объектом класса первой отлавливаемой ошибки, значит проверяется следующий rescue  тд.
rescue ArgumentError => error
    puts "Ошибка: Некорректный формат введенных данных. #{error.inspect}"
end
# если мы отловили ошибку, то после кода внутри rescue программа начем работать дальше
puts "finish"
```

В целом `begin ... rescue ... end` по своему виду очень похож на `if ... elsif ... else ... end`, только в одном случае мы проверяем условия, а в другом тип ошибки.

## Создание собственных

Как Ruby выкидывает нам свою ошибку, так и мы можем выкидывать свои собственные ошибки.

Для начала создадим класс ошибки и унаследуем его от `StandardError`:

```ruby
class MyError < StandardError
  def initialize(message)
    # любая ошибка имеет внутри себя сообщение об ошибке, которое в случае чего показывается в консоли
    # например ZeroDivisionError имеет текст "divided by 0"
    super(message)
  end
end
```

Теперь нам нужно выбросить эту самую ошибку

```ruby
def example(arg)
  if arg > 10
    # выброс ошибки отличается от создание объекта
    # нсачала пишем raise, потом класс ошибки, потом текст, который будет передан в метод initialize
    raise MyError, "helpful description for error"
  else
    puts "It is argument - #{arg}"
  end
end

begin 
  # Сначала в консоль распечатается 'It is argument - 1'
  example(1)
  # Здесь уже сработает наша ошибка
  example(20)
# Отловили нашу ошибку
rescue MyError => error
  # Теперь в консоль напечаталось 'It is MyError - helpful description for error'
  puts "It is MyError - #{error.message}"
end
```

## Дополнительный материал

* [Ошибки в Ruby](https://rollbar.com/guides/ruby/how-to-handle-exceptions-in-ruby/)
* [Все встроенные ошибки Ruby](https://www.honeybadger.io/blog/understanding-the-ruby-exception-hierarchy/)
* [Создание собственных ошибок](https://www.honeybadger.io/blog/ruby-custom-exceptions/s)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://evgenii-afanasev.gitbook.io/ruby-course/5_advanced/5_exceptions.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
