├── bin └── test.sh ├── test ├── test_helper.exs └── exercises_elixir_test.exs ├── modules ├── 30-flow │ ├── 20-case │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 30-cond │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 50-pipeline │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── lib │ │ │ └── solution.ex │ │ ├── mix.exs │ │ └── ru │ │ │ ├── data.yml │ │ │ ├── EXERCISE.md │ │ │ └── README.md │ ├── 10-pattern-matching │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 40-function-clause │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── Makefile │ │ ├── ru │ │ │ └── data.yml │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 15-pattern-matching-for-maps │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── description.en.yml │ └── description.ru.yml ├── 10-basics │ ├── 20-modules │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── data.yml │ │ │ └── README.md │ │ ├── ru │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── lib │ │ │ └── solution.ex │ │ └── mix.exs │ ├── 30-strings │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── lib │ │ │ └── solution.ex │ │ └── mix.exs │ ├── 40-numbers │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ ├── EXERCISE.md │ │ │ └── README.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 50-booleans │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 70-interop │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── lib │ │ │ └── solution.ex │ │ ├── mix.exs │ │ └── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ ├── 75-sigils │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 10-hello-world │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── lib │ │ │ └── solution.ex │ │ ├── mix.exs │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── data.yml │ │ │ └── README.md │ │ └── ru │ │ │ ├── EXERCISE.md │ │ │ ├── data.yml │ │ │ └── README.md │ ├── 25-functions │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── en │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── lib │ │ │ └── solution.ex │ │ └── mix.exs │ ├── 60-attributes │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── ru │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ └── lib │ │ │ └── solution.ex │ ├── description.ru.yml │ └── description.en.yml ├── 35-fp │ ├── 10-recursion │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── lib │ │ │ └── solution.ex │ │ └── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ ├── 30-immutability │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 40-anonymous-fn │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── lib │ │ │ └── solution.ex │ │ └── ru │ │ │ ├── data.yml │ │ │ ├── EXERCISE.md │ │ │ └── README.md │ ├── 20-recursion-with-acc │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── description.en.yml │ └── description.ru.yml ├── 60-macros │ ├── 20-quoting │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── lib │ │ │ └── solution.ex │ │ └── ru │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ ├── 10-macros-intro │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── lib │ │ │ └── solution.ex │ │ ├── mix.exs │ │ └── ru │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ ├── 50-macros-ast │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 30-new-functionality │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 40-macros-hygiene │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── lib │ │ │ └── solution.ex │ │ └── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ ├── description.en.yml │ └── description.ru.yml ├── 20-data-types │ ├── 20-lists │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── lib │ │ │ └── solution.ex │ │ └── mix.exs │ ├── 30-maps │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 10-atoms-and-tuples │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── description.ru.yml │ └── description.en.yml ├── 40-collections │ ├── 10-map │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 20-filter │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── lib │ │ │ └── solution.ex │ │ └── ru │ │ │ ├── data.yml │ │ │ ├── EXERCISE.md │ │ │ └── README.md │ ├── 30-reduce │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 50-stream │ │ ├── en │ │ │ ├── README.md │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── lib │ │ │ └── solution.ex │ │ └── mix.exs │ ├── 40-comprehension │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── description.en.yml │ └── description.ru.yml ├── 45-structs │ ├── 20-typespecs │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 30-behaviour │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 40-protocols │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 10-struct-intro │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 50-any-protocols │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── description.ru.yml │ └── description.en.yml ├── 55-processes │ ├── 35-links │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 50-supervisors │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── Makefile │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 60-genservers │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ └── data.yml │ │ └── lib │ │ │ └── solution.ex │ ├── 10-processes-intro │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── lib │ │ │ └── solution.ex │ │ ├── mix.exs │ │ └── ru │ │ │ ├── EXERCISE.md │ │ │ └── data.yml │ ├── 20-processes-mailbox │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 30-processes-state │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ └── test_helper.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ └── data.yml │ │ └── lib │ │ │ └── solution.ex │ ├── 40-tasks-and-agents │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ └── lib │ │ │ └── solution.ex │ ├── 55-process-registration │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── Makefile │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── ru │ │ │ └── data.yml │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── description.en.yml │ └── description.ru.yml ├── 50-errors │ ├── 10-errors-handling │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── mix.exs │ │ ├── lib │ │ │ └── solution.ex │ │ └── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ ├── 30-with-operator │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── 20-tuple-errors-processing │ │ ├── en │ │ │ ├── EXERCISE.md │ │ │ ├── README.md │ │ │ └── data.yml │ │ ├── test │ │ │ ├── test_helper.exs │ │ │ └── solution_test.exs │ │ ├── Makefile │ │ ├── ru │ │ │ ├── data.yml │ │ │ └── EXERCISE.md │ │ ├── mix.exs │ │ └── lib │ │ │ └── solution.ex │ ├── description.en.yml │ └── description.ru.yml └── 65-extra │ ├── 10-dates-and-times │ ├── en │ │ ├── EXERCISE.md │ │ ├── README.md │ │ └── data.yml │ ├── test │ │ └── test_helper.exs │ ├── Makefile │ ├── mix.exs │ ├── ru │ │ ├── data.yml │ │ └── EXERCISE.md │ └── lib │ │ └── solution.ex │ ├── description.en.yml │ └── description.ru.yml ├── docker-compose.yml ├── docker-compose.override.yml ├── .formatter.exs ├── spec.yml ├── .credo.exs ├── .github └── workflows │ └── Docker.yml ├── description.en.yml ├── Dockerfile ├── mix.exs ├── .gitignore ├── description.ru.yml ├── README.md ├── Makefile └── mix.lock /bin/test.sh: -------------------------------------------------------------------------------- 1 | mix test 2 | -------------------------------------------------------------------------------- /test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Логика 3 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Case 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Cond 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Sigils 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Maps 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Map 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Functions 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Strings 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Numbers 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | In development 3 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Lists 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Конструкция case 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Конструкция cond 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pipeline 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Recursion 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Filter 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Reduce 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Streams 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Erlang interop 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Closure 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Immutability 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Typespecs 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Behaviours 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Protocols 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start() 2 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Process links 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | 🚧 In development 3 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Genservers 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Функции в Elixir 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Boolean and logic 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Atoms 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Anonymous functions 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Structs intro 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Any protocols 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: With operator 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Supervisors 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start(capture_log: true) 2 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Macros hygiene 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Date and time 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pattern matching 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Comprehensions 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Введение в структуры 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Processes state 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Intoduction to macros 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: AST and final thoughts 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Processes mailbox 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tasks and agents 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/Makefile: -------------------------------------------------------------------------------- 1 | test: 2 | @ test.sh 3 | 4 | .PHONY: test 5 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/test/test_helper.exs: -------------------------------------------------------------------------------- 1 | ExUnit.start(capture_log: true) 2 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: New functionality 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Новые возможности 3 | tips: [] 4 | -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | services: 4 | exercises: 5 | build: . 6 | command: make check 7 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Тело функции (function clause) 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Recursion with accumulator 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Errors handling, exceptions 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Intoduction to processes 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Process registration 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Intoduction to quote and unquote 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Pattern matching for maps 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Errors handling using tuples 3 | tips: [] 4 | -------------------------------------------------------------------------------- /docker-compose.override.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | services: 4 | exercises: 5 | volumes: 6 | - .:/exercises-elixir 7 | -------------------------------------------------------------------------------- /.formatter.exs: -------------------------------------------------------------------------------- 1 | # Used by "mix format" 2 | [ 3 | inputs: ["{mix,.formatter}.exs", "modules/**/{lib,test}/*.{ex,exs}"] 4 | ] 5 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Create module _My.Super.Module_ and put the function `hello()` we defined above 2 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Сопоставление с образцом для словарей 3 | tips: [] 4 | -------------------------------------------------------------------------------- /modules/30-flow/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Flow control constructions 3 | description: | 4 | 5 | In development 6 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Modules 3 | tips: 4 | - | 5 | [Kernel](https://hexdocs.pm/elixir/Kernel.html) 6 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Определите модуль _My.Super.Module_ и поместите в него функцию `hello()` описанную выше. 3 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Модули 3 | tips: 4 | - | 5 | [Kernel](https://hexdocs.pm/elixir/Kernel.html) 6 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Словари 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Map.html) 6 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Строки 3 | tips: 4 | - | 5 | [String.upcase/2](https://hexdocs.pm/elixir/String.html#upcase/2) 6 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Арифметика 3 | tips: 4 | - | 5 | Обратите внимание, в каком порядке требуется использовать числа. 6 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Списки 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/List.html) 6 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Стримы 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Stream.html) 6 | -------------------------------------------------------------------------------- /modules/50-errors/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Errors handling 3 | description: | 4 | 5 | In this module we will study error and exception handling in Elixir. 6 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def hello do 4 | IO.puts("Hello, World!") 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule My.Super.Module do 2 | # BEGIN 3 | def hello do 4 | IO.puts("Hello, World!") 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | defmacro my_abs(x) do 4 | {:abs, [], [x]} 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/65-extra/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Extra chapter 3 | description: | 4 | 5 | In this module we cover small topics, which can be described in single exercise. 6 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Общие протоколы 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Protocol.html#derive/3) 6 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def hours_to_milliseconds(hours) do 4 | :timer.hours(hours) 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def run_in_process(function) do 4 | spawn(function) 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Регистрация процессов 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Registry.html) 6 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def print_twice(n) do 4 | IO.puts(n) 5 | IO.puts(n) 6 | end 7 | 8 | # END 9 | end 10 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Строковые метки (сигили) 3 | tips: 4 | - > 5 | [Официальная 6 | документация](https://hexdocs.pm/elixir/syntax-reference.html#sigils) 7 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Оператор with 3 | tips: 4 | - > 5 | [Официальная 6 | документация](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#with/1) 7 | -------------------------------------------------------------------------------- /modules/65-extra/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Экстра глава 3 | description: | 4 | 5 | В этом модуле мы рассмотрим небольшие самостоятельные топики, которые можно описать одним упражнением. 6 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Рекурсивные функции с аккумуляторами 3 | tips: 4 | - | 5 | [Статья в Hexlet про рекурсию](https://ru.hexlet.io/blog/posts/recursive) 6 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Отображение 3 | tips: 4 | - > 5 | [Про map, filter, 6 | reduce](https://ru.hexlet.io/blog/posts/js-prosto-o-slozhnom-filter-map-reduce) 7 | -------------------------------------------------------------------------------- /modules/45-structs/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Структуры и поведение 3 | description: | 4 | 5 | В этом модуле мы изучим структуры, как их обрабатывать и как наделить их полиморфным поведением. 6 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Create function `print_twice(value)` that prints provided value twice 3 | 4 | ```elixir 5 | Solution.print_twice("WoW") 6 | # => WoW 7 | # => WoW 8 | ``` 9 | -------------------------------------------------------------------------------- /modules/45-structs/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Structs and behavior 3 | description: | 4 | In this module, we will study structures, how to process them, and how to endow them with polymorphic behavior. 5 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def join_and_upcase(str1, str2) do 4 | String.trim(String.upcase(str1 <> str2, :ascii)) 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def get_second_item(list) do 4 | [item1, item2 | _] = list 5 | item1 + item2 6 | end 7 | 8 | # END 9 | end 10 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | def process(str, num) do 3 | # BEGIN 4 | str |> String.trim() |> String.downcase() |> String.duplicate(num) 5 | # END 6 | end 7 | end 8 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Компрехеншен или конструкторы списков 3 | tips: 4 | - > 5 | [Официальная 6 | документация](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#for/1) 7 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def generate(num) do 4 | Stream.repeatedly(fn -> Enum.random(1..20) end) |> Enum.take(num) 5 | end 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /test/exercises_elixir_test.exs: -------------------------------------------------------------------------------- 1 | defmodule ExercisesElixirTest do 2 | use ExUnit.Case 3 | doctest ExercisesElixir 4 | 5 | test "greets the world" do 6 | assert ExercisesElixir.hello() == :world 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `print_twice(value)`, которая печатает на экран переданное значение два раза 3 | 4 | ```elixir 5 | Solution.print_twice("WoW") 6 | # => WoW 7 | # => WoW 8 | ``` 9 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def sigil_i(string, []), do: String.to_integer(string) 4 | 5 | def sigil_i(string, [?n]), do: -String.to_integer(string) 6 | 7 | # END 8 | end 9 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def do_math(a, b) do 4 | IO.puts((a + b) / b) 5 | IO.puts(div(a, b)) 6 | IO.puts(rem(b, a)) 7 | end 8 | 9 | # END 10 | end 11 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def range(from, to) when from <= to do 4 | [from | range(from + 1, to)] 5 | end 6 | 7 | def range(_, _), do: [] 8 | # END 9 | end 10 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Обработка ошибок с помощью кортежей 3 | tips: 4 | - > 5 | [Пример модуля с описанным подходом к обработке 6 | ошибок](https://hexdocs.pm/elixir/File.html) 7 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def any?(a, b, c, d) do 4 | a or b or c or d 5 | end 6 | 7 | def truthy?(a, b) do 8 | a && b 9 | end 10 | 11 | # END 12 | end 13 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Неизменяемые структуры данных 3 | tips: 4 | - > 5 | [Объяснение иммутабельных структур данных на примере 6 | Clojure](https://youtu.be/wASCH_gPnDw?si=l7jkfOLZxDNyu30G&t=1815) 7 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/50-errors/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Работа с ошибками 3 | description: | 4 | 5 | В этом модуле мы изучим обработку ошибок и исключений в Elixir. Рассмотрим, в каких случаях стоит выбросить исключение, а в каких вернуть ошибку. 6 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/mix.exs: -------------------------------------------------------------------------------- 1 | defmodule Exercise.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercise, 7 | version: "0.1.0", 8 | ] 9 | end 10 | end 11 | 12 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Описание типов 3 | tips: 4 | - | 5 | [Список типов](https://hexdocs.pm/elixir/typespecs.html#basic-types) 6 | - | 7 | [Dyalyzer для Elixir](https://github.com/jeremyjh/dialyxir) 8 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Define the following attributes with values inside the module: 2 | - Attribute: number_attr, value: 10 3 | - Attribute: boolean_attr, value: false 4 | - Attribute: hello_world_attr, value: "Hello, World!" 5 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Определите внутри модуля следующие атрибуты со значениями: 2 | - Атрибут: number_attr, значение: 10 3 | - Атрибут: boolean_attr, значение: false 4 | - Атрибут: hello_world_attr, значение: "Hello, World!" 5 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Оператор pipe 3 | tips: 4 | - | 5 | [Документация для String](https://hexdocs.pm/elixir/String.html) 6 | - | 7 | [Официальная документация](https://hexdocs.pm/elixir/Kernel.html#%7C%3E/2) 8 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Рекурсия 3 | tips: 4 | - | 5 | [Статья в Hexlet про рекурсию](https://ru.hexlet.io/blog/posts/recursive?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=recursion-article) 6 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def inc_numbers(elements) do 4 | elements 5 | |> Enum.filter(&is_number/1) 6 | |> Enum.map(&(&1 + 1)) 7 | end 8 | 9 | # END 10 | end 11 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Поведение 3 | tips: 4 | - > 5 | [Официальная 6 | документация](https://hexdocs.pm/elixir/Module.html#module-behaviour) 7 | - | 8 | [Документация Plug](https://hexdocs.pm/plug/readme.html) 9 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | import Solution 5 | 6 | test "sigil_i work" do 7 | assert ~i(10) == 10 8 | assert ~i(5)n == -5 9 | assert ~i(-15)n == 15 10 | end 11 | end 12 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Задачи и агенты 3 | tips: 4 | - | 5 | [Официальная документация Agent](https://hexdocs.pm/elixir/Agent.html) 6 | - | 7 | [Официальная документация Task](https://hexdocs.pm/elixir/Task.html) 8 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | defmacro my_unless(condition, do: expression) do 4 | quote do 5 | if(!unquote(condition), do: unquote(expression)) 6 | end 7 | end 8 | 9 | # END 10 | end 11 | -------------------------------------------------------------------------------- /modules/10-basics/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Основы Elixir 3 | description: | 4 | 5 | Язык Эликсир необычный, большинство его элементов устроены сложнее, чем кажется на первый взгляд. В первом модуле мы рассмотрим модули и функции, базовые типы данных и операции над ними. 6 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Атомы и кортежи 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Atom.html) 6 | - > 7 | [Почему максимальное число атомов 8 | 1,048,576](https://www.erlang.org/doc/man/erl.html#+t) 9 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Фильтрация 3 | tips: 4 | - > 5 | [Про map, filter, 6 | reduce](https://ru.hexlet.io/blog/posts/js-prosto-o-slozhnom-filter-map-reduce?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=js-array-methods) 7 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Свертка 3 | tips: 4 | - > 5 | [Про map, filter, 6 | reduce](https://ru.hexlet.io/blog/posts/js-prosto-o-slozhnom-filter-map-reduce?utm_source=code-basics&utm_medium=referral&utm_campaign=blog&utm_content=js-filter-map-reduce) 7 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import ExUnit.CaptureIO 4 | 5 | test "greets the world" do 6 | msg = capture_io(fn -> Solution.hello() end) |> String.trim() 7 | assert msg == "Hello, World!" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/10-basics/25-functions/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import ExUnit.CaptureIO 4 | 5 | test "print twice" do 6 | msg = capture_io(fn -> Solution.print_twice("WoW") end) |> String.trim() 7 | assert msg == "WoW\nWoW" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/10-basics/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Elixir Basics 3 | description: | 4 | 5 | The Elixir language is quite complex. Most of its elements are more complex than they first appear. In the first module, we will look at modules and functions, basic data types and operations with them. 6 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Состояние процесса 3 | tips: 4 | - > 5 | [Конкурентность на примере процессов 6 | Elixir](https://www.youtube.com/watch?v=A4x6IfceJCM) 7 | - | 8 | [Официальная документация](https://hexdocs.pm/elixir/Process.html) 9 | -------------------------------------------------------------------------------- /spec.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | language: 4 | docker_image: "ghcr.io/hexlet-basics/exercises-elixir" 5 | extension: elixir 6 | exercise_filename: lib/solution.ex 7 | exercise_test_filename: test/solution_test.exs 8 | learn_as: second_language 9 | progress: completed 10 | name: Elixir 11 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import ExUnit.CaptureIO 4 | 5 | test "greets the world" do 6 | msg = capture_io(fn -> My.Super.Module.hello() end) |> String.trim() 7 | assert msg == "Hello, World!" 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | use Solution 4 | 5 | test "solution module attributes" do 6 | assert @number_attr == 10 7 | refute @boolean_attr 8 | assert @hello_world_attr = "Hello, World!" 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Почтовый ящик процессов 3 | tips: 4 | - > 5 | [Конкурентность на примере процессов 6 | Elixir](https://www.youtube.com/watch?v=A4x6IfceJCM) 7 | - | 8 | [Официальная документация](https://hexdocs.pm/elixir/Process.html) 9 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | defmacro __using__(_) do 3 | quote do 4 | # BEGIN 5 | @number_attr 10 6 | 7 | @boolean_attr false 8 | 9 | @hello_world_attr "Hello, World!" 10 | # END 11 | end 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "run_in_process work" do 5 | assert Solution.run_in_process(fn -> 2 + 2 end) |> is_pid() 6 | assert Solution.run_in_process(fn -> "hello world" end) |> is_pid() 7 | end 8 | end 9 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def my_div(x, y) when y == 0, 4 | do: raise(ArgumentError, message: "Divide #{x} by zero is prohibited!") 5 | 6 | def my_div(x, y) do 7 | Integer.floor_div(x, y) 8 | end 9 | 10 | # END 11 | end 12 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "process test" do 6 | assert "my cool stringmy cool string" == process(" My Cool String ", 2) 7 | assert "boom-boom-boom-" == process(" BOOM- ", 3) 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Интероп с Erlang 3 | tips: 4 | - | 5 | [Документация на timer](https://www.erlang.org/doc/man/timer.html) 6 | - | 7 | [Документация на os](https://www.erlang.org/doc/man/os.html) 8 | - | 9 | [Официальный сайт Erlang](https://www.erlang.org/) 10 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Attributes 3 | tips: 4 | - > 5 | [Library documentation 6 | example](https://github.com/michalmuskala/jason/blob/v1.4.0/lib/jason.ex) 7 | - > 8 | [Official 9 | documentation](https://elixir-lang.org/getting-started/module-attributes.html) 10 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | @operations %{"+" => &(&1 + &2), "-" => &(&1 - &2), "*" => &(&1 * &2), "/" => &(&1 / &2)} 4 | 5 | def calculate(operation, arg1, arg2) do 6 | Map.get(@operations, operation).(arg1, arg2) 7 | end 8 | 9 | # END 10 | end 11 | -------------------------------------------------------------------------------- /modules/10-basics/60-attributes/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Атрибуты 3 | tips: 4 | - > 5 | [Пример с документацией 6 | библиотеки](https://github.com/michalmuskala/jason/blob/v1.4.0/lib/jason.ex) 7 | - > 8 | [Официальная 9 | документация](https://elixir-lang.org/getting-started/module-attributes.html) 10 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Сопоставление с образцом (Pattern Matching) 3 | tips: 4 | - > 5 | [Про pattern 6 | matching](https://ru.wikipedia.org/wiki/%D0%A1%D0%BE%D0%BF%D0%BE%D1%81%D1%82%D0%B0%D0%B2%D0%BB%D0%B5%D0%BD%D0%B8%D0%B5_%D1%81_%D0%BE%D0%B1%D1%80%D0%B0%D0%B7%D1%86%D0%BE%D0%BC) 7 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "get second item" do 6 | assert 42 == get_second_item([20, 22, 24]) 7 | assert 3 == get_second_item([1, 2, 3, 4]) 8 | assert -3 == get_second_item([-1, -2, -3, -4]) 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/en/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Type this code in the editor and hit "Run" 2 | 3 | ```elixir 4 | # Define a module Solution 5 | defmodule Solution do 6 | # define a function hello 7 | def hello do 8 | # Call an other module's function 9 | IO.puts("Hello, World!") # No colon 10 | end 11 | end 12 | ``` 13 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def encode(str, code) when is_list(str) do 4 | Enum.map(str, fn char -> char + code end) 5 | end 6 | 7 | def decode(str, code) when is_list(str) do 8 | Enum.map(str, fn char -> char - code end) 9 | end 10 | 11 | # END 12 | end 13 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def get_values(data) do 4 | %{a: a_value, b: b_value} = data 5 | {a_value, b_value} 6 | end 7 | 8 | def get_value_by_key(data, key) do 9 | %{^key => value} = data 10 | value 11 | end 12 | 13 | # END 14 | end 15 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализовать функцию `range(from, to)`, которая принимает два числа, задающих диапазон, и возвращает список, заполненный числами в этом диапазоне, `from` и `to` включительно: 3 | 4 | ```elixir 5 | Solution.range(1, 5) # [1, 2, 3, 4, 5] 6 | Solution.range(2, 2) # [2] 7 | Solution.range(3, 2) # [] 8 | ``` 9 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def max_delta([], []), do: 0 4 | 5 | def max_delta(first, second) do 6 | Enum.zip(first, second) 7 | |> Enum.reduce(0, fn {x, y}, acc -> 8 | diff = abs(x - y) 9 | max(acc, diff) 10 | end) 11 | end 12 | 13 | # END 14 | end 15 | -------------------------------------------------------------------------------- /modules/60-macros/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Macros in Elixir 3 | description: | 4 | 5 | In this module we will look at metaprogramming in the Elixir language. Thanks to macros, you can greatly extend the expressiveness of the language by creating DSLs, but the use of macros is black magic, so they must be used with care and understanding. 6 | -------------------------------------------------------------------------------- /modules/30-flow/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Управляющие конструкции в Elixir 3 | description: | 4 | 5 | В третьем модуле мы научимся управлять ветвлениями в коде — вызывать ту или иную ветку кода в зависимости от некоторых условий. Тут мы познакомимся с killer feature функционального программирования — сопоставлением с образцом (pattern matching). 6 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Протоколы 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Protocol.html) 6 | - | 7 | [Про Expression Problem](https://en.wikipedia.org/wiki/Expression_problem) 8 | - | 9 | [Подкаст про Expression Problem](https://soundcloud.com/mimpod/episode_61) 10 | -------------------------------------------------------------------------------- /modules/40-collections/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Collections 3 | description: | 4 | 5 | In this module, we will study typical ways of working with lists and other collections: map, filter, and reduce. We will get acquainted with the Enum module, the workhorse for all collections. We will also study list constructors (lists comprehension) and streams. 6 | -------------------------------------------------------------------------------- /modules/40-collections/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Работа с коллекциями в Elixir 3 | description: | 4 | 5 | В этом модуле мы изучим типовые способы работы со списками и другими коллекциями: map, filter и reduce. Познакомимся с модулем `Enum` — рабочей лошадкой для всех коллекций. Также изучим конструкторы списков (lists comprehension) и стримы (streams). 6 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | defmacro prohibit_words(words) do 4 | quote do 5 | def forbidden?(word) when is_bitstring(word) do 6 | word in unquote(words) 7 | end 8 | 9 | def forbidden?(_), do: false 10 | end 11 | end 12 | 13 | # END 14 | end 15 | -------------------------------------------------------------------------------- /modules/60-macros/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Работа с макросами в Elixir 3 | description: | 4 | 5 | В этом модуле мы рассмотрим метапрограммирование в языке Elixir. Благодаря макросам можно значительно расширить выразительность языка, создавая DSL, однако использование макросов — черная магия, поэтому ими нужно пользоваться с осторожностью и пониманием. 6 | -------------------------------------------------------------------------------- /modules/20-data-types/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Типы данных Elixir 3 | description: | 4 | 5 | Во втором модуле мы продолжим знакомство с разными типами данных: с атомами, кортежами, списками и словарями. Если вы не знакомы с функциональным программированием, то уже на этом этапе что-то может показаться странным. Но не пугайтесь, использовать все это не сложно. 6 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def fetch_gamers(employees) do 4 | for employee <- employees, 5 | employee.status == :active, 6 | hobby <- employee.hobbies, 7 | hobby.type == :gaming do 8 | {employee.name, hobby} 9 | end 10 | end 11 | 12 | # END 13 | end 14 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | require Solution 5 | 6 | test "my_abs macro work" do 7 | assert Solution.my_abs(-2) == 2 8 | assert Solution.my_abs(2) == 2 9 | assert Solution.my_abs(-5 * 100) == 500 10 | assert Solution.my_abs(-2 - 100 + 1) == 101 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | defmacro with_logging(do: function) do 4 | quote do 5 | IO.puts("Started execution...") 6 | result = unquote(function).() 7 | IO.puts("Execution result is: #{inspect(result)}") 8 | result 9 | end 10 | end 11 | 12 | # END 13 | end 14 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "max_delta work" do 5 | assert Solution.max_delta([], []) == 0 6 | assert Solution.max_delta([-5], [-15]) == 10 7 | assert Solution.max_delta([0], [42]) == 42 8 | assert Solution.max_delta([10, -15, 35], [2, -12, 42]) == 8 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Гигиена макросов 3 | tips: 4 | - | 5 | [Статья про гигиену макросов](https://en.wikipedia.org/wiki/Hygienic_macro) 6 | - | 7 | [Официальная документация](https://hexdocs.pm/elixir/Kernel.html#var!/2) 8 | - | 9 | [Официальная документация про Env](https://hexdocs.pm/elixir/Macro.Env.html) 10 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `run_in_process`, которая принимает функцию и создает процесс, который выполняет эту функцию: 3 | 4 | ```elixir 5 | Solution.run_in_process(fn -> String.upcase("code basics") end) 6 | # => #PID<0.42.0> 7 | 8 | Solution.run_in_process(fn -> Process.sleep(1000) end) 9 | # => #PID<0.43.0> 10 | ``` 11 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `hours_to_milliseconds` которая конвертирует часы в миллисекунды, обратите внимание на `:timer` библиотеку из Erlang: 3 | 4 | ```elixir 5 | Solution.hours_to_milliseconds(0) 6 | # => 0 7 | Solution.hours_to_milliseconds(1.5) 8 | # => 5400000.0 9 | Solution.hours_to_milliseconds(2) 10 | # => 7200000 11 | ``` 12 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def zip([], []), do: [] 4 | 5 | def zip(first, second) do 6 | len = max(length(first), length(second)) 7 | range = 0..(len - 1) 8 | 9 | Enum.map(range, fn index -> 10 | [Enum.at(first, index), Enum.at(second, index)] 11 | end) 12 | end 13 | 14 | # END 15 | end 16 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте макрос `my_abs`, который берет абсолютное значение переданного аргумента (поможет функция `abs`): 3 | 4 | ```elixir 5 | require Solution 6 | 7 | Solution.my_abs(-2) 8 | # => 2 9 | Solution.my_abs(2) 10 | # => 2 11 | Solution.my_abs(-5 * 100) 12 | # => 500 13 | Solution.my_abs(-2 - 100 + 1) 14 | # => 101 15 | ``` 16 | -------------------------------------------------------------------------------- /.credo.exs: -------------------------------------------------------------------------------- 1 | %{ 2 | configs: [ 3 | %{ 4 | name: "default", 5 | files: %{ 6 | included: ["modules/**/lib", "modules/**/test"], 7 | excluded: [] 8 | }, 9 | checks: [ 10 | {Credo.Check.Readability.ModuleDoc, false}, 11 | {Credo.Check.Refactor.CyclomaticComplexity, max_complexity: 12} 12 | ] 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /modules/20-data-types/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Elixir data types 3 | description: | 4 | 5 | In the second module we will continue to get acquainted with different data types: atoms, tuples, lists and dictionaries. If you are not familiar with functional programming, even at this stage, some of it may already seem strange. But don't be frightened, it's not hard to use all of this. 6 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте макрос `my_unless`, который повторяет семантику `unless`: 3 | 4 | ```elixir 5 | require Solution 6 | 7 | Solution.my_unless(false, do: 1 + 3) 8 | # => 4 9 | Solution.my_unless(true, do: 1 + 3) 10 | # => nil 11 | Solution.my_unless(2 == 2, do: "hello") 12 | # => nil 13 | Solution.my_unless(2 == 1, do: "world") 14 | # => "world" 15 | ``` 16 | -------------------------------------------------------------------------------- /modules/10-basics/70-interop/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "hours_to_milliseconds work" do 5 | assert Solution.hours_to_milliseconds(0) == 0 6 | assert Solution.hours_to_milliseconds(1) == 3_600_000 7 | assert Solution.hours_to_milliseconds(1.5) == 5_400_000.0 8 | assert Solution.hours_to_milliseconds(2) == 7_200_000 9 | end 10 | end 11 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def get_age(user) do 4 | {:user, _name, age} = user 5 | age 6 | end 7 | 8 | def get_names(users) do 9 | [ 10 | {:user, name1, _}, 11 | {:user, name2, _}, 12 | {:user, name3, _} 13 | ] = users 14 | 15 | [name1, name2, name3] 16 | end 17 | 18 | # END 19 | end 20 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "inc_numbers work" do 5 | assert Solution.inc_numbers(["foo", false, ["foo"]]) == [] 6 | assert Solution.inc_numbers([10, "foo", false, true, ["foo"], 1.2, %{}, 32]) == [11, 2.2, 33] 7 | assert Solution.inc_numbers([1, 2, 3, 4, 5, 6.0]) == [2, 3, 4, 5, 6, 7.0] 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | require Solution 5 | 6 | test "my_unless work" do 7 | assert Solution.my_unless(false, do: 1 + 3) == 4 8 | refute Solution.my_unless(true, do: 2) 9 | refute Solution.my_unless(2 == 2, do: "Hello") 10 | assert Solution.my_unless(1 == 2, do: "world") == "world" 11 | end 12 | end 13 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Анонимные функции 3 | tips: 4 | - > 5 | [Про объекты первого 6 | класса](https://ru.wikipedia.org/wiki/%D0%9E%D0%B1%D1%8A%D0%B5%D0%BA%D1%82_%D0%BF%D0%B5%D1%80%D0%B2%D0%BE%D0%B3%D0%BE_%D0%BA%D0%BB%D0%B0%D1%81%D1%81%D0%B0) 7 | - > 8 | [Почему используются точки при вызове анонимных 9 | функций](https://dashbit.co/blog/why-the-dot) 10 | -------------------------------------------------------------------------------- /modules/10-basics/75-sigils/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Создайте сигиль `~i` который переводит переданную в него строку в целое число и если указан модификатор `n`, который переводит переданное строку-число в отрицательное: 2 | 3 | ```elixir 4 | import Solution 5 | 6 | ~i(40) 7 | # => 40 8 | 9 | ~i(21)n 10 | # => -21 11 | ``` 12 | 13 | Для перевода строки в число воспользуйтесь функцией `to_integer` из модуля `String`. 14 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "calculate_stats work" do 5 | assert Solution.calculate_stats([]) == %{humans: 0, pets: 0} 6 | assert Solution.calculate_stats([%User{}, %User{}, %Pet{}]) == %{humans: 2, pets: 1} 7 | assert Solution.calculate_stats([%Pet{}, %Pet{}, %Pet{}]) == %{humans: 0, pets: 3} 8 | end 9 | end 10 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `join_and_upcase`, которая принимает две строки, соединяет их вместе, удаляет пробелы в начале и в конце, и переводит в верхний регистр только символы латинского алфавита. 3 | 4 | ```elixir 5 | Solution.join_and_upcase(" привет ", "world!") 6 | # => "привет WORLD!" 7 | 8 | Solution.join_and_upcase("hello ", "мир! ") 9 | # => "HELLO мир!" 10 | ``` 11 | -------------------------------------------------------------------------------- /.github/workflows/Docker.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | push: 5 | branches: 6 | - main 7 | pull_request: 8 | branches: 9 | - main 10 | 11 | jobs: 12 | main: 13 | runs-on: ubuntu-latest 14 | 15 | steps: 16 | - uses: hexlet-basics/exercises-action@release 17 | with: 18 | DOCKER_USERNAME: ${{ github.actor }} 19 | DOCKER_PASSWORD: ${{ secrets.GITHUB_TOKEN }} 20 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `generate`, которая случайно генерирует бесконечную последовательность чисел от 1 до 20 и берет `n` элементов от этой коллекции: 3 | 4 | ```elixir 5 | Solution.generate(5) 6 | # => [2, 10, 20, 12, 11] 7 | Solution.generate(2) 8 | # => [7, 14] 9 | Solution.generate(20) 10 | # => [2, 9, 18, 1, 3, 16, 1, 1, 20, 20, 9, 11, 10, 14, 10, 15, 3, 3, 10, 8] 11 | ``` 12 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/en/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Hello, World! 3 | tips: 4 | - > 5 | [repl.it](https://repl.it/languages/elixir) - write your Elixir experiments 6 | in your browser. 7 | 8 | [Phoenix](https://phoenixframework.org/) - the most popular web framework in 9 | Elixir. 10 | 11 | [Elixir: The Documentary](https://youtu.be/lxYFOM3UJzo) - the video that 12 | tells the origins of Elixir 13 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Обработка ошибок, исключения 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Exception.html) 6 | - > 7 | [Статья про 8 | исключения](https://belaycpp.com/2021/06/16/exceptions-are-just-fancy-gotos/) 9 | - > 10 | [Исключения на примере 11 | JS](https://ru.hexlet.io/courses/js_errors/lessons/exceptions/theory_unit) 12 | -------------------------------------------------------------------------------- /description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | title: | 3 | Elixir Basics 4 | 5 | header: Elixir 6 | description: | 7 | The Elixir language is quite complex. Most of its elements are more complex than they first appear. In the first module, we will look at modules and functions, basic data types and operations with them. 8 | 9 | seo_description: | 10 | SEO description... 11 | 12 | keywords: 13 | - keyword1 14 | - keyword2 15 | - keyword3 16 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте парсер, который читает текст (расширение `.txt`) и построчно читает его (разделитель `\n`). Если текст пустой, верните ошибку: 3 | 4 | ```elixir 5 | TextParser.extensions() 6 | # => [".txt"] 7 | 8 | text = "hello\nworld!" 9 | TextParser.parse(text) 10 | # => {:ok, ["hello", "world!"]} 11 | 12 | text = "" 13 | TextParser.parse(text) 14 | # => {:error, :no_text} 15 | ``` 16 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Наберите в редакторе код из задания символ в символ и нажмите «Проверить». 2 | 3 | ```elixir 4 | # Определение модуля Solution 5 | defmodule Solution do 6 | # Определение функции hello 7 | # Отступ 2 пробела 8 | def hello do 9 | # Вызов функции другого модуля 10 | # Отступ 2 пробела 11 | IO.puts("Hello, World!") # В конце не нужна точка с запятой 12 | end 13 | end 14 | ``` 15 | -------------------------------------------------------------------------------- /modules/55-processes/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Processes 3 | description: | 4 | 5 | In Elixir, all code runs inside processes. Processes are isolated from each other, run in parallel, and communicate via messaging. Processes are not the only basis for parallel operation, but they provide the basis for building distributed and fault-tolerant programs. In this module, we will look at the processes and actor model that underlie the language. 6 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `compare`, которая сравнивает два переданных *числа*: 3 | 4 | ```elixir 5 | Solution.compare(2, 3) 6 | # => {:ok, :less} 7 | Solution.compare(3, 3) 8 | # => {:ok, :equal} 9 | Solution.compare(4, 3) 10 | # => {:ok, :greater} 11 | 12 | Solution.compare("", 3) 13 | # => {:error, :not_number} 14 | Solution.compare(2, []) 15 | # => {:error, :not_number} 16 | ``` 17 | -------------------------------------------------------------------------------- /modules/55-processes/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Процессы 3 | description: | 4 | 5 | В Elixir весь код запускается внутри процессов. Процессы изолированы друг от друга, запускаются параллельно и взаимодействуют через отправку сообщений. Процессы – не единственная основа параллельной работы, но они предоставляют базу для построения распределённых и отказоустойчивых программ. В этом модуле рассмотрим процессы и акторную модель, которые лежат в основе языка. 6 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM hexletbasics/base-image:latest 2 | 3 | WORKDIR /exercises-elixir 4 | 5 | ENV PATH=/exercises-elixir/bin:$PATH 6 | 7 | # Установка зависимостей и очистка кэша 8 | RUN apt-get update && \ 9 | apt-get install -yqq erlang elixir && \ 10 | rm -rf /var/lib/apt/lists/* 11 | 12 | COPY mix.* ./ 13 | 14 | RUN mix local.hex --force && \ 15 | mix local.rebar --force && \ 16 | mix hex.info && \ 17 | mix deps.get 18 | 19 | COPY . . 20 | -------------------------------------------------------------------------------- /modules/10-basics/30-strings/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "join and upcase works" do 5 | res = Solution.join_and_upcase(" привет ", "world!") 6 | assert res == "привет WORLD!" 7 | 8 | res = Solution.join_and_upcase("hello ", "мир! ") 9 | assert res == "HELLO мир!" 10 | 11 | res = Solution.join_and_upcase(" hello ", "world! ") 12 | assert res == "HELLO WORLD!" 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /modules/35-fp/10-recursion/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "range test" do 6 | assert [1, 2, 3, 4, 5] == range(1, 5) 7 | assert [4, 5, 6, 7, 8, 9, 10] == range(4, 10) 8 | assert [-2, -1, 0, 1, 2, 3] == range(-2, 3) 9 | assert [2] == range(2, 2) 10 | assert [] == range(3, 2) 11 | assert [] == range(3, -2) 12 | assert [-3, -2] == range(-3, -2) 13 | end 14 | end 15 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Супервизоры 3 | tips: 4 | - > 5 | [Официальная документация 6 | Supervisor](https://hexdocs.pm/elixir/Supervisor.html) 7 | - > 8 | [Про дерево супервизии в 9 | Erlang](https://erlang.org/documentation/doc-4.9.1/doc/design_principles/sup_princ.html) 10 | - > 11 | [Пример модуля 12 | супервизора](https://hexdocs.pm/elixir/Supervisor.html#module-module-based-supervisors) 13 | -------------------------------------------------------------------------------- /modules/60-macros/20-quoting/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Знакомство с quote и unquote 3 | tips: 4 | - > 5 | [Официальная 6 | документация](https://hexdocs.pm/elixir/Kernel.SpecialForms.html#quote/2) 7 | - > 8 | [Про 9 | AST](https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE) 10 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `generate_pets`, в которую передается количество питомцев, список которых нужно сгенерировать с именем `Barkley x`, где `x` - идентификатор питомца (отсчет идет с нуля). Модуль `Pet` описан заранее. Опишите спецификацию созданной функции: 3 | 4 | ```elixir 5 | Solution.generate_pets(2) 6 | # => [%Pet{name: "Barkley 0"}, %Pet{name: "Barkley 1"}] 7 | 8 | Solution.generate_pets(-2) 9 | # => [] 10 | ``` 11 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Pet do 2 | @type pet :: %__MODULE__{name: String.t()} 3 | 4 | defstruct name: "Barkley" 5 | end 6 | 7 | defmodule Solution do 8 | # BEGIN 9 | @spec generate_pets(integer()) :: list(Pet.t()) | list() 10 | def generate_pets(amount) when amount > 0 do 11 | 0..(amount - 1) |> Enum.map(fn id -> %Pet{name: "Barkley #{id}"} end) 12 | end 13 | 14 | def generate_pets(_), do: [] 15 | 16 | # END 17 | end 18 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Связь процессов 3 | tips: 4 | - | 5 | [Отказоустойчивость в Elixir](https://www.youtube.com/watch?v=mkGq1WoEvI4) 6 | - | 7 | [Официальная документация](https://hexdocs.pm/elixir/Process.html#exit/2) 8 | - > 9 | [Документация по настройке 10 | процессов](https://www.erlang.org/doc/man/erlang.html#process_flag-2) 11 | - | 12 | [Документация по супервизорам](https://hexdocs.pm/elixir/Supervisor.html) 13 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def keys_sum(map, key1, key2) do 4 | Map.get(map, key1, 0) + Map.get(map, key2, 0) 5 | end 6 | 7 | def keys_product(map, key1, key2) do 8 | Map.get(map, key1, 1) * Map.get(map, key2, 1) 9 | end 10 | 11 | def copy_key(from_map, to_map, key, default_value) do 12 | value = Map.get(from_map, key, default_value) 13 | Map.put(to_map, key, value) 14 | end 15 | 16 | # END 17 | end 18 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию `inc_numbers`, которая берёт из переданного списка значения, являющиеся числами `is_number` и возвращает список этих чисел, увеличив каждое число на единицу. 2 | Примеры: 3 | 4 | ```elixir 5 | Solution.inc_numbers(["foo", false, ["foo"]]) 6 | # => [] 7 | Solution.inc_numbers([10, "foo", false, true, ["foo"], 1.2, %{}, 32]) 8 | # => [11, 2.2, 33] 9 | Solution.inc_numbers([1, 2, 3, 4, 5, 6.0]) 10 | # => [2, 3, 4, 5, 6, 7.0] 11 | ``` 12 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "my_div work" do 5 | assert_raise(ArgumentError, "Divide 10 by zero is prohibited!", fn -> 6 | Solution.my_div(10, 0) 7 | end) 8 | 9 | assert_raise(ArgumentError, "Divide 128 by zero is prohibited!", fn -> 10 | Solution.my_div(128, 0) 11 | end) 12 | 13 | assert Solution.my_div(128, 2) == 64 14 | assert Solution.my_div(0, 2) == 0 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def compare(first, _) when not is_integer(first), do: {:error, :not_number} 4 | def compare(_, second) when not is_integer(second), do: {:error, :not_number} 5 | 6 | def compare(first, second) do 7 | cond do 8 | first == second -> {:ok, :equal} 9 | first < second -> {:ok, :less} 10 | first > second -> {:ok, :greater} 11 | end 12 | end 13 | 14 | # END 15 | end 16 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Привет, Мир! 3 | tips: 4 | - > 5 | [repl.it](https://repl.it/languages/elixir) - здесь вы можете 6 | экспериментировать с кодом на Elixir. 7 | - | 8 | [Официальный сайт](https://elixir-lang.org/) 9 | - | 10 | [Phoenix, веб-фреймворк](https://phoenixframework.org/) 11 | - | 12 | [Исходный код языка](https://github.com/elixir-lang/elixir) 13 | - | 14 | [Официальный форум, посвященный языку](https://elixirforum.com/) 15 | -------------------------------------------------------------------------------- /modules/35-fp/description.en.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Functional Programming Basics 3 | description: | 4 | 5 | Elixir is a bright representative of the family of functional languages. It's time to learn what functional programming is, what elements it consists of, and how it differs from other programming paradigms. 6 | 7 | We have already been introduced to one of the most important elements of FP - pattern matching. Now let us consider the other elements: immutability, recursion, higher-order functions, and anonymous functions. 8 | -------------------------------------------------------------------------------- /modules/35-fp/description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Основы функционального программирования 3 | description: | 4 | 5 | Эликсир — яркий представитель семейства функциональных языков. Пришло время узнать, что такое функциональное программирование, из каких элементов оно состоит, и чем отличается от других парадигм программирования. 6 | 7 | Мы уже познакомились с одним из важнейших элементов ФП — сопоставлением с образцом. Теперь рассмотрим другие элементы: иммутабельность, рекурсию, функции высшего порядка и анонимные функции. 8 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `calculate_stats`, которая подсчитывает, сколько в списке людей и питомцев: 3 | 4 | ```elixir 5 | users_and_pets = [%User{}, %User{}, %Pet{}] 6 | 7 | Solution.calculate_stats(users_and_pets) 8 | # => %{humans: 2, pets: 1} 9 | 10 | Solution.calculate_stats([]) 11 | # => %{humans: 0, pets: 0} 12 | 13 | only_pets = [%Pet{}, %Pet{}, %Pet{}] 14 | # => %{humans: 0, pets: 3} 15 | ``` 16 | 17 | Обратите внимание, что структуры в модуле заранее определены. 18 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Изучите документацию для модуля *String*. Найдите функции для удаления пробельных символов в начале и конце строки, для приведения строки к нижнему регистру, и для дублирования строки несколько раз. 3 | 4 | Нужно собрать эти три функции в цепочку, таким образом, чтобы строка на входе была очищена от лишних пробелов, приведена в нижний регистр и продублирована указанное количество раз: 5 | 6 | ```elixir 7 | Solution.process(" My Cool String ", 2) # "my cool stringmy cool string" 8 | ``` 9 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def filter_by_age(users, age) do 4 | filter_by_age(users, age, []) 5 | end 6 | 7 | defp filter_by_age([], _age, acc), do: Enum.reverse(acc) 8 | 9 | defp filter_by_age([user | users], age, acc) do 10 | {:user, _, _, user_age} = user 11 | 12 | if user_age > age do 13 | filter_by_age(users, age, [user | acc]) 14 | else 15 | filter_by_age(users, age, acc) 16 | end 17 | end 18 | 19 | # END 20 | end 21 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def single_win?(a_win, b_win) do 4 | cond do 5 | a_win and not b_win -> true 6 | b_win and not a_win -> true 7 | true -> false 8 | end 9 | end 10 | 11 | def double_win?(a_win, b_win, c_win) do 12 | cond do 13 | a_win and b_win and not c_win -> :ab 14 | a_win and c_win and not b_win -> :ac 15 | b_win and c_win and not a_win -> :bc 16 | true -> false 17 | end 18 | end 19 | 20 | # END 21 | end 22 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `do_math(a, b)`, которая принимает два числа, и выводит на экран: 3 | 4 | * результат деления суммы первого и второго числа на второе число 5 | * результат целочисленного деления первого числа на второе 6 | * остаток от деления второго числа на первое 7 | 8 | Каждый результат выводится на отдельной строке. 9 | 10 | ```elixir 11 | Solution.do_math(10, 10) 12 | # => 2.0 13 | # => 1 14 | # => 0 15 | 16 | Solution.do_math(42, 3) 17 | # => 15.0 18 | # => 14 19 | # => 3 20 | ``` 21 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Даны два *целых* числа. Создайте простой калькулятор, который поддерживает следующие операции: `сложение`, `вычитание`, `деление`, `умножение`. 3 | 4 | ```elixir 5 | Solution.calculate("+", 2, 3) # => 5 6 | Solution.calculate("+", 0, -3) # => -3 7 | Solution.calculate("-", 2, 3) # => -1 8 | Solution.calculate("-", 0, 3) # => -3 9 | Solution.calculate("/", 4, 4) # => 1.0 10 | Solution.calculate("/", 3, 2) # => 1.5 11 | Solution.calculate("*", 2, 2) # => 4 12 | Solution.calculate("*", 0, 2) # => 0 13 | ``` 14 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | defmodule Exercise do 5 | require Solution 6 | 7 | Solution.prohibit_words(["hello", "world", "foo"]) 8 | end 9 | 10 | test "prohibit_words work" do 11 | assert Exercise.forbidden?("hello") 12 | assert Exercise.forbidden?("world") 13 | assert Exercise.forbidden?("foo") 14 | refute Exercise.forbidden?("baz") 15 | refute Exercise.forbidden?(2) 16 | refute Exercise.forbidden?(%{hello: :world}) 17 | end 18 | end 19 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def join_game(user) do 4 | case user do 5 | {:user, _name, _age, :admin} -> :ok 6 | {:user, _name, _age, :moderator} -> :ok 7 | {:user, _name, age, _role} when age >= 18 -> :ok 8 | _ -> :error 9 | end 10 | end 11 | 12 | def move_allowed?(current_color, figure) do 13 | case figure do 14 | {:pawn, ^current_color} -> true 15 | {:rock, ^current_color} -> true 16 | _ -> false 17 | end 18 | end 19 | 20 | # END 21 | end 22 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def validate(str) do 4 | with {:not_binary, true} <- {:not_binary, is_binary(str)}, 5 | {:too_long, true} <- {:too_long, String.length(str) <= 8}, 6 | {:too_short, true} <- {:too_short, 2 <= String.length(str)} do 7 | {:ok, str} 8 | else 9 | {:not_binary, _} -> {:error, :not_binary} 10 | {:too_long, _} -> {:error, :too_long} 11 | {:too_short, _} -> {:error, :too_short} 12 | end 13 | end 14 | 15 | # END 16 | end 17 | -------------------------------------------------------------------------------- /modules/40-collections/30-reduce/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `max_delta`, которая должна принимать два списка чисел и вычислять максимальную разницу (абсолютное значение разницы) между соответствующими парами элементов. Примеры: 3 | 4 | ```elixir 5 | Solution.max_delta([], []) 6 | # => 0 7 | Solution.max_delta([10, -15, 35], [2, -12, 42]) 8 | # => 8 9 | Solution.max_delta([-5], [-15]) 10 | # => 10 11 | ``` 12 | 13 | Вам пригодятся функции `abs` и `max`: 14 | 15 | ```elixir 16 | abs(42) # => 42 17 | abs(-13) # => 13 18 | max(1, 5) # => 5 19 | ``` 20 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Определите три структуры `Human`, `Dog` и `Cat` с полем `name`. Затем определите функцию `say_something` для протокола `Teller` для каждого из модулей, которая возвращает строку в зависимости от типа: 3 | - Для Human `Hello, world!` 4 | - Для Cat `Meow, world!` 5 | - Для Dog `Bark, world!` 6 | 7 | ```elixir 8 | Teller.say_something(%Human{name: "John"}) # => "Hello, world!" 9 | Teller.say_something(%Dog{name: "Barkinson"}) # => "Bark, world!" 10 | Teller.say_something(%Cat{name: "Meowington"}) # => "Meow, world!" 11 | ``` 12 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "validate work" do 5 | test "with valid data" do 6 | assert Solution.validate("some") == {:ok, "some"} 7 | assert Solution.validate("hello!!") == {:ok, "hello!!"} 8 | end 9 | 10 | test "with invalid data" do 11 | assert Solution.validate(1) == {:error, :not_binary} 12 | assert Solution.validate("a") == {:error, :too_short} 13 | assert Solution.validate("hello, world!") == {:error, :too_long} 14 | end 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "zip realization" do 5 | assert Solution.zip([], []) == [] 6 | assert Solution.zip([1, 2], [3, 4]) == [[1, 3], [2, 4]] 7 | assert Solution.zip([1, 2], []) == [[1, nil], [2, nil]] 8 | assert Solution.zip([], [3, 4]) == [[nil, 3], [nil, 4]] 9 | assert Solution.zip([1, 2], [3]) == [[1, 3], [2, nil]] 10 | assert Solution.zip([1], [3, 4]) == [[1, 3], [nil, 4]] 11 | assert Solution.zip([1, 2, 3, 4], [5, 6, 7, 8]) == [[1, 5], [2, 6], [3, 7], [4, 8]] 12 | end 13 | end 14 | -------------------------------------------------------------------------------- /modules/45-structs/30-behaviour/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Parser do 2 | @doc """ 3 | Parses a string. 4 | """ 5 | @callback parse(String.t()) :: {:ok, any} | {:error, atom} 6 | 7 | @doc """ 8 | Lists all supported file extensions. 9 | """ 10 | @callback extensions() :: [String.t()] 11 | end 12 | 13 | defmodule TextParser do 14 | @behaviour Parser 15 | 16 | # BEGIN 17 | @impl Parser 18 | def parse(""), do: {:error, :no_text} 19 | def parse(text), do: {:ok, String.split(text, "\n")} 20 | 21 | @impl Parser 22 | def extensions(), do: [".txt"] 23 | # END 24 | end 25 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Продолжим упражнение из прошлого модуля, теперь опишите структуру `Robot` с явным указанием протокола `Teller` и реализуйте протокол для `Any` который возвращает строку `World!`: 3 | 4 | ```elixir 5 | Teller.say_something(%Human{name: "John"}) # => "Hello, world!" 6 | Teller.say_something(%Dog{name: "Barkinson"}) # => "Bark, world!" 7 | Teller.say_something(%Cat{name: "Meowington"}) # => "Meow, world!" 8 | Teller.say_something(%Robot{name: "Roberto"}) # => "World!" 9 | ``` 10 | 11 | Реализация для `Any` должна быть описана раньше, чем структуры. 12 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def calculate(pid) do 4 | receive do 5 | {operation, args} -> 6 | send(pid, {:ok, exec(operation, args)}) 7 | calculate(pid) 8 | 9 | {:exit} -> 10 | send(pid, {:ok, :exited}) 11 | end 12 | end 13 | 14 | defp exec(:+, [first, second]) do 15 | first + second 16 | end 17 | 18 | defp exec(:-, [first, second]) do 19 | first - second 20 | end 21 | 22 | defp exec(:*, [first, second]) do 23 | first * second 24 | end 25 | 26 | # END 27 | end 28 | -------------------------------------------------------------------------------- /modules/50-errors/30-with-operator/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `validate`, которая проверяет переданный аргумент на следующие условия: 3 | - аргумент является строкой 4 | - длина строки меньше или равна 8 5 | - длина строки больше или равна 2 6 | 7 | Примеры работы функции: 8 | 9 | ```elixir 10 | Solution.validate("some") 11 | # => {:ok, "some"} 12 | Solution.validate("hello!!") 13 | # => {:ok, "hello!!"} 14 | 15 | Solution.validate(1) 16 | # => {:error, :not_binary} 17 | Solution.validate("a") 18 | # => {:error, :too_short} 19 | Solution.validate("hello, world!") 20 | # => {:error, :too_long} 21 | ``` 22 | -------------------------------------------------------------------------------- /modules/60-macros/10-macros-intro/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Знакомство с макросами 3 | tips: 4 | - | 5 | [Официальная документация](https://hexdocs.pm/elixir/Macro.html) 6 | - > 7 | [Про 8 | DSL](https://ru.wikipedia.org/wiki/%D0%9F%D1%80%D0%B5%D0%B4%D0%BC%D0%B5%D1%82%D0%BD%D0%BE-%D0%BE%D1%80%D0%B8%D0%B5%D0%BD%D1%82%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%BD%D1%8B%D0%B9_%D1%8F%D0%B7%D1%8B%D0%BA) 9 | - > 10 | [Про 11 | метапрограммирование](https://ru.wikipedia.org/wiki/%D0%9C%D0%B5%D1%82%D0%B0%D0%BF%D1%80%D0%BE%D0%B3%D1%80%D0%B0%D0%BC%D0%BC%D0%B8%D1%80%D0%BE%D0%B2%D0%B0%D0%BD%D0%B8%D0%B5) 12 | -------------------------------------------------------------------------------- /modules/40-collections/10-map/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | Реализуйте функцию `zip`, которая группирует элементы переданных векторов в подвектора. Если вектора отличаются длиной, то вместо сгруппированного элемента оставьте `nil`. Для обращения к элементу списка по индексу используйте `Enum.at`. 2 | Примеры: 3 | 4 | ```elixir 5 | Solution.zip([], []) 6 | # => [] 7 | Solution.zip([1, 2, 3, 4], [5, 6, 7, 8]) 8 | # => [[1, 5], [2, 6], [3, 7], [4, 8]] 9 | Solution.zip([1, 2], [3, 4]) 10 | # => [[1, 3], [2, 4]] 11 | Solution.zip([1, 2], [3]) 12 | # => [[1, 3], [2, nil]] 13 | Solution.zip([1], [3, 4]) 14 | # => [[1, 3], [nil, 4]] 15 | ``` 16 | -------------------------------------------------------------------------------- /modules/45-structs/20-typespecs/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "generate_pets work" do 5 | test "with valid input" do 6 | pets = Solution.generate_pets(10) 7 | 8 | assert is_list(pets) 9 | 10 | Enum.each(Enum.with_index(pets), fn {pet, index} -> 11 | assert is_struct(pet, Pet) 12 | assert pet.name == "Barkley #{index}" 13 | end) 14 | end 15 | 16 | test "with invalid input" do 17 | pets = Solution.generate_pets(-20) 18 | 19 | assert is_list(pets) 20 | assert Enum.empty?(pets) 21 | end 22 | end 23 | end 24 | -------------------------------------------------------------------------------- /modules/50-errors/20-tuple-errors-processing/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "compare work" do 5 | test "with valid data" do 6 | assert Solution.compare(1, 1) == {:ok, :equal} 7 | assert Solution.compare(2, 1) == {:ok, :greater} 8 | assert Solution.compare(0, 1) == {:ok, :less} 9 | end 10 | 11 | test "with invalid data" do 12 | assert Solution.compare("", 1) == {:error, :not_number} 13 | assert Solution.compare(1, []) == {:error, :not_number} 14 | assert Solution.compare(%{}, []) == {:error, :not_number} 15 | end 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "encode/decode" do 6 | assert encode(~c"Hello", 10) |> decode(10) == ~c"Hello" 7 | assert encode(~c"12345", 1) == ~c"23456" 8 | assert decode(~c"12345", 1) == ~c"01234" 9 | assert encode(~c"abcdef", 2) == ~c"cdefgh" 10 | assert decode(~c"abcdef", 2) == ~c"_`abcd" 11 | end 12 | 13 | test "encode/decode with cyrillic symbols" do 14 | assert encode(~c"Привет", 10) |> decode(10) == ~c"Привет" 15 | assert encode(~c"Привет мир", 500) |> decode(500) == ~c"Привет мир" 16 | end 17 | end 18 | -------------------------------------------------------------------------------- /modules/60-macros/30-new-functionality/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте макрос `prohibit_words`, генерирующий функцию `forbidden?`, в который передается список запрещенных слов и проверяется, запрещено ли слово, переданное в функцию `forbidden?`. Если передано не слово, то функция возвращает `false`: 3 | 4 | ```elixir 5 | defmodule Exercise 6 | require Solution 7 | 8 | Solution.prohibit_words(["hello", "world", "foo"]) 9 | end 10 | 11 | Exercise.forbidden?("hello") 12 | # => true 13 | Exercise.forbidden?("test") 14 | # => false 15 | Exercise.forbidden?(1) 16 | # => false 17 | Exercise.forbidden?(%{hello: :world}) 18 | # => false 19 | ``` 20 | -------------------------------------------------------------------------------- /mix.exs: -------------------------------------------------------------------------------- 1 | defmodule ExercisesElixir.MixProject do 2 | use Mix.Project 3 | 4 | def project do 5 | [ 6 | app: :exercises_elixir, 7 | version: "0.1.0", 8 | elixir: "~> 1.9", 9 | start_permanent: Mix.env() == :prod, 10 | deps: deps() 11 | ] 12 | end 13 | 14 | # Run "mix help compile.app" to learn about applications. 15 | def application do 16 | [ 17 | extra_applications: [:logger] 18 | ] 19 | end 20 | 21 | # Run "mix help deps" to learn about dependencies. 22 | defp deps do 23 | [ 24 | {:credo, "~> 1.7.11", only: [:dev, :test], runtime: false} 25 | ] 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defprotocol Teller do 2 | @spec say_something(any()) :: String.t() 3 | def say_something(someone) 4 | end 5 | 6 | # BEGIN 7 | defmodule Human do 8 | defstruct [:name] 9 | end 10 | 11 | defmodule Dog do 12 | defstruct [:name] 13 | end 14 | 15 | defmodule Cat do 16 | defstruct [:name] 17 | end 18 | 19 | defimpl Teller, for: Human do 20 | def say_something(_), do: "Hello, world!" 21 | end 22 | 23 | defimpl Teller, for: Dog do 24 | def say_something(_), do: "Bark, world!" 25 | end 26 | 27 | defimpl Teller, for: Cat do 28 | def say_something(_), do: "Meow, world!" 29 | end 30 | 31 | # END 32 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Даты и время 3 | tips: 4 | - | 5 | [Официальная документация Date](https://hexdocs.pm/elixir/Date.html) 6 | - | 7 | [Официальная документация DateTime](https://hexdocs.pm/elixir/DateTime.html) 8 | - > 9 | [Официальная документация 10 | NaiveDateTime](https://hexdocs.pm/elixir/NaiveDateTime.html) 11 | - | 12 | [Официальная документация Time](https://hexdocs.pm/elixir/Time.html) 13 | - > 14 | [Про базу знаний о часовых поясах 15 | tzdata](https://habr.com/ru/articles/130401/) 16 | - | 17 | [Библиотека tzdata для Elixir](https://github.com/lau/tzdata) 18 | -------------------------------------------------------------------------------- /modules/50-errors/10-errors-handling/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `my_div`, которая выбрасывает исключение `ArgumentError` с сообщением `Divide x by zero is prohibited!`, где `x` - первый переданный аргумент. Для деления с округлением воспользуйтесь `Integer.floor_div`: 3 | 4 | ```elixir 5 | Solution.my_div(128, 2) 6 | # => 64 7 | 8 | Solution.my_div(128, 0) 9 | # => ** (ArgumentError) Divide 128 by zero is prohibited! 10 | # => iex:142: Solution.my_div/2 11 | # => iex:149: (file) 12 | 13 | Solution.my_div(10, 0) 14 | # => ** (ArgumentError) Divide 10 by zero is prohibited! 15 | # => iex:142: Solution.my_div/2 16 | # => iex:149: (file) 17 | ``` 18 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте макрос `with_logging`, который принимает функцию, логгирует результат выполнения и возвращает результат. Примеры использования: 3 | 4 | ```elixir 5 | defmodule Exercise 6 | require Solution 7 | 8 | def run_fn(function) do 9 | Solution.with_logging do 10 | function 11 | end 12 | end 13 | end 14 | 15 | Exercise.run_fn(fn -> 1 + 5 end) 16 | # => Started execution... 17 | # => Execution result is: 6 18 | # => 6 19 | 20 | 21 | Exercise.run_fn(fn -> %{hello: :world} end) 22 | # => Started execution... 23 | # => Execution result is: %{hello: :world} 24 | # => %{hello: :world} 25 | ``` 26 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `any?(a, b, c, d)`, которая принимает четыре булевых аргумента, и возвращает `true`, если среди аргументов есть `true`. 3 | 4 | Реализуйте функцию `truthy?(a, b)`, которая принимает два аргумента любого типа, и если первый аргумент truthy, то функция возвращает второй аргумент. 5 | 6 | ```elixir 7 | Solution.any?(false, false, false, false) # => false 8 | Solution.any?(true, false, false, false) # => true 9 | Solution.any?(false, true, false, true) # => true 10 | 11 | Solution.truthy?(true, 42) # => 42 12 | Solution.truthy?("hello", false) # => false 13 | Solution.truthy?("", nil) # => nil 14 | ``` 15 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "foobar supervisor work" do 5 | result = Solution.supervise_foobar(1) 6 | 7 | assert Enum.count(String.split(result)) == 47 8 | 9 | assert result == 10 | "Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar" 11 | 12 | assert Solution.supervise_foobar(101) == "" 13 | assert Solution.supervise_foobar(-123) == "" 14 | assert Solution.supervise_foobar(0) == "" 15 | end 16 | end 17 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `get_age(user)`, которая принимает объект `user`, представленный в виде кортежа `{:user, name, age}`, и возвращает возраст (age). 3 | 4 | Реализуйте функцию `get_names(users)`, которая принимает список из трёх объектов `user`, представленных такими же кортежами, и возвращает список из трёх имен. 5 | 6 | ```elixir 7 | bob = {:user, "Bob", 42} 8 | helen = {:user, "Helen", 20} 9 | kate = {:user, "Kate", 22} 10 | 11 | Solution.get_age(bob) # => 42 12 | Solution.get_age(helen) # => 20 13 | Solution.get_age(kate) # => 22 14 | 15 | Solution.get_names([bob, helen, kate]) 16 | # => ["Bob", "Helen", "Kate"] 17 | ``` 18 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import ExUnit.CaptureIO 4 | 5 | test "do math" do 6 | assert call_solution(10, 10) == {2.0, 1, 0} 7 | assert call_solution(15, 5) == {4.0, 3, 5} 8 | assert call_solution(42, 3) == {15.0, 14, 3} 9 | assert call_solution(20, 40) == {1.5, 0, 0} 10 | assert call_solution(20, 8) == {3.5, 2, 8} 11 | end 12 | 13 | defp call_solution(a, b) do 14 | [a, b, c] = 15 | capture_io(fn -> Solution.do_math(a, b) end) 16 | |> String.trim() 17 | |> String.split() 18 | 19 | {String.to_float(a), String.to_integer(b), String.to_integer(c)} 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /modules/45-structs/40-protocols/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "teller protocol work" do 5 | test "for human" do 6 | assert Teller.impl_for(%Human{}) == Teller.Human 7 | assert Teller.say_something(%Human{name: "John"}) == "Hello, world!" 8 | end 9 | 10 | test "for dog" do 11 | assert Teller.impl_for(%Dog{}) == Teller.Dog 12 | assert Teller.say_something(%Dog{name: "Barkinson"}) == "Bark, world!" 13 | end 14 | 15 | test "for cat" do 16 | assert Teller.impl_for(%Cat{}) == Teller.Cat 17 | assert Teller.say_something(%Cat{name: "Meowington"}) == "Meow, world!" 18 | end 19 | end 20 | end 21 | -------------------------------------------------------------------------------- /modules/55-processes/10-processes-intro/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Знакомство с процессами 3 | tips: 4 | - | 5 | [Про green threads](https://ru.wikipedia.org/wiki/Green_threads) 6 | - | 7 | [Про ООП в Erlang](https://www.infoq.com/interviews/johnson-armstrong-oop/) 8 | - | 9 | [Видео про BEAM и процессы](https://www.youtube.com/watch?v=JvBT4XBdoUE) 10 | - | 11 | [Официальная документация](https://hexdocs.pm/elixir/Process.html) 12 | - > 13 | [Про вытесняющую 14 | многозадачность](https://ru.wikipedia.org/wiki/%D0%92%D1%8B%D1%82%D0%B5%D1%81%D0%BD%D1%8F%D1%8E%D1%89%D0%B0%D1%8F_%D0%BC%D0%BD%D0%BE%D0%B3%D0%BE%D0%B7%D0%B0%D0%B4%D0%B0%D1%87%D0%BD%D0%BE%D1%81%D1%82%D1%8C) 15 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # The directory Mix will write compiled artifacts to. 2 | _build 3 | 4 | # If you run "mix test --cover", coverage assets end up here. 5 | /cover/ 6 | 7 | # The directory Mix downloads your dependencies sources to. 8 | /deps/ 9 | 10 | # Where third-party dependencies like ExDoc output generated docs. 11 | /doc/ 12 | 13 | # Ignore .fetch files in case you like to edit your project deps locally. 14 | /.fetch 15 | 16 | # If the VM crashes, it generates a dump, let's ignore it too. 17 | erl_crash.dump 18 | 19 | # Also ignore archive artifacts (built via "mix archive.build"). 20 | *.ez 21 | 22 | # Ignore package tarball (built via "mix hex.build"). 23 | exercises_elixir-*.tar 24 | .elixir_ls 25 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | В функции `filter_adults/1` критерием фильтрации является возраст пользователя. Но этот возраст явно указан в коде функции. Нужно реализовать функцию `filter_by_age/2`, которая принимает список пользователей и возраст. 3 | 4 | ```elixir 5 | users = [ 6 | {:user, 1, "Bob", 23}, 7 | {:user, 2, "Helen", 20}, 8 | {:user, 3, "Bill", 15}, 9 | {:user, 4, "Kate", 14} 10 | ] 11 | 12 | Solution.filter_by_age(users, 16) # [{:user, 1, "Bob", 23}, {:user, 2, "Helen", 20}] 13 | Solution.filter_by_age(users, 14) # [{:user, 1, "Bob", 23}, {:user, 2, "Helen", 20}, {:user, 3, "Bill", 15}] 14 | Solution.filter_by_age(users, 22) # [{:user, 1, "Bob", 23}] 15 | ``` 16 | -------------------------------------------------------------------------------- /modules/45-structs/10-struct-intro/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule User do 2 | defstruct name: "John" 3 | end 4 | 5 | defmodule Pet do 6 | defstruct name: "Barkley" 7 | end 8 | 9 | defmodule Solution do 10 | # BEGIN 11 | @default_stats %{humans: 0, pets: 0} 12 | 13 | def calculate_stats([]), do: @default_stats 14 | 15 | def calculate_stats(humans_and_pets) do 16 | Enum.reduce(humans_and_pets, @default_stats, &stat_member/2) 17 | end 18 | 19 | defp stat_member(%User{}, acc) do 20 | Map.update(acc, :humans, 0, fn curr -> curr + 1 end) 21 | end 22 | 23 | defp stat_member(%Pet{}, acc) do 24 | Map.update(acc, :pets, 0, fn curr -> curr + 1 end) 25 | end 26 | 27 | # END 28 | end 29 | -------------------------------------------------------------------------------- /modules/30-flow/10-pattern-matching/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | @bob {:user, "Bob", 42} 6 | @bill {:user, "Bill", 12} 7 | @helen {:user, "Helen", 20} 8 | @kate {:user, "Kate", 22} 9 | 10 | test "get_age test" do 11 | assert 42 == get_age(@bob) 12 | assert 12 == get_age(@bill) 13 | assert 20 == get_age(@helen) 14 | assert 22 == get_age(@kate) 15 | end 16 | 17 | test "get_names test" do 18 | assert ["Bob", "Helen", "Kate"] == get_names([@bob, @helen, @kate]) 19 | assert ["Helen", "Bill", "Kate"] == get_names([@helen, @bill, @kate]) 20 | assert ["Kate", "Bill", "Bob"] == get_names([@kate, @bill, @bob]) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /modules/40-collections/50-stream/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "generate work" do 5 | count = 5 6 | numbers = Solution.generate(count) 7 | 8 | assert validate_result(numbers, count) 9 | 10 | count = 2 11 | numbers = Solution.generate(count) 12 | 13 | assert validate_result(numbers, count) 14 | 15 | count = 30 16 | numbers = Solution.generate(count) 17 | 18 | assert validate_result(numbers, count) 19 | end 20 | 21 | defp validate_result(result, count) do 22 | elements_validation = Enum.map(result, fn x -> is_number(x) && x in 1..20 end) |> Enum.all?() 23 | 24 | elements_validation && length(result) == count 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | Elixir is a dynamic, functional programming language designed for building scalable and easily maintainable applications. 3 | 4 | Elixir was created by José Valim and appeared for the first time in 2011. It steadily gained popularity since then. Today some big companies use Elixir in production, including Brex, Heroku, Discord, Pinterest, and others. 5 | 6 | It runs on top of the Erlang virtual machine BEAM and inherits all the goodies of Erlang OTP. It's famous for its unique features for creating reliable distributed systems and extensively used in real-time embedded systems and apps: messengers, online games, etc. 7 | 8 | Elixir is a very pragmatic language that is easy to learn. Have fun! 9 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "calculator process work" do 5 | parent = self() 6 | calculator = spawn(fn -> Solution.calculate(parent) end) 7 | 8 | send(calculator, {:+, [2, 5]}) 9 | assert_receive({:ok, 7}) 10 | assert Process.alive?(calculator) 11 | 12 | send(calculator, {:*, [2, 5]}) 13 | assert_receive({:ok, 10}) 14 | assert Process.alive?(calculator) 15 | 16 | send(calculator, {:-, [2, 5]}) 17 | assert_receive({:ok, -3}) 18 | assert Process.alive?(calculator) 19 | 20 | send(calculator, {:exit}) 21 | assert_receive({:ok, :exited}) 22 | refute Process.alive?(calculator) 23 | end 24 | end 25 | -------------------------------------------------------------------------------- /description.ru.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | title: 'Elixir (Эликсир): курс программирования на языке Elixir' 4 | 5 | header: Elixir 6 | description: | 7 | Эликсир — язык программирования, работающий поверх Erlang. Как Erlang, это — функциональный язык со строгими вычислениями, однократным присвоением и динамической типизацией, созданный, чтобы поддерживать распределенные, отказоустойчивые, безостановочные приложения с горячей заменой кода 8 | 9 | seo_description: | 10 | Эликсир — язык программирования, работающий поверх Erlang. Как Erlang, Elixir это — функциональный язык со строгими вычислениями, созданный, чтобы поддерживать распределенные, отказоустойчивые приложения 11 | 12 | keywords: 13 | - Элексир 14 | - elixir 15 | - функциональный язык 16 | -------------------------------------------------------------------------------- /modules/10-basics/50-booleans/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "any?" do 5 | assert false == Solution.any?(false, false, false, false) 6 | assert true == Solution.any?(true, false, false, false) 7 | assert true == Solution.any?(false, true, false, false) 8 | assert true == Solution.any?(false, false, true, false) 9 | assert true == Solution.any?(false, false, false, true) 10 | assert true == Solution.any?(false, true, false, true) 11 | end 12 | 13 | test "truthy?" do 14 | assert 42 == Solution.truthy?(true, 42) 15 | assert [42] == Solution.truthy?(1, [42]) 16 | assert false == Solution.truthy?("hello", false) 17 | assert nil == Solution.truthy?("", nil) 18 | end 19 | end 20 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | def distance({:point, x1, y1}, {:point, x2, y2}) do 3 | x_dist = abs(x1 - x2) 4 | y_dist = abs(y1 - y2) 5 | :math.sqrt(:math.pow(x_dist, 2) + :math.pow(y_dist, 2)) 6 | end 7 | 8 | # BEGIN 9 | def point_inside_circle?(point, circle) do 10 | {:circle, center, radius} = circle 11 | distance(point, center) <= radius 12 | end 13 | 14 | def point_inside_rect?(point, rect) do 15 | {:point, x, y} = point 16 | {:rect, left_top, right_bottom} = rect 17 | {:point, left_x, top_y} = left_top 18 | {:point, right_x, bottom_y} = right_bottom 19 | x >= left_x and x <= right_x and y <= top_y and y >= bottom_y 20 | end 21 | 22 | # END 23 | end 24 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "get_values test" do 6 | assert {1, 2} = get_values(%{a: 1, b: 2}) 7 | assert {:ok, 42} = get_values(%{a: :ok, b: 42, c: true}) 8 | end 9 | 10 | test "get_values invalid input test" do 11 | assert_raise MatchError, fn -> 12 | get_values(%{}) 13 | end 14 | end 15 | 16 | test "get_value_by_key test" do 17 | assert 42 = get_value_by_key(%{answer: 42}, :answer) 18 | assert "6 * 7" = get_value_by_key(%{question: "6 * 7"}, :question) 19 | end 20 | 21 | test "get_value_by_key invalid input test" do 22 | assert_raise MatchError, fn -> 23 | get_value_by_key(%{a: 1}, :b) 24 | end 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "single_win? test" do 6 | assert single_win?(true, false) 7 | assert single_win?(false, true) 8 | assert not single_win?(true, true) 9 | assert not single_win?(false, false) 10 | end 11 | 12 | test "double_win? test" do 13 | assert :ab == double_win?(true, true, false) 14 | assert :bc == double_win?(false, true, true) 15 | assert :ac == double_win?(true, false, true) 16 | assert not double_win?(true, true, true) 17 | assert not double_win?(false, false, false) 18 | assert not double_win?(true, false, false) 19 | assert not double_win?(false, true, false) 20 | assert not double_win?(false, false, true) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `shift_days`, которая принимает структуры `Time`, `DateTime`, `NaiveDateTime`, `Date` и смещает ее на количество переданных дней. Дни могут быть отрицательным числом: 3 | 4 | ```elixir 5 | naive_time = NaiveDateTime.utc_now() 6 | # => ~N[2023-11-17 18:24:21.345116] 7 | 8 | 9 | Solution.shift_days(naive_time, -2) 10 | # => ~N[2023-11-15 18:24:21.345116] 11 | Solution.shift_days(naive_time, 1) 12 | # => ~N[2023-11-18 18:24:21.345116] 13 | Solution.shift_days(naive_time, 0) 14 | # => ~N[2023-11-17 18:24:21.345116] 15 | 16 | date = Date.utc_today() 17 | # => ~D[2023-11-17] 18 | Solution.shift_days(date, -2) 19 | # => ~D[2023-11-15] 20 | Solution.shift_days(date, 1) 21 | # => ~D[2023-11-18] 22 | Solution.shift_days(date, 0) 23 | # => ~D[2023-11-17] 24 | ``` 25 | -------------------------------------------------------------------------------- /modules/35-fp/30-immutability/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуем [шифр Цезаря](https://ru.wikipedia.org/wiki/%D0%A8%D0%B8%D1%84%D1%80_%D0%A6%D0%B5%D0%B7%D0%B0%D1%80%D1%8F) -- простой способ шифрования путем сдвига каждого символа на константу. 3 | 4 | Нужно реализовать функцию `encode/2`, которая принимает набор символов (`charlists`) и сдвиг, и возвращает зашифрованный набор символов (`charlists`). 5 | 6 | ```elixir 7 | Solution.encode('Hello', 10) 8 | # => 'Rovvy' 9 | Solution.encode('Hello', 5) 10 | # => 'Mjqqt' 11 | ``` 12 | 13 | Также нужно реализовать функцию `decode/2`, которая принимает зашифрованную набор символов (`charlists`) и сдвиг, и возвращает оригинальный набор символов (`charlists`). 14 | 15 | ```elixir 16 | Solution.decode('Rovvy', 10) 17 | # => 'Hello' 18 | Solution.decode('Mjqqt', 5) 19 | # => 'Hello' 20 | ``` 21 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | test "addition" do 5 | assert Solution.calculate("+", 2, 3) == 5 6 | assert Solution.calculate("+", 0, -3) == -3 7 | end 8 | 9 | test "substraction" do 10 | assert Solution.calculate("-", 2, 3) == -1 11 | assert Solution.calculate("-", 0, 3) == -3 12 | assert Solution.calculate("-", 5, 3) == 2 13 | end 14 | 15 | test "division" do 16 | assert Solution.calculate("/", 4, 4) == 1.0 17 | assert Solution.calculate("/", 3, 2) == 1.5 18 | assert Solution.calculate("/", 4, 2) == 2.0 19 | end 20 | 21 | test "multiply" do 22 | assert Solution.calculate("*", 2, 2) == 4 23 | assert Solution.calculate("*", 0, 2) == 0 24 | assert Solution.calculate("*", 4, -2) == -8 25 | end 26 | end 27 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defprotocol Teller do 2 | @spec say_something(any()) :: String.t() 3 | def say_something(someone) 4 | end 5 | 6 | defmodule Human do 7 | defstruct [:name] 8 | end 9 | 10 | defmodule Dog do 11 | defstruct [:name] 12 | end 13 | 14 | defmodule Cat do 15 | defstruct [:name] 16 | end 17 | 18 | defimpl Teller, for: Human do 19 | def say_something(_), do: "Hello, world!" 20 | end 21 | 22 | defimpl Teller, for: Dog do 23 | def say_something(_), do: "Bark, world!" 24 | end 25 | 26 | defimpl Teller, for: Cat do 27 | def say_something(_), do: "Meow, world!" 28 | end 29 | 30 | # BEGIN 31 | defimpl Teller, for: Any do 32 | def say_something(_), do: "World!" 33 | end 34 | 35 | defmodule Robot do 36 | @derive [Teller] 37 | defstruct [:name] 38 | end 39 | 40 | # END 41 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: AST и подведение итогов 3 | tips: 4 | - | 5 | [Официальная документация Code](https://hexdocs.pm/elixir/Code.html) 6 | - > 7 | [Официальная документация 8 | Macro](https://hexdocs.pm/elixir/Macro.html#prewalk/2) 9 | - > 10 | [Про 11 | AST](https://ru.wikipedia.org/wiki/%D0%90%D0%B1%D1%81%D1%82%D1%80%D0%B0%D0%BA%D1%82%D0%BD%D0%BE%D0%B5_%D1%81%D0%B8%D0%BD%D1%82%D0%B0%D0%BA%D1%81%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%BE%D0%B5_%D0%B4%D0%B5%D1%80%D0%B5%D0%B2%D0%BE) 12 | - > 13 | [Примеры макросов на основе ExUnit, фреймворка для 14 | тестирования](https://github.com/elixir-lang/elixir/tree/main/lib/ex_unit/lib/ex_unit) 15 | - > 16 | [Веб фреймворк, в котором тоже много используется 17 | метапрограммирование](https://github.com/phoenixframework/phoenix) 18 | -------------------------------------------------------------------------------- /modules/20-data-types/20-lists/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `get_second_item`, которая возвращает сумму первого и второго элементов списка. 3 | 4 | Внимательный читатель спросит: "а что функция должна сделать, если в списке только один элемент, или список вообще пустой?". На этот вопрос мы ответим в следующем модуле, где будем изучать ветвления в коде и сопоставление с образцом. Пока будем считать, что функция всегда вызывается со списком, содержащим два или больше элементов. 5 | 6 | ```elixir 7 | Solution.get_second_item([20, 22, 24]) 8 | # => 42 9 | Solution.get_second_item([1, 2, 3, 4]) 10 | # => 3 11 | ``` 12 | 13 | Еще более внимательный читатель спросит: "а что, если список содержит элементы такого типа, для которого не определена операция суммирования?". В этом случае возникнет исключение. Исключения и обработку ошибок изучим в соответствующем модуле. 14 | -------------------------------------------------------------------------------- /modules/60-macros/40-macros-hygiene/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | import ExUnit.CaptureIO 5 | 6 | defmodule Exercise do 7 | require Solution 8 | 9 | def run_fn(function) do 10 | Solution.with_logging do 11 | function 12 | end 13 | end 14 | end 15 | 16 | test "with_logging work" do 17 | assert capture_io(fn -> Exercise.run_fn(fn -> 1 + 5 end) end) == 18 | "Started execution...\nExecution result is: 6\n" 19 | 20 | assert capture_io(fn -> Exercise.run_fn(fn -> %{hello: :world} end) end) == 21 | "Started execution...\nExecution result is: %{hello: :world}\n" 22 | 23 | assert capture_io(fn -> 24 | Exercise.run_fn(fn -> "some string" end) 25 | end) == "Started execution...\nExecution result is: \"some string\"\n" 26 | end 27 | end 28 | -------------------------------------------------------------------------------- /modules/45-structs/50-any-protocols/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "any teller protocol work" do 5 | test "for human" do 6 | assert Teller.impl_for(%Human{}) == Teller.Human 7 | assert Teller.say_something(%Human{name: "John"}) == "Hello, world!" 8 | end 9 | 10 | test "for dog" do 11 | assert Teller.impl_for(%Dog{}) == Teller.Dog 12 | assert Teller.say_something(%Dog{name: "Barkinson"}) == "Bark, world!" 13 | end 14 | 15 | test "for cat" do 16 | assert Teller.impl_for(%Cat{}) == Teller.Cat 17 | assert Teller.say_something(%Cat{name: "Meowington"}) == "Meow, world!" 18 | end 19 | 20 | test "for robot" do 21 | assert Teller.impl_for(%Robot{}) == Teller.Robot 22 | assert Teller.say_something(%Robot{name: "Roberto"}) == "World!" 23 | end 24 | end 25 | end 26 | -------------------------------------------------------------------------------- /modules/30-flow/15-pattern-matching-for-maps/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализовать функцию `get_values(data)`, которая принимает словарь, извлекает из него два значения по ключам `:a` и `:b`, и возвращает их в виде кортежа `{a_value, b_value}`. 3 | 4 | Реализовать функцию `get_value_by_key(data, key)`, которая принимает словарь и ключ, извлекает значение по указанному ключу и возвращает его. 5 | 6 | Обе функции генерируют исключение `MatchError` если в словаре нет нужных ключей. 7 | 8 | ```elixir 9 | Solution.get_values(%{a: 1, b: 2}) 10 | # => {1, 2} 11 | Solution.get_values(%{a: :ok, b: 42, c: true}) 12 | # => {:ok, 42} 13 | 14 | Solution.get_values(%{}) 15 | # => MatchError 16 | 17 | Solution.get_value_by_key(%{answer: 42}, :answer) 18 | # => 42 19 | Solution.get_value_by_key(%{question: "6 * 7"}, :question) 20 | # => "6 * 7" 21 | 22 | Solution.get_value_by_key(%{a: 1}, :b) 23 | # => MatchError 24 | ``` 25 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "join_game test" do 6 | assert :ok == join_game({:user, "Bob", 17, :admin}) 7 | assert :ok == join_game({:user, "Bob", 27, :admin}) 8 | assert :ok == join_game({:user, "Bob", 17, :moderator}) 9 | assert :ok == join_game({:user, "Bob", 27, :moderator}) 10 | assert :error == join_game({:user, "Bob", 17, :member}) 11 | assert :ok == join_game({:user, "Bob", 27, :member}) 12 | end 13 | 14 | test "move_allowed? test" do 15 | assert move_allowed?(:white, {:pawn, :white}) 16 | assert not move_allowed?(:black, {:pawn, :white}) 17 | assert move_allowed?(:white, {:rock, :white}) 18 | assert not move_allowed?(:black, {:rock, :white}) 19 | assert not move_allowed?(:white, {:queen, :white}) 20 | assert not move_allowed?(:black, {:queen, :white}) 21 | end 22 | end 23 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | В этот раз допишите функции агента `Accumulator`, используя модуль `Task` и опираясь на модуль `Calculator`: 3 | - `add` прибавить к состоянию аккумулятора переданное число; 4 | - `sub` вычесть состояние аккумулятора на переданное число; 5 | - `mul` умножить состояние аккумулятора на переданное число; 6 | - `div` разделить состояние аккумулятора на переданное число; 7 | - `reset` сбрасывает состояние `Accumulator` в ноль; 8 | - `current` возвращает нынешнее состояние `Accumulator`. 9 | 10 | ```elixir 11 | Accumulator.start_link(0) 12 | 13 | Accumulator.add(10) # => :ok 14 | Accumulator.current() # => 10 15 | 16 | Accumulator.sub(2) # => :ok 17 | Accumulator.current() # => 8 18 | 19 | Accumulator.mul(2) # => :ok 20 | Accumulator.current() # => 16 21 | 22 | Accumulator.div(4) # => :ok 23 | Accumulator.current() # => 4 24 | 25 | Accumulator.reset() # => :ok 26 | Accumulator.current() # => 0 27 | ``` 28 | -------------------------------------------------------------------------------- /modules/55-processes/20-processes-mailbox/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `calculate` которая принимает процесс-получатель и поддерживает операции `:+`, `:-`, `:*` в виде сообщений от процесса и при обработке возвращает сообщение процессу отправителю с результатом, функция должна поддерживать постоянную обработку сообщений. При передаче сообщения `:exit`, функция перестает обрабатывать входящие сообщения: 3 | 4 | ```elixir 5 | parent = self() 6 | calculator = spawn(fn -> Solution.calculate(parent) end) 7 | 8 | send(calculator, {:+, [2, 5]}) 9 | receive do 10 | {:ok, result} -> result 11 | end 12 | # => 7 13 | Process.alive?(calculator) 14 | # => true 15 | 16 | send(calculator, {:*, [2, 5]}) 17 | receive do 18 | {:ok, result} -> result 19 | end 20 | # => 10 21 | Process.alive?(calculator) 22 | # => true 23 | 24 | send(calculator, {:exit}) 25 | receive do 26 | {:ok, result} -> result 27 | end 28 | # => :exited 29 | Process.alive?(calculator) 30 | # => false 31 | ``` 32 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule ProcessRegister do 2 | use Agent 3 | 4 | def start_link(initial_value \\ %{}) do 5 | Agent.start_link(fn -> initial_value end, name: __MODULE__) 6 | end 7 | 8 | # BEGIN 9 | def add(process, name) when is_pid(process) do 10 | if registrable?(process, name) do 11 | Process.register(process, name) 12 | Agent.update(__MODULE__, fn state -> Map.put(state, name, process) end) 13 | end 14 | 15 | :ok 16 | end 17 | 18 | def drop(name) do 19 | try do 20 | Process.unregister(name) 21 | :ok 22 | rescue 23 | _ -> :ok 24 | after 25 | Agent.update(__MODULE__, fn state -> Map.delete(state, name) end) 26 | end 27 | end 28 | 29 | def list_registered() do 30 | Agent.get(__MODULE__, & &1) 31 | end 32 | 33 | defp registrable?(pid, name) do 34 | !Map.has_key?(list_registered(), name) && Process.alive?(pid) 35 | end 36 | 37 | # END 38 | end 39 | -------------------------------------------------------------------------------- /modules/65-extra/10-dates-and-times/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | @spec shift_days( 3 | time :: Time.t() | NaiveDateTime.t() | Date.t() | Time.t(), 4 | amount :: integer() 5 | ) :: Time.t() | NaiveDateTime.t() | Date.t() | Time.t() 6 | # BEGIN 7 | def shift_days(time, 0), do: time 8 | 9 | def shift_days(%Time{} = time, amount) when is_integer(amount) do 10 | Time.add(time, days_to_seconds(amount), :second) 11 | end 12 | 13 | def shift_days(%NaiveDateTime{} = time, amount) when is_integer(amount) do 14 | NaiveDateTime.add(time, days_to_seconds(amount), :second) 15 | end 16 | 17 | def shift_days(%Date{} = time, amount) when is_integer(amount) do 18 | Date.add(time, amount) 19 | end 20 | 21 | def shift_days(%DateTime{} = time, amount) when is_integer(amount) do 22 | DateTime.add(time, days_to_seconds(amount), :second) 23 | end 24 | 25 | defp days_to_seconds(amount) do 26 | amount * 24 * 60 * 60 27 | end 28 | 29 | # END 30 | end 31 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def to_ast(string) do 4 | {_, result} = Code.string_to_quoted(string) 5 | result 6 | end 7 | 8 | def collect_fn_and_arity({op, _, args} = ast, acc) when op in [:def, :defp] do 9 | {fn_name, fn_args} = get_fn_name_and_args(args) 10 | arity = length(fn_args) 11 | 12 | {ast, [%{name: fn_name, arity: arity} | acc]} 13 | end 14 | 15 | def collect_fn_and_arity(ast, acc) do 16 | {ast, acc} 17 | end 18 | 19 | defp get_fn_name_and_args(def_args) do 20 | case def_args do 21 | [{:when, _, args} | _] -> get_fn_name_and_args(args) 22 | [{name, _, args} | _] when is_list(args) -> {name, args} 23 | [{name, _, args} | _] when is_atom(args) -> {name, []} 24 | end 25 | end 26 | 27 | def collect_module_stats(string) do 28 | {_, acc} = 29 | string 30 | |> to_ast() 31 | |> Macro.prewalk([], &collect_fn_and_arity/2) 32 | 33 | acc 34 | end 35 | 36 | # END 37 | end 38 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # exercises-elixir 2 | 3 | [![Github Actions Status](../../workflows/Docker/badge.svg)](../../actions) 4 | 5 | ## How to contribute 6 | 7 | * Discuss the project on Telegram: https://t.me/hexletcommunity/12 8 | 9 | ## Develop 10 | 11 | ```bash 12 | # setup 13 | make 14 | # run 15 | make compose 16 | # check 17 | make ci-check 18 | 19 | # run tests 20 | make compose-test 21 | 22 | # run linters and validators 23 | make compose-code-lint 24 | make compose-description-lint 25 | make compose-schema-validate 26 | ``` 27 | 28 | --- 29 | 30 | [![Hexlet Ltd. logo](https://raw.githubusercontent.com/Hexlet/assets/master/images/hexlet_logo128.png)](https://hexlet.io/?utm_source=github&utm_medium=link&utm_campaign=exercises-elixir) 31 | 32 | This repository is created and maintained by the team and the community of Hexlet, an educational project. [Read more about Hexlet](https://hexlet.io/?utm_source=github&utm_medium=link&utm_campaign=exercises-elixir). 33 | 34 | See most active contributors on [hexlet-friends](https://friends.hexlet.io/). 35 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | -include /opt/basics/common/common.mk 2 | 3 | install: 4 | mix deps.get 5 | 6 | compose-setup: compose-build compose-install 7 | 8 | compose: 9 | docker-compose up 10 | 11 | compose-install: 12 | docker-compose run --rm exercises make install 13 | 14 | compose-bash: 15 | docker-compose run --rm exercises bash 16 | 17 | compose-build: 18 | docker-compose build 19 | 20 | compose-down: 21 | docker-compose down -v --remove-orphans 22 | 23 | compose-test: 24 | docker-compose run --rm exercises make test 25 | 26 | compose-lint: 27 | docker-compose run --rm exercises make code-lint 28 | 29 | code-lint-fix: 30 | mix format 31 | 32 | code-lint: 33 | mix format --check-formatted && \ 34 | mix credo 35 | 36 | compose-description-lint: 37 | docker-compose run --rm exercises make description-lint 38 | 39 | compose-schema-validate: 40 | docker-compose run --rm exercises make schema-validate 41 | 42 | ci-check: 43 | docker-compose --file docker-compose.yml build 44 | docker-compose --file docker-compose.yml up --abort-on-container-exit 45 | -------------------------------------------------------------------------------- /modules/30-flow/30-cond/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализовать функцию `single_win?(a_win, b_win)`, которая принимает 2 булевых параметра: `a_win` -- победил ли игрок A, и `b_win` -- победил ли игрок B. Функция возвращает `true` если победил только один из двоих игроков, иначе возвращает `false`. 3 | 4 | Реализовать функцию `double_win?(a_win, b_win, c_win)`, которая принимает 3 булевых параметра для трех игроков. Если победили игроки A и B, то функция возвращает атом `:ab`. Если победили игроки A и C, то функция возвращает атом `:ac`, если победили игроки B и C, то функция возвращает атом `:bc`. Во всех остальных случаях функция возвращает `false`. 5 | 6 | ```elixir 7 | Solution.single_win?(true, false) 8 | # => true 9 | Solution.single_win?(false, true) 10 | # => true 11 | Solution.single_win?(true, true) 12 | # => false 13 | 14 | Solution.double_win?(true, true, false) 15 | # => :ab 16 | Solution.double_win?(true, false, true) 17 | # => :ac 18 | Solution.double_win?(true, true, true) 19 | # => false 20 | Solution.double_win?(true, false, false) 21 | # => false 22 | ``` 23 | -------------------------------------------------------------------------------- /modules/40-collections/40-comprehension/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `fetch_gamers`, которая принимает список сотрудников и выводит список активных сотрудников (статус `:active`) сотрудников у которых хобби связаны с играми (тип хобби `:gaming`). Структура сотрудников описана в примере: 3 | 4 | ```elixir 5 | employees = [ 6 | %{ 7 | name: "Eric", 8 | status: :active, 9 | hobbies: [%{name: "Text Adventures", type: :gaming}, %{name: "Chickens", type: :animals}] 10 | }, 11 | %{ 12 | name: "Mitch", 13 | status: :former, 14 | hobbies: [%{name: "Woodworking", type: :making}, %{name: "Homebrewing", type: :making}] 15 | }, 16 | %{ 17 | name: "Greg", 18 | status: :active, 19 | hobbies: [ 20 | %{name: "Dungeons & Dragons", type: :gaming}, 21 | %{name: "Woodworking", type: :making} 22 | ] 23 | } 24 | ] 25 | 26 | 27 | Solution.fetch_gamers(employees) 28 | # => [ 29 | # => {"Eric", %{name: "Text Adventures", type: :gaming}}, 30 | # => {"Greg", %{name: "Dungeons & Dragons", type: :gaming}} 31 | # => ] 32 | ``` 33 | -------------------------------------------------------------------------------- /modules/40-collections/20-filter/ru/README.md: -------------------------------------------------------------------------------- 1 | 2 | Функция `map` может менять элементы списка, но не может менять их количество: сколько элементов было в исходном списке, столько же останется. Функция `filter` же, напротив, не может менять сами элементы, но может решать, какие из них попадут в выходной список, а какие будут отброшены. 3 | 4 | ```elixir 5 | numbers = [12, 2, 30, 4, 55, 10, 11] 6 | 7 | result = Enum.filter(numbers, fn (x) -> x >= 10 end) 8 | IO.puts(result) # => [12, 30, 55, 10, 11] 9 | 10 | result = 11 | numbers 12 | |> Enum.filter(fn (x) -> x < 20 end) 13 | |> Enum.filter(fn (x) -> rem(x, 2) == 0 end) 14 | |> IO.puts() # => [12, 2, 4, 10] 15 | 16 | users = [%{name: "Igor", age: 21}, %{name: "John", age: 13}, %{name: "Alice", age: 20}, %{name: "Isabella", age: 13}] 17 | 18 | result = Enum.filter(users, fn %{age: age} -> age < 15 end) 19 | IO.puts(result) # => [%{age: 13, name: "John"}, %{age: 13, name: "Isabella"}] 20 | 21 | result = Enum.filter(users, &(String.starts_with?(&1[:name], "Al"))) 22 | IO.puts(result) # => [%{age: 20, name: "Alice"}] 23 | ``` 24 | -------------------------------------------------------------------------------- /mix.lock: -------------------------------------------------------------------------------- 1 | %{ 2 | "bunt": {:hex, :bunt, "1.0.0", "081c2c665f086849e6d57900292b3a161727ab40431219529f13c4ddcf3e7a44", [:mix], [], "hexpm", "dc5f86aa08a5f6fa6b8096f0735c4e76d54ae5c9fa2c143e5a1fc7c1cd9bb6b5"}, 3 | "credo": {:hex, :credo, "1.7.11", "d3e805f7ddf6c9c854fd36f089649d7cf6ba74c42bc3795d587814e3c9847102", [:mix], [{:bunt, "~> 0.2.1 or ~> 1.0", [hex: :bunt, repo: "hexpm", optional: false]}, {:file_system, "~> 0.2 or ~> 1.0", [hex: :file_system, repo: "hexpm", optional: false]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: false]}], "hexpm", "56826b4306843253a66e47ae45e98e7d284ee1f95d53d1612bb483f88a8cf219"}, 4 | "file_system": {:hex, :file_system, "1.1.0", "08d232062284546c6c34426997dd7ef6ec9f8bbd090eb91780283c9016840e8f", [:mix], [], "hexpm", "bfcf81244f416871f2a2e15c1b515287faa5db9c6bcf290222206d120b3d43f6"}, 5 | "jason": {:hex, :jason, "1.4.4", "b9226785a9aa77b6857ca22832cffa5d5011a667207eb2a0ad56adb5db443b8a", [:mix], [{:decimal, "~> 1.0 or ~> 2.0", [hex: :decimal, repo: "hexpm", optional: true]}], "hexpm", "c5eb0cab91f094599f94d55bc63409236a8ec69a21a67814529e8d5f6cc90b3b"}, 6 | } 7 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Decrementor do 2 | use Agent 3 | 4 | def start_link(initial_state \\ 0) do 5 | Agent.start_link(fn -> initial_state end, name: __MODULE__) 6 | end 7 | 8 | def current_value, do: Agent.get(__MODULE__, fn state -> state end) 9 | def run, do: Agent.update(__MODULE__, fn state -> state - 1 end) 10 | end 11 | 12 | defmodule Incrementor do 13 | use Agent 14 | 15 | def start_link(initial_state \\ 0) do 16 | Agent.start_link(fn -> initial_state end, name: __MODULE__) 17 | end 18 | 19 | def current_value, do: Agent.get(__MODULE__, fn state -> state end) 20 | def run, do: Agent.update(__MODULE__, fn state -> state + 1 end) 21 | end 22 | 23 | defmodule Solution do 24 | use Supervisor 25 | 26 | # BEGIN 27 | def start_link(init_args \\ %{}) do 28 | Supervisor.start_link(__MODULE__, init_args, name: __MODULE__) 29 | end 30 | 31 | def init(_init_args) do 32 | children = [ 33 | {Incrementor, 0}, 34 | {Decrementor, 0} 35 | ] 36 | 37 | Supervisor.init(children, strategy: :one_for_one) 38 | end 39 | 40 | # END 41 | end 42 | -------------------------------------------------------------------------------- /modules/35-fp/40-anonymous-fn/ru/README.md: -------------------------------------------------------------------------------- 1 | 2 | Помимо именованных функций, можно создавать анонимные в форме `fn (x) -> fn_body end`, важно отметить, что для вызова таких функций нужно дописать перед скобками точку `.`. Рассмотрим примеры: 3 | 4 | ```elixir 5 | sum = fn (x, y) -> x + y end 6 | sum.(2, 3) # => 5 7 | 8 | magic = fn (a, b, c) -> (a + b) * c end 9 | magic.(2, 3, 4) # => 20 10 | ``` 11 | 12 | Так как функции в эликсире являются объектами первого класса, то часто приходится писать анонимные функции, которые передаются в другие функции и для сокращения записи таких функций используется оператор `&`: 13 | 14 | ```elixir 15 | mul = &(&1 * &2) 16 | mul.(3, 3) # => 9 17 | 18 | magic = &((&1 + &2 + &3) * &4) 19 | magic.(1, 2, 3, 4) # => 24 20 | 21 | more_magic = &(&1.(&2)) 22 | increment = &(&1 + 1) 23 | more_magic.(increment, 10) # => 11 24 | 25 | double = &(&1 * &1) 26 | more_magic.(double, 5) # => 25 27 | ``` 28 | 29 | При использовании сокращенного синтаксиса для анонимных функций следует быть аккуратным, так как при большом количестве аргументов можно легко запутаться с их порядком, особенно, если в функции есть сложная логика. 30 | -------------------------------------------------------------------------------- /modules/55-processes/50-supervisors/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Супервизоры могут задаваться через модули, для этого нужно в модуле использовать поведение `Supervisor` и определить функцию обратного вызова `init/1`, которая будет вызвана при запуске супервизора через `start_link`. В файле с решением описано два агента, ваша задача дописать модуль `Solution`, добавив две функции: 3 | - `start_link` - функция для запуска супервизора из модуля 4 | - `init` - функция, которая запустится перед стартом супервизора, в неё передается список потомков, стратегия перезапуска и т.д. 5 | 6 | В функции `init` сделайте потомками `Decrementor` и `Incrementor`, а в стратегии перезапуска укажите `:one_for_one`. 7 | 8 | ```elixir 9 | {:ok, _} = Solution.start_link() 10 | 11 | Supervisor.which_children(Solution) 12 | # => [ 13 | # => {Decrementor, #PID<0.196.0>, :worker, [Decrementor]}, 14 | # => {Incrementor, #PID<0.195.0>, :worker, [Incrementor]} 15 | # => ] 16 | 17 | Supervisor.count_children(Solution) 18 | # => %{active: 2, workers: 2, supervisors: 0, specs: 2} 19 | 20 | Incrementor.run() 21 | Incrementor.current_value() 22 | # => 1 23 | 24 | Decrementor.current_value() 25 | # => 0 26 | ``` 27 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/ru/data.yml: -------------------------------------------------------------------------------- 1 | --- 2 | name: Генсерверы 3 | tips: 4 | - > 5 | [Официальная документация 6 | GenServer](https://hexdocs.pm/elixir/GenServer.html) 7 | - > 8 | [Акторная 9 | модель](https://ru.wikipedia.org/wiki/%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C_%D0%B0%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2#:~:text=%D0%9C%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D0%B0%CC%81%D0%BA%D1%82%D0%BE%D1%80%D0%BE%D0%B2%20%E2%80%94%20%D0%BC%D0%B0%D1%82%D0%B5%D0%BC%D0%B0%D1%82%D0%B8%D1%87%D0%B5%D1%81%D0%BA%D0%B0%D1%8F%20%D0%BC%D0%BE%D0%B4%D0%B5%D0%BB%D1%8C%20%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D1%8B%D1%85,%D1%81%D1%87%D0%B8%D1%82%D0%B0%D1%8E%D1%89%D0%B5%D0%B3%D0%BE%D1%81%D1%8F%20%D1%83%D0%BD%D0%B8%D0%B2%D0%B5%D1%80%D1%81%D0%B0%D0%BB%D1%8C%D0%BD%D1%8B%D0%BC%20%D0%BF%D1%80%D0%B8%D0%BC%D0%B8%D1%82%D0%B8%D0%B2%D0%BE%D0%BC%20%D0%BF%D0%B0%D1%80%D0%B0%D0%BB%D0%BB%D0%B5%D0%BB%D1%8C%D0%BD%D0%BE%D0%B3%D0%BE%20%D0%B8%D1%81%D0%BF%D0%BE%D0%BB%D0%BD%D0%B5%D0%BD%D0%B8%D1%8F.) 10 | - | 11 | [История Erlang](https://habr.com/ru/companies/ruvds/articles/749192/) 12 | - > 13 | [Цитаты Джо Армстронга, создателя 14 | Erlang](https://habr.com/ru/articles/508696/) 15 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Calculator do 2 | def exec(:+, a, b), do: a + b 3 | def exec(:-, a, b), do: a - b 4 | def exec(:*, a, b), do: a * b 5 | def exec(:/, a, b), do: div(a, b) 6 | end 7 | 8 | defmodule Accumulator do 9 | use Agent 10 | 11 | def start_link(initial_value) do 12 | Agent.start_link(fn -> initial_value end, name: __MODULE__) 13 | end 14 | 15 | # BEGIN 16 | def current do 17 | Agent.get(__MODULE__, & &1) 18 | end 19 | 20 | def add(number) when is_number(number) do 21 | update(:+, number) 22 | end 23 | 24 | def sub(number) when is_number(number) do 25 | update(:-, number) 26 | end 27 | 28 | def mul(number) when is_number(number) do 29 | update(:*, number) 30 | end 31 | 32 | def div(number) when is_number(number) do 33 | update(:/, number) 34 | end 35 | 36 | def reset, do: mul(0) 37 | 38 | defp update(operation, operator) do 39 | Agent.update(__MODULE__, fn state -> 40 | run_calculator_task(operation, state, operator) 41 | end) 42 | end 43 | 44 | defp run_calculator_task(operation, a, b) do 45 | Task.async(fn -> Calculator.exec(operation, a, b) end) |> Task.await() 46 | end 47 | 48 | # END 49 | end 50 | -------------------------------------------------------------------------------- /modules/30-flow/40-function-clause/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | # BEGIN 3 | def valid_game?({row1, row2, row3}) do 4 | valid_row(row1) and valid_row(row2) and valid_row(row3) 5 | end 6 | 7 | def valid_game?(_), do: false 8 | 9 | def valid_row({cell1, cell2, cell3}) do 10 | valid_cell(cell1) and valid_cell(cell2) and valid_cell(cell3) 11 | end 12 | 13 | def valid_row(_), do: false 14 | 15 | def valid_cell(:x), do: true 16 | def valid_cell(:o), do: true 17 | def valid_cell(:f), do: true 18 | def valid_cell(_), do: false 19 | 20 | def check_who_win({{c, c, c}, _, _}) when c != :f, do: {:win, c} 21 | def check_who_win({_, {c, c, c}, _}) when c != :f, do: {:win, c} 22 | def check_who_win({_, _, {c, c, c}}) when c != :f, do: {:win, c} 23 | def check_who_win({{c, _, _}, {c, _, _}, {c, _, _}}) when c != :f, do: {:win, c} 24 | def check_who_win({{_, c, _}, {_, c, _}, {_, c, _}}) when c != :f, do: {:win, c} 25 | def check_who_win({{_, _, c}, {_, _, c}, {_, _, c}}) when c != :f, do: {:win, c} 26 | def check_who_win({{c, _, _}, {_, c, _}, {_, _, c}}) when c != :f, do: {:win, c} 27 | def check_who_win({{_, _, c}, {_, c, _}, {c, _, _}}) when c != :f, do: {:win, c} 28 | def check_who_win(_), do: :no_win 29 | # END 30 | end 31 | -------------------------------------------------------------------------------- /modules/30-flow/50-pipeline/ru/README.md: -------------------------------------------------------------------------------- 1 | 2 | Одна из фишек Эликсир -- оператор *pipe*. Это удобный способ написания цепочек вызовов функций, где результат одной функции является аргументом для другой. 3 | 4 | В большинстве языков в такой ситуации используют либо временные переменные: 5 | 6 | ```elixir 7 | a = func1() 8 | b = func2(a) 9 | c = func3(b) 10 | ``` 11 | 12 | Либо вложенные вызовы: 13 | 14 | ```elixir 15 | func3(func2(func1()) 16 | ``` 17 | 18 | Но pipe позволяет написать код короче и с естественным порядком функций в цепочке: 19 | 20 | ```elixir 21 | func1() |> func2() |> func3() 22 | ``` 23 | 24 | Оператор принимает значение из одной функции, и передаёт его первым аргументом во вторую функцию. Если у функции больше одного аргумента, то их нужно указать явно: 25 | 26 | ```elixir 27 | Map.put(%{}, :a, 1) |> Map.put(:b, 2) |> Map.put(:c, 3) # %{a: 1, b: 2, c: 3} 28 | ``` 29 | 30 | `pipe` настолько важен, что все функции системных библиотек рассчитаны на его использование. Например, большинство функций в модуле *Map* первым аргументом принимают Map, поэтому их легко собирать в цепочку. 31 | 32 | ```elixir 33 | Map.new() |> Map.put_new(:a, 1) |> Map.to_list() # [a: 1] 34 | ``` 35 | 36 | Рекомендуется придерживаться такого же подхода в своих собственных функциях. 37 | -------------------------------------------------------------------------------- /modules/55-processes/30-processes-state/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule CacheServer do 2 | # BEGIN 3 | def init(parent, initial_state \\ %{}) do 4 | process_requests(parent, initial_state) 5 | end 6 | 7 | defp process_requests(parent, state) do 8 | receive do 9 | {operation, args} -> 10 | {response, result, new_state} = exec(operation, args, state) 11 | send(parent, {response, result}) 12 | process_requests(parent, new_state) 13 | 14 | {:exit} -> 15 | send(parent, {:ok, :exited}) 16 | 17 | _ -> 18 | send(parent, {:error, :unrecognized_operation}) 19 | process_requests(parent, state) 20 | end 21 | end 22 | 23 | defp exec(:put, {key, value}, state) do 24 | {:ok, value, Map.put(state, key, value)} 25 | end 26 | 27 | defp exec(:get, {key}, state) do 28 | if Map.has_key?(state, key) do 29 | value = Map.get(state, key) 30 | {:ok, value, state} 31 | else 32 | {:error, :not_found, state} 33 | end 34 | end 35 | 36 | defp exec(:drop, {key}, state) do 37 | new_state = Map.delete(state, key) 38 | {:ok, key, new_state} 39 | end 40 | 41 | defp exec(_, _, state) do 42 | {:error, :unrecognized_operation, state} 43 | end 44 | 45 | # END 46 | end 47 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализовать функцию `point_inside_circle?(point, circle)`, которая принимает точку и окружность, и возвращает `true`, если точка находится внутри окружности, или `false`, если точка находится снаружи. 3 | 4 | Реализовать функцию `point_inside_rect?(point, rect)`, которая принимает точку и прямоугольник, и возвращает `true`, если точка находится внутри прямоугольника, или `false`, если точка находится снаружи. 5 | 6 | Точка представлена кортежем `{:point, x, y}`. 7 | 8 | Окружность представлена кортежем `{:circle, center, radius}`, где center — это кортеж `:point`. 9 | 10 | Прямоугольник представлен кортежем `{:rect, left_top, right_bottom}`, где `left_top` и `right_bottom` — это кортежи `:point`. 11 | 12 | Уже реализованная функция distance может вам пригодиться: 13 | 14 | ```elixir 15 | point = {:point, 50, 50} 16 | Solution.point_inside_circle?(point, {:circle, {:point, 10, 10}, 100}) 17 | # => true 18 | Solution.point_inside_circle?(point, {:circle, {:point, -10, -10}, 20}) 19 | # => false 20 | 21 | point = {:point, -10, 20} 22 | Solution.point_inside_rect?(point, {:rect, {:point, -20, 30}, {:point, 20, 10}}) 23 | # => true 24 | Solution.point_inside_rect?(point, {:rect, {:point, 0, 0}, {:point, 10, 10}}) 25 | # => false 26 | ``` 27 | -------------------------------------------------------------------------------- /modules/30-flow/20-case/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализовать функцию `join_game(user)`, которая принимает игрока в виде кортежа `{:user, name, age, role}` и определяет, разрешено ли данному игроку подключиться к игре. Если игроку уже исполнилось 18 лет, то он может войти в игру. Если роль игрока `:admin` или `:moderator`, то он может войти в игру независимо от возраста. Функция должна вернуть `:ok` или `:error`. 3 | 4 | Реализовать функцию `move_allowed?(current_color, figure)` которая определяет, разрешено ли данной шахматной фигуре сделать ход. Параметр `current_color` может быть либо `:white` либо `:black`, и он указывает, фигурам какого цвета разрешено сделать ход. Параметр `figure` представлен кортежем `{type, color}`, где `type` может быть один из: `:pawn`, `:rock`, `:bishop`, `:knight`, `:queen`, `:king`, а color может быть `:white` или `:black`. Фигура может сделать ход если её тип `:pawn` или `:rock` и её цвет совпадает с `current_color`. Функция должна вернуть `true` или `false`. 5 | 6 | ```elixir 7 | Solution.join_game({:user, "Bob", 17, :admin}) 8 | # => :ok 9 | Solution.join_game({:user, "Bob", 17, :moderator}) 10 | # => :ok 11 | Solution.join_game({:user, "Bob", 17, :member}) 12 | # => :error 13 | 14 | Solution.move_allowed?(:white, {:pawn, :white}) 15 | # => true 16 | Solution.move_allowed?(:black, {:pawn, :white}) 17 | # => false 18 | ``` 19 | -------------------------------------------------------------------------------- /modules/55-processes/60-genservers/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Solution do 2 | use GenServer 3 | 4 | def start_link(initial_state \\ %{}) do 5 | GenServer.start_link(__MODULE__, initial_state, name: __MODULE__) 6 | end 7 | 8 | def init(initial_state) do 9 | {:ok, initial_state} 10 | end 11 | 12 | # BEGIN 13 | # client 14 | def add(key, value) do 15 | GenServer.cast(__MODULE__, {:add, key, value}) 16 | end 17 | 18 | def drop(key) do 19 | GenServer.cast(__MODULE__, {:drop, key}) 20 | end 21 | 22 | def reset() do 23 | GenServer.cast(__MODULE__, :reset) 24 | end 25 | 26 | def current_state() do 27 | GenServer.call(__MODULE__, :current_state) 28 | end 29 | 30 | def has?(key) do 31 | GenServer.call(__MODULE__, {:has?, key}) 32 | end 33 | 34 | # server 35 | def handle_call(:current_state, _from, state) do 36 | {:reply, state, state} 37 | end 38 | 39 | def handle_call({:has?, key}, _from, state) do 40 | {:reply, Map.has_key?(state, key), state} 41 | end 42 | 43 | def handle_cast(:reset, _state) do 44 | {:noreply, %{}} 45 | end 46 | 47 | def handle_cast({:add, key, value}, state) do 48 | {:noreply, Map.put(state, key, value)} 49 | end 50 | 51 | def handle_cast({:drop, key}, state) do 52 | {:noreply, Map.delete(state, key)} 53 | end 54 | 55 | # END 56 | end 57 | -------------------------------------------------------------------------------- /modules/20-data-types/10-atoms-and-tuples/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "distance not changed" do 6 | assert 5.0 == distance({:point, 0, 0}, {:point, 0, 5}) 7 | assert 5.0 == distance({:point, 5, 0}, {:point, 0, 0}) 8 | assert 0.0 == distance({:point, 5, 5}, {:point, 5, 5}) 9 | assert 5.0 == distance({:point, 0, 0}, {:point, 3, 4}) 10 | assert 5.0 == distance({:point, 0, 0}, {:point, -3, -4}) 11 | end 12 | 13 | test "bigger distance not changed" do 14 | assert 12.806248474865697 == distance({:point, 2, 2}, {:point, 10, 12}) 15 | assert 21.213203435596427 == distance({:point, -5, -5}, {:point, 10, 10}) 16 | assert 21.400934559032695 == distance({:point, -5, 5}, {:point, 8, -12}) 17 | assert 17.26267650163207 == distance({:point, -5, 5}, {:point, -8, -12}) 18 | end 19 | 20 | test "point inside circle" do 21 | point = {:point, 50, 50} 22 | assert point_inside_circle?(point, {:circle, {:point, 10, 10}, 100}) 23 | assert not point_inside_circle?(point, {:circle, {:point, -10, -10}, 20}) 24 | end 25 | 26 | test "point inside rect" do 27 | point = {:point, -10, 20} 28 | assert point_inside_rect?(point, {:rect, {:point, -20, 30}, {:point, 20, 10}}) 29 | assert not point_inside_rect?(point, {:rect, {:point, 0, 0}, {:point, 10, 10}}) 30 | end 31 | end 32 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/lib/solution.ex: -------------------------------------------------------------------------------- 1 | defmodule Worker do 2 | def work(number) do 3 | cond do 4 | rem(number, 3) == 0 && rem(number, 5) == 0 -> exit(:foobar) 5 | rem(number, 3) == 0 -> exit(:foo) 6 | rem(number, 5) == 0 -> exit(:bar) 7 | true -> exit(:normal) 8 | end 9 | end 10 | end 11 | 12 | defmodule Solution do 13 | # BEGIN 14 | def supervise_foobar(initial_number) do 15 | Process.flag(:trap_exit, true) 16 | call_worker(initial_number) 17 | 18 | initial_number |> supervise() |> String.trim() 19 | end 20 | 21 | defp supervise(number) do 22 | receive do 23 | {:EXIT, _, :foobar} -> process_next("FooBar", number) 24 | {:EXIT, _, :foo} -> process_next("Foo", number) 25 | {:EXIT, _, :bar} -> process_next("Bar", number) 26 | {:EXIT, _, :normal} -> process_next("", number) 27 | end 28 | end 29 | 30 | defp process_next(_, number) when number > 100, do: "" 31 | defp process_next(_, number) when number < 1, do: "" 32 | 33 | defp process_next("", number) do 34 | next_number = number + 1 35 | call_worker(next_number) 36 | supervise(next_number) 37 | end 38 | 39 | defp process_next(text, number) do 40 | next_number = number + 1 41 | call_worker(next_number) 42 | "#{text} #{supervise(next_number)}" 43 | end 44 | 45 | defp call_worker(number) do 46 | spawn_link(fn -> Worker.work(number) end) 47 | end 48 | 49 | # END 50 | end 51 | -------------------------------------------------------------------------------- /modules/35-fp/20-recursion-with-acc/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | setup do 6 | users = [ 7 | {:user, 1, "Bob", 23}, 8 | {:user, 2, "Helen", 20}, 9 | {:user, 3, "Bill", 15}, 10 | {:user, 4, "Kate", 14} 11 | ] 12 | 13 | [users: users] 14 | end 15 | 16 | test "filter_by_age test", %{users: users} do 17 | assert filter_by_age(users, 30) == [] 18 | assert filter_by_age(users, 23) == [] 19 | assert filter_by_age(users, 22) == [{:user, 1, "Bob", 23}] 20 | assert filter_by_age(users, 20) == [{:user, 1, "Bob", 23}] 21 | assert filter_by_age(users, 19) == [{:user, 1, "Bob", 23}, {:user, 2, "Helen", 20}] 22 | assert filter_by_age(users, 15) == [{:user, 1, "Bob", 23}, {:user, 2, "Helen", 20}] 23 | 24 | assert filter_by_age(users, 14) == [ 25 | {:user, 1, "Bob", 23}, 26 | {:user, 2, "Helen", 20}, 27 | {:user, 3, "Bill", 15} 28 | ] 29 | 30 | assert filter_by_age(users, 13) == [ 31 | {:user, 1, "Bob", 23}, 32 | {:user, 2, "Helen", 20}, 33 | {:user, 3, "Bill", 15}, 34 | {:user, 4, "Kate", 14} 35 | ] 36 | 37 | assert filter_by_age(users, 10) == [ 38 | {:user, 1, "Bob", 23}, 39 | {:user, 2, "Helen", 20}, 40 | {:user, 3, "Bill", 15}, 41 | {:user, 4, "Kate", 14} 42 | ] 43 | end 44 | end 45 | -------------------------------------------------------------------------------- /modules/10-basics/10-hello-world/ru/README.md: -------------------------------------------------------------------------------- 1 | 2 | Elixir – динамический, функциональный язык программирования, спроектированный для создания масштабируемых и легко поддерживаемых приложений. Эликсир был выпущен в 2012 году Жозе Валимом, и несколько лет поддерживался только своим создателем. В какой-то момент его популярность выросла настолько, что многие компании начали серьезно использовать его в своих проектах. 3 | 4 | Эликсир работает поверх виртуальной машины языка эрланг. Она широко известна своими уникальными возможностями для создания отказоустойчивых и распределенных систем. Причем, как во встраиваемых устройствах, например роутерах, так и в вебе, при создании приложений реального времени (игры, мессенджеры). 5 | 6 | Практически все, что говорится про эликсир, является заслугой виртуальной машины эрланга. Эликсир задумывался как язык, который привносит в мир эрланга кое-что новое, чего не хватало самому эрлангу. В первую очередь это средства, повышающие уровень абстракции (Struct, Protocol), позволяющие писать более лаконичный код (оператор pipe, конструкция with), и удобно управлять проектом и его зависимостями (mix). Кроме того, это метапрограммирование -- мощная система макросов, позволяющая создавать DSL-языки. Хорошим примером такого DSL-языка является библиотека Ecto для работы с базами данных. 7 | 8 | Эликсир – практичный язык. Он прост в освоении и эффективен в работе. На его базе создан веб-фреймворк Phoenix, очень напоминающий упрощенный Ruby On Rails. Его код открыт и доступен на гитхабе. 9 | -------------------------------------------------------------------------------- /modules/60-macros/50-macros-ast/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Создайте функцию `collect_module_stats` принимающую строку, в которой определяется модуль и функции модуля, а затем подсчитывается статистика по функциям, определенные внутри модуля. 3 | 4 | Для начала, изучите функцию `string_to_quoted` модуля `Code` и функцию `prewalk` из модуля `Macro`. Формат собираемой статистики представлен в примерах: 5 | 6 | ```elixir 7 | new_module = """ 8 | defmodule MyModule do 9 | 10 | end 11 | """ 12 | 13 | Solution.collect_module_stats(new_module) 14 | # => [] 15 | 16 | new_module = """ 17 | defmodule MyModule do 18 | def hello() do 19 | "world" 20 | end 21 | end 22 | """ 23 | 24 | Solution.collect_module_stats(new_module) 25 | # => [%{arity: 0, name: :hello}] 26 | 27 | new_module = """ 28 | defmodule MyModule do 29 | def hello() do 30 | "world" 31 | end 32 | 33 | defp test(a, b) do 34 | a + b 35 | end 36 | end 37 | """ 38 | 39 | Solution.collect_module_stats(new_module) 40 | # => [%{arity: 2, name: :test}, %{arity: 0, name: :hello}] 41 | 42 | new_module = """ 43 | defmodule MyModule do 44 | def hello(string) do 45 | [string, "world"] 46 | end 47 | 48 | def magic(a, b, c) do 49 | (a + b) * c 50 | end 51 | 52 | defp test(a, b) do 53 | a + b 54 | end 55 | end 56 | """ 57 | 58 | Solution.collect_module_stats(new_module) 59 | # => [%{arity: 2, name: :test}, %{arity: 3, name: :magic}, %{arity: 1, name: :hello}] 60 | ``` 61 | -------------------------------------------------------------------------------- /modules/10-basics/40-numbers/ru/README.md: -------------------------------------------------------------------------------- 1 | 2 | В Эликсир есть два вида чисел — целые и с плавающей точкой. 3 | 4 | Целые числа могут быть представлены разными способами. В разных системах исчисления: в десятичной, шестнадцатеричной, восьмеричной и двоичной: 5 | 6 | ```elixir 7 | 42 8 | 0x2A 9 | 0o52 10 | 0b101010 11 | ``` 12 | 13 | В экспоненциальном виде: 14 | 15 | ```elixir 16 | 0.42e2 17 | ``` 18 | 19 | Для больших чисел можно использовать символ подчеркивания между разрядами для удобства чтения: 20 | 21 | ```elixir 22 | 100_500 23 | 1_000_000 24 | ``` 25 | 26 | Числа с плавающей точкой реализованы по стандарту IEEE 754, как и в большинстве других языков. Это значит, что их точность ограничена, и при некоторых операциях возможна потеря точности: 27 | 28 | ```elixir 29 | 0.1 + 0.2 # 0.30000000000000004 30 | ``` 31 | 32 | Для целых чисел, и чисел с плавающей точкой реализованы обычные арифметические операции: 33 | 34 | ```elixir 35 | 20 + 22 # 42 36 | 20.0 + 22 # 42.0 37 | 50 - 8.0 # 42.0 38 | 2 * 16 # 32 39 | 4 * 16.0 # 64.0 40 | 128 / 2 # 64.0 41 | 64.0 / 4.0 # 16.0 42 | ``` 43 | 44 | Операторы `+ - *` возвращают целое число, если оба аргумента целые, и число с плавающей точкой, если хотя бы один из аргументов с плавающей точкой. Оператор `/` всегда возвращает число с плавающей точкой. 45 | 46 | Еще есть оператор целочисленного деления `div` и оператор взятия остатка `rem`: 47 | 48 | ```elixir 49 | div(42, 2) # 21 50 | div(45, 2) # 22 51 | rem(42, 2) # 0 52 | rem(45, 2) # 1 53 | ``` 54 | -------------------------------------------------------------------------------- /modules/10-basics/20-modules/en/README.md: -------------------------------------------------------------------------------- 1 | 2 | In Elixir, functions are grouped by modules that play the role of namespaces. For example, in the previous exercise we used the function `puts(text)` from module _IO_: 3 | 4 | ```elixir 5 | IO.puts("Hello, World!") 6 | ``` 7 | 8 | Modules are defined with a special contstruct _defmodule/do/end_: 9 | 10 | ```elixir 11 | # use CamelCase for name 12 | defmodule HexletBasics do 13 | # Here goes module contains 14 | end 15 | ``` 16 | 17 | Elixir allows the creation of multiple modules in the same file, but there is a convention to have only one module per file with the same name as the module but in _snake_case_. 18 | 19 | Modules can be nested. By convention, we create nested modules when they are located in a directory. For example, there's the module `HexletBasics.Application` located in _lib/hexlet_basics/application.ex_ directory. 20 | 21 | ```elixir 22 | defmodule HexletBasics.Application do 23 | # Function 24 | def hello do 25 | IO.puts("Hello, World!") 26 | end 27 | end 28 | ``` 29 | 30 | Function calls for nested modules are the same as for flat modules. First, we put the module's full name, then a function call. 31 | 32 | ```elixir 33 | HexletBasics.Application.hello() 34 | ``` 35 | 36 | There is a special module _Kernel_ which functions we can call directly. 37 | 38 | ```elixir 39 | is_number(13) # true 40 | ``` 41 | 42 | _Kernel_ contains basic language primitives for arithmetic operations, spawning processes, data type handling, macros for defining new functionality, and more. 43 | -------------------------------------------------------------------------------- /modules/55-processes/40-tasks-and-agents/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "calculator code unchanged" do 5 | test "adding" do 6 | assert Calculator.exec(:+, 2, 3) == 5 7 | assert Calculator.exec(:+, 10, 20) == 30 8 | end 9 | 10 | test "subtraction" do 11 | assert Calculator.exec(:-, 2, 3) == -1 12 | assert Calculator.exec(:-, 10, 20) == -10 13 | end 14 | 15 | test "multiply" do 16 | assert Calculator.exec(:*, 2, 3) == 6 17 | assert Calculator.exec(:*, 10, 20) == 200 18 | end 19 | 20 | test "division" do 21 | assert Calculator.exec(:/, 2, 3) == 0 22 | assert Calculator.exec(:/, 20, 10) == 2 23 | end 24 | end 25 | 26 | test "accumulator agent" do 27 | Accumulator.start_link(0) 28 | 29 | Accumulator.add(10) 30 | assert Accumulator.current() == 10 31 | Accumulator.add(3) 32 | assert Accumulator.current() == 13 33 | 34 | Accumulator.mul(10) 35 | assert Accumulator.current() == 130 36 | Accumulator.mul(3) 37 | assert Accumulator.current() == 390 38 | 39 | Accumulator.sub(10) 40 | assert Accumulator.current() == 380 41 | Accumulator.sub(3) 42 | assert Accumulator.current() == 377 43 | 44 | Accumulator.div(10) 45 | assert Accumulator.current() == 37 46 | Accumulator.div(3) 47 | assert Accumulator.current() == 12 48 | 49 | Accumulator.reset() 50 | assert Accumulator.current() == 0 51 | assert Agent.stop(Accumulator) == :ok 52 | end 53 | end 54 | -------------------------------------------------------------------------------- /modules/55-processes/35-links/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | В файле с решением описан модуль `Worker`. Для работы с ним, нужно создать и связать процесс с этим модулем следующим образом: 3 | 4 | ```elixir 5 | number = 5 6 | spawn_link(fn -> Worker.work(number) end) 7 | ``` 8 | 9 | После этого, `Worker` проверяет число по правилам классической задачи с собеседований `FooBar` и процесс завершается с соответствующим сигналом: 10 | - число кратно 3 и 5 - `:foobar`; 11 | - число кратно 3 - `:foo`; 12 | - число кратно 3 - `:bar`; 13 | - в ином случае процесс завершается в штатном режиме `:normal`. 14 | 15 | Создайте функцию `supervise_foobar` которая принимает число, вызывает `Worker` и на основе сигнала о завершении формирует строку, где вместо переданного числа подставляется `Foo`, `Bar`, `FooBar` либо ничего, затем число увеличивается на *единицу* и процесс проверки числа и сбора строки идет дальше. 16 | 17 | Если переданное число больше 100 или меньше 1, то продолжать сбор строки не нужно. Не забудьте о `Process.flag(:trap_exit, true)`, так как иначе не получится собрать информацию о сигналах завершения `Worker`. Примеры: 18 | 19 | ```elixir 20 | Solution.supervise_foobar(0) 21 | # => "" 22 | 23 | Solution.supervise_foobar(-10) 24 | # => "" 25 | 26 | Solution.supervise_foobar(11123) 27 | # => "" 28 | 29 | Solution.supervise_foobar(80) 30 | # => "Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar" 31 | 32 | Solution.supervise_foobar(100) 33 | # => "Bar" 34 | 35 | Solution.supervise_foobar(75) 36 | # => "FooBar Foo Bar Foo Foo Bar Foo FooBar Foo Bar Foo Foo Bar" 37 | ``` 38 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | import Solution 4 | 5 | test "keys_sum" do 6 | map = %{a: 1, b: 2, c: 42} 7 | assert keys_sum(map, :a, :b) == 3 8 | assert keys_sum(map, :a, :c) == 43 9 | assert keys_sum(map, :c, :b) == 44 10 | assert keys_sum(map, :a, :a) == 2 11 | assert keys_sum(map, :a, :d) == 1 12 | assert keys_sum(map, :d, :c) == 42 13 | assert keys_sum(map, :d, :e) == 0 14 | end 15 | 16 | test "keys_product" do 17 | map = %{one: 1, five: 5, ten: 10} 18 | assert keys_product(map, :one, :five) == 5 19 | assert keys_product(map, :one, :ten) == 10 20 | assert keys_product(map, :five, :ten) == 50 21 | assert keys_product(map, :five, :five) == 25 22 | assert keys_product(map, :five, :two) == 5 23 | assert keys_product(map, :two, :ten) == 10 24 | assert keys_product(map, :two, :three) == 1 25 | end 26 | 27 | test "copy_key" do 28 | map1 = %{a: 1, b: 2} 29 | map2 = %{c: 3, d: 4} 30 | assert copy_key(map1, map2, :a, 42) == %{c: 3, d: 4, a: 1} 31 | assert copy_key(map1, map2, :b, 42) == %{c: 3, d: 4, b: 2} 32 | assert copy_key(map1, map2, :e, 42) == %{c: 3, d: 4, e: 42} 33 | assert copy_key(map1, map2, :c, 42) == %{c: 42, d: 4} 34 | 35 | assert copy_key(map2, map1, :c, 42) == %{a: 1, b: 2, c: 3} 36 | assert copy_key(map2, map1, :d, 42) == %{a: 1, b: 2, d: 4} 37 | assert copy_key(map2, map1, :e, 42) == %{a: 1, b: 2, e: 42} 38 | assert copy_key(map2, map1, :b, 42) == %{a: 1, b: 42} 39 | end 40 | end 41 | -------------------------------------------------------------------------------- /modules/20-data-types/30-maps/ru/EXERCISE.md: -------------------------------------------------------------------------------- 1 | 2 | Реализуйте функцию `keys_sum`, которая принимает словарь и два ключа, извлекает значения по этим ключам, и возвращает сумму значений. Если ключа в словаре нет, то соответствующее значение не учитывается. 3 | 4 | Реализуйте функцию `keys_product`, которая принимает словарь и два ключа, извлекает значения по этим ключам, и возвращает произведение значений. Если ключа в словаре нет, то соответствующее значение не учитывается. 5 | 6 | Реализуйте функцию `copy_key`, которая принимает два словаря, ключ, и значение по умолчанию. По ключу нужно извлечь значение из первого словаря и вставить во второй словарь. Если в первом словаре нет такого ключа, то во второй словарь нужно вставить значение по умолчанию. Если во втором словаре уже есть такой ключ, то его значение меняется. 7 | 8 | ```elixir 9 | map = %{a: 1, b: 2, c: 42} 10 | Solution.keys_sum(map, :a, :b) 11 | # => 3 12 | Solution.keys_sum(map, :a, :c) 13 | # => 43 14 | Solution.keys_sum(map, :c, :b) 15 | # => 44 16 | 17 | map = %{one: 1, five: 5, ten: 10} 18 | Solution.keys_product(map, :one, :five) 19 | # => 5 20 | Solution.keys_product(map, :five, :ten) 21 | # => 50 22 | Solution.keys_product(map, :two, :ten) 23 | # => 10 24 | 25 | map1 = %{a: 1, b: 2} 26 | map2 = %{c: 3, d: 4} 27 | 28 | Solution.copy_key(map1, map2, :a, 42) 29 | # => %{c: 3, d: 4, a: 1} 30 | Solution.copy_key(map1, map2, :b, 42) 31 | # => %{c: 3, d: 4, b: 2} 32 | 33 | Solution.copy_key(map2, map1, :d, 42) 34 | # => %{a: 1, b: 2, d: 4} 35 | Solution.copy_key(map2, map1, :e, 42) 36 | # => %{a: 1, b: 2, e: 42} 37 | ``` 38 | -------------------------------------------------------------------------------- /modules/55-processes/55-process-registration/test/solution_test.exs: -------------------------------------------------------------------------------- 1 | defmodule Test do 2 | use ExUnit.Case 3 | 4 | describe "process register work" do 5 | test "list_registered work" do 6 | {:ok, _} = ProcessRegister.start_link() 7 | 8 | assert ProcessRegister.list_registered() == %{} 9 | end 10 | 11 | test "add work" do 12 | {:ok, _} = ProcessRegister.start_link() 13 | 14 | process = spawn(fn -> Process.sleep(:timer.seconds(10)) end) 15 | 16 | assert ProcessRegister.add(process, :some_process) == :ok 17 | assert %{some_process: ^process} = ProcessRegister.list_registered() 18 | 19 | second_process = spawn(fn -> Process.sleep(:timer.seconds(10)) end) 20 | 21 | assert ProcessRegister.add(second_process, :other_process) == :ok 22 | 23 | assert %{some_process: ^process, other_process: ^second_process} = 24 | ProcessRegister.list_registered() 25 | 26 | dead_process = spawn(fn -> 2 + 2 end) 27 | 28 | assert ProcessRegister.add(dead_process, :dead) == :ok 29 | 30 | assert %{some_process: ^process, other_process: ^second_process} = 31 | ProcessRegister.list_registered() 32 | end 33 | 34 | test "drop work" do 35 | {:ok, _} = ProcessRegister.start_link() 36 | 37 | process = spawn(fn -> Process.sleep(:timer.seconds(10)) end) 38 | 39 | ProcessRegister.add(process, :new_process) 40 | assert ProcessRegister.drop(:new_process) == :ok 41 | assert ProcessRegister.list_registered() == %{} 42 | 43 | assert ProcessRegister.drop(:not_existing_process) == :ok 44 | end 45 | end 46 | end 47 | --------------------------------------------------------------------------------