Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix task description #135

Open
wants to merge 16 commits into
base: main
Choose a base branch
from
4 changes: 2 additions & 2 deletions modules/10-basics/10-hello-world/ru/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,6 @@

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

Практически все, что говорится про эликсир, является заслугой виртуальной машины эрланга. Эликсир задумывался как язык, который привносит в мир эрланга кое-что новое, чего не хватало самому эрлангу. В первую очередь это средства, повышающие уровень абстракции (Struct, Protocol), позволяющие писать более лаконичный код (оператор pipe, конструкция with), и удобно управлять проектом и его зависимостями (mix). Кроме того, это метапрограммирование -- мощная система макросов, позволяющая создавать DSL-языки. Хорошим примером такого DSL-языка является библиотека Ecto для работы с базами данных.
Практически все, что говорится про эликсир, является заслугой виртуальной машины эрланга. Эликсир задумывался как язык, который привносит в мир эрланга кое-что новое, чего не хватало самому эрлангу. В первую очередь это средства, повышающие уровень абстракции (Struct, Protocol), позволяющие писать более лаконичный код (оператор pipe, конструкция with), и удобно управлять проектом и его зависимостями (mix). Кроме того, это метапрограммирование -- мощная система макросов, позволяющая создавать DSL-языки. Хорошим примером такого DSL-языка является библиотека Ecto для работы с базами данных.

Check warning on line 6 in modules/10-basics/10-hello-world/ru/README.md

View workflow job for this annotation

GitHub Actions / main

[LanguageTool] reported by reviewdog 🐶 If the term is a proper noun, use the suggested capitalization. (EN_SPECIFIC_CASE) Suggestions: `Ruby on Rails` URL: https://languagetool.org/insights/post/spelling-capital-letters/ Rule: https://community.languagetool.org/rule/show/EN_SPECIFIC_CASE?lang=en-US Category: CASING Raw Output: modules/10-basics/10-hello-world/ru/README.md:6:179: If the term is a proper noun, use the suggested capitalization. (EN_SPECIFIC_CASE) Suggestions: `Ruby on Rails` URL: https://languagetool.org/insights/post/spelling-capital-letters/ Rule: https://community.languagetool.org/rule/show/EN_SPECIFIC_CASE?lang=en-US Category: CASING

Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе. Было бы несправедливо не сделать обучение по Elixir именно тут)
Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе.
2 changes: 1 addition & 1 deletion modules/10-basics/20-modules/ru/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ end
HexletBasics.Application.hello()
```

Один модуль встроенный в Эликсир является особенным. Это модуль _Kernel_. Функции этого модуля можно вызывать напрямую, без указания самого модуля:
Один модуль, встроенный в Эликсир, является особенным. Это модуль _Kernel_. Функции этого модуля можно вызывать напрямую, без указания самого модуля:

```elixir
is_number(13) # true
Expand Down
2 changes: 2 additions & 0 deletions modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,13 @@
Уже реализованная функция distance может вам пригодиться:

```elixir
point = {:point, 50, 50}
Solution.is_point_inside_circle(point, {:circle, {:point, 10, 10}, 100})
# => true
Solution.is_point_inside_circle(point, {:circle, {:point, -10, -10}, 20})
# => false

point = {:point, -10, 20}
Solution.is_point_inside_rect(point, {:rect, {:point, -20, 30}, {:point, 20, 10}})
# => true
Solution.is_point_inside_rect(point, {:rect, {:point, 0, 0}, {:point, 10, 10}})
Expand Down
2 changes: 1 addition & 1 deletion modules/30-flow/40-function-clause/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

В Эликсир одна функция может иметь несколько тел -- несколько разных блоков кода. В зависимости от входящих аргументов выполняется только один из этих блоков.

По английски термин "тело функции" пишется *clause* и произносится `[klôz]`. Поскольку это короче, то все Эликсир разработчики предпочитают говорить "клоз" вместо "тело функции".
По-английски термин "тело функции" пишется *clause* и произносится `[klôz]`. Поскольку это короче, то все Эликсир разработчики предпочитают говорить "клоз" вместо "тело функции".

```elixir
def handle({:dog, name}, :add) do
Expand Down
2 changes: 1 addition & 1 deletion modules/40-collections/10-map/ru/EXERCISE.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Реализуйте функцию `zip`, которая группирует элементы переданных векторов в подвектора. Если вектора отличаются длиной, то вместо сгрупированного элемента оставьте `nil`. Для обращения к элементу списка по индексу используйте `Enum.at`.
Реализуйте функцию `zip`, которая группирует элементы переданных векторов в подвектора. Если вектора отличаются длиной, то вместо сгруппированного элемента оставьте `nil`. Для обращения к элементу списка по индексу используйте `Enum.at`.
Примеры:

```elixir
Expand Down
2 changes: 1 addition & 1 deletion modules/45-structs/20-typespecs/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Для продолжения обсуждения `протоколов` и `поведения`, нам нужно ознакомиться с типизацией в Elixir.

Elixir - динамически типизированный язык, поэтому все типы в Elixir проверяются во время выполнения. Тем не менее, Elixir поставляется со *спецификациями*, которые представляют собой нотацию, используемую для:
Elixir - динамически типизированный язык, поэтому все типы в Elixir проверяются во время выполнения. Тем не менее Elixir поставляется со *спецификациями*, которые представляют собой нотацию, используемую для:

- объявления типизированных сигнатур функций (также называемых спецификациями);
- объявления пользовательских типов.
Expand Down
2 changes: 1 addition & 1 deletion modules/45-structs/30-behaviour/ru/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,4 +96,4 @@ defp find_parser(ext, parsers) do
end
```

Можно вызвать необходимый парсер напрямую или сделать словарь, где ключем будет нужное расширение файла, а значением нужный модуль парсера, однако *поведение* в этом дает чуть больше гарантий, что функции модулей реализованы соответствующим образом.
Можно вызвать необходимый парсер напрямую или сделать словарь, где ключём будет нужное расширение файла, а значением нужный модуль парсера, однако *поведение* в этом дает чуть больше гарантий, что функции модулей реализованы соответствующим образом.
2 changes: 1 addition & 1 deletion modules/55-processes/30-processes-state/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

В прошлом упражнении мы создали процесс-калькулятор, который только обрабатывает входящие запросы, не храня никакого *состояния*. Но как его сохранить? Основная идея процесса, который обрабатывает более одного сообщения за раз, это вызов рекурсивной функции, которая продолжит основной цикл обработки сообщений. Рассмотрим пример с процессом-счетчиком:
В прошлом упражнении мы создали процесс-калькулятор, который только обрабатывает входящие запросы, не храня никакого *состояния*. Но как его сохранить? Основная идея процесса, который обрабатывает более одного сообщения за раз, это вызов рекурсивной функции. Повторный вызов которой, продолжит основной цикл обработки сообщений. Рассмотрим пример с процессом-счетчиком:

```elixir
defmodule Counter do
Expand Down
2 changes: 1 addition & 1 deletion modules/55-processes/50-supervisors/ru/EXERCISE.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@

Супервизоры могут задаваться через модули, для этого нужно в модуле использовать поведение `Supervisor` и определить функцию обратного вызова `init/1`, которая будет вызвана при запуске супервизора через `start_link`. В файле с решением описано два агента, ваша задача дописать модуль `Solution`, добавив две функции:
- `start_link` - функция для запуска супервизора из модуля
- `init` - функция, которая запустится перед стартом супервизора, в котором указывается список потомков, стратегия перезапуска и т.д.
- `init` - функция, которая запустится перед стартом супервизора, в неё передается список потомков, стратегия перезапуска и т.д.

В функции `init` сделайте потомками `Decrementor` и `Incrementor`, а в стратегии перезапуска укажите `:one_for_one`.

Expand Down
2 changes: 1 addition & 1 deletion modules/55-processes/50-supervisors/ru/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ Supervisor.which_children(pid)

Зачастую используются стратегии `:one_for_one` и `:rest_for_one`.

Помимо стратегии перезапуска, в супервизоре можно указать, каким образом завершать наблюдаемые процессы. А точнее, какой сигнал выхода отправить процессу при, например, перезапуске. Можно указать приоритет у процессов потомков, например, если есть какой-то важный процесс потомок, без которого супервизия не имеет смысла и после завершения работы этого потомка супервизор получает сигнал от этого процесса и супервизор завершает работу (process shutdown). Об этом можно подробнее почитать в [официальной документации](https://hexdocs.pm/elixir/Supervisor.html#module-supervisor-strategies-and-options). Тепрерь посмотрим на примере, как работает стратегия `:one_for_all`:
Помимо стратегии перезапуска, в супервизоре можно указать, каким образом завершать наблюдаемые процессы. А точнее, какой сигнал выхода отправить процессу при, например, перезапуске. Можно указать приоритет у процессов потомков, например, если есть какой-то важный процесс потомок, без которого супервизия не имеет смысла и после завершения работы этого потомка супервизор получает сигнал от этого процесса и супервизор завершает работу (process shutdown). Об этом можно подробнее почитать в [официальной документации](https://hexdocs.pm/elixir/Supervisor.html#module-supervisor-strategies-and-options). Теперь посмотрим на примере, как работает стратегия `:one_for_all`:

```elixir
{:ok, supervisor_pid} = Supervisor.start_link([{Counter, 0}], strategy: :one_for_one)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

Допишите агента, добавив функции `add`, `drop` для регистрации/снятия процессов с учета и функцию `list_registered`, которая выводит список процессов, которые зарегистрированы через агента. Если процесс завершился, то при вызове `add` регистрировать процесс не нужно. Если удаляемый процесс не существует, то нужно вернуть `:ok`, учтите, что `Process.unregister` вызывает исключение при попытке удалить несуществующий процесс.
Допишите агента, добавив функции `add`, `drop` для регистрации/снятия процессов с учета и функцию `list_registered`, которая выводит список процессов, зарегистрированных через агента. Если процесс завершился, то при вызове `add` регистрировать процесс не нужно. Если удаляемый процесс не существует, то нужно вернуть `:ok`, учтите, что `Process.unregister` вызывает исключение при попытке удалить несуществующий процесс.

```elixir
ProcessRegister.start_link()
Expand Down
4 changes: 2 additions & 2 deletions modules/55-processes/60-genservers/ru/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

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

Возникает вопрос, а в чем разница между `Agent` и `GenServer`, ведь с первого взгляда они делают одно и то же. Разница в том, что абстракция `Agent` построена на основе `GenServer`, например в `Agent` управление состоянием происходит через функцию `Agent.update`, в то время как у `GenServer` состоянием нужно управлять вручную. Абстракция агентов построена вокруг какого-либо *состояния*, в то время как генсервер может и не обладать состоянием, а только выполнять какую-либо работу.

Expand Down Expand Up @@ -101,7 +101,7 @@ iex(48)> b GenServer
# ..............
```

Важно понимать, что обработчики `handle_call`, `handle_cast` и `handle_info` при определении завязываются на конкретные сообщения, которые они обрабатывают, поэтому важно описать паттерн catch all, который перехватит сообщения, которые генсервер не знает как обработать. Если же не описать обобщенный вариант обработки сообщения, то процесс генсервер аварийно завершится при таком вызове:
Важно понимать, что обработчики `handle_call`, `handle_cast` и `handle_info` при определении завязываются на конкретные сообщения, которые они обрабатывают, поэтому важно описать паттерн-матч функцию catch all. Эта функция перехватит сообщения, которые генсервер не знает как обработать. Если же не описать обобщенный вариант обработки сообщения, то процесс генсервер аварийно завершится при таком вызове:

```elixir
GenServer.call(Counter, :do_something_different)
Expand Down
Loading