Исходный код Введение в Mix
В этом руководстве мы создадим полное приложение Elixir с собственной иерархией управления, конфигурацией, тестами и многим другим.
Требования к этому руководству (см. elixir -v) :
- Elixir 1.15.0 и выше
- Erlang/OTP 24 и выше
Приложение работает как распределённый хранилище ключей-значений. Мы будем организовывать пары «ключ-значение» в корзины и распределять эти корзины по нескольким узлам. Мы также создадим простой клиент, который позволит нам подключаться к любому из этих узлов и отправлять запросы, такие как:
CREATE shopping OK PUT shopping milk 1 OK PUT shopping eggs 3 OK GET shopping milk 1 OK DELETE shopping eggs OK
Для создания нашего приложения «ключ-значение» мы будем использовать три основных инструмента:
OTP (Open Telecom Platform) — это набор библиотек, поставляемый с Erlang. Разработчики Erlang используют OTP для создания надёжных, устойчивых к ошибкам приложений. В этой главе мы рассмотрим, как многие аспекты OTP интегрируются с Elixir, включая иерархии управления, менеджеры событий и многое другое;
Mix — это инструмент сборки, поставляемый с Elixir, который предоставляет задачи для создания, компиляции, тестирования вашего приложения, управления его зависимостями и многим другим;
ExUnit — это фреймворк для модульного тестирования, поставляемый с Elixir.
В этой главе мы создадим наш первый проект с помощью Mix и изучим различные функции OTP, Mix и ExUnit по ходу работы.
Исходный код
Окончательный код приложения, созданного в этом руководстве, находится в этом репозитории и может использоваться в качестве справки.
Требуется ли чтение этого руководства?
Это руководство не является обязательным для изучения Elixir. Мы объясним почему.
Как разработчик Elixir, вы, скорее всего, будете использовать один из многих существующих фреймворков при написании кода Elixir. Phoenix охватывает веб-приложения, Ecto взаимодействует с базами данных, вы можете создавать встроенное программное обеспечение с помощью Nerves, Nx управляет проектами машинного обучения и искусственного интеллекта, Membrane собирает аудио/видео обработку, Broadway обрабатывает загрузку и обработку данных, и многое другое. Эти фреймворки обрабатывают низкоуровневые детали конкурентности, распределения и отказоустойчивости, поэтому вы, как пользователь, можете сосредоточиться на своих собственных потребностях и задачах.
С другой стороны, если вы хотите изучить основы, на которых построены эти фреймворки, и абстракции, которые питают экосистему Elixir, это руководство даст вам обзор нескольких важных концепций.
Наш первый проект
При установке Elixir, помимо получения elixir, elixirc, и iex исполняемых файлов, вы также получаете исполняемый скрипт Elixir под названием mix.
Давайте создадим наш первый проект, вызвав mix new из командной строки. Мы передадим путь к проекту в качестве аргумента (kv, в данном случае). По умолчанию имя приложения и имя модуля будут получены из пути. Поэтому мы сообщим Mix, что наш основной модуль должен быть KV, а не по умолчанию, которое было бы Kv:
$ mix new kv --module KV
Mix создаст каталог под названием kv с несколькими файлами в нём:
* creating README.md * creating .formatter.exs * creating .gitignore * creating mix.exs * creating lib * creating lib/kv.ex * creating test * creating test/test_helper.exs * creating test/kv_test.exs
Давайте кратко рассмотрим эти сгенерированные файлы.
Исполняемые файлы в PATH
Mix — это исполняемый файл Elixir. Это означает, что для запуска mix, вам необходимо иметь как mix, так и elixir исполняемые файлы в вашей переменной среды PATH. Именно это происходит при установке Elixir.
Компиляция проекта
Файл под названием mix.exs был сгенерирован внутри нашей новой папки проекта (kv) и его основная задача — настройка нашего проекта. Давайте посмотрим на него:
defmodule KV.MixProject do
use Mix.Project
def project do
[
app: :kv,
version: "0.1.0",
elixir: "~> 1.11",
start_permanent: Mix.env() == :prod,
deps: deps()
]
end
# Run "mix help compile.app" to learn about applications
def application do
[
extra_applications: [:logger]
]
end
# Run "mix help deps" to learn about dependencies
defp deps do
[
# {:dep_from_hexpm, "~> 0.3.0"},
# {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"},
]
end
end
Наш mix.exs определяет две публичные функции: project, которая возвращает конфигурацию проекта, такую как имя и версия проекта, и application, которая используется для генерации файла приложения.
Также есть частная функция под названием deps, которая вызывается из функции project, которая определяет зависимости нашего проекта. Определение deps как отдельной функции не требуется, но это помогает поддерживать аккуратность конфигурации проекта.
Mix также создаёт файл по адресу lib/kv.ex с модулем, содержащим ровно одну функцию, называемую hello:
defmodule KV do
@moduledoc """
Documentation for KV.
"""
@doc """
Hello world.
## Examples
iex> KV.hello()
:world
"""
def hello do
:world
end
end
Эта структура достаточна для компиляции нашего проекта:
$ cd kv $ mix compile
Выведет:
Compiling 1 file (.ex) Generated kv app
Файл lib/kv.ex был скомпилирован, и был сгенерирован манифест приложения под названием kv.app. Все артефакты компиляции размещаются в каталоге _build с использованием опций, определённых в файле mix.exs.
После компиляции проекта вы можете запустить сеанс iex внутри проекта, выполнив команду ниже. -S mix необходим для загрузки проекта в интерактивную оболочку:
$ iex -S mix
Мы будем работать над этим проектом kv, внося изменения и пробуя последние изменения из сеанса iex. Хотя вы можете запускать новый сеанс всякий раз, когда происходят изменения в исходном коде проекта, вы также можете перекомпилировать проект изнутри сеанса iex с помощью вспомогательной функции recompile, подобно этому:
iex> recompile() Compiling 1 file (.ex) :ok iex> recompile() :noop
Если что-то нужно было скомпилировать, вы увидите информацию, а затем получите атом :ok, иначе функция будет молчать и вернёт :noop.
Запуск тестов
Mix также сгенерировал соответствующую структуру для запуска тестов нашего проекта. Проекты Mix обычно следуют соглашению о наличии файла <filename>_test.exs в каталоге test для каждого файла в каталоге lib. По этой причине мы уже можем найти test/kv_test.exs соответствующий нашему файлу lib/kv.ex. Пока он не выполняет много действий:
defmodule KVTest do
use ExUnit.Case
doctest KV
test "greets the world" do
assert KV.hello() == :world
end
end
Важно отметить несколько моментов:
файл теста — это файл скрипта Elixir (
.exs). Это удобно, потому что нам не нужно компилировать файлы тестов перед их запуском;мы определяем модуль теста под названием
KVTest, в котором мыuse ExUnit.Caseдля вставки API тестирования;мы используем одну из импортированных макросов,
ExUnit.DocTest.doctest/1, чтобы указать, что модульKVсодержит doctests (мы рассмотрим их в следующей главе);мы используем макрос
ExUnit.Case.test/2для определения простого теста;
Mix также сгенерировал файл под названием test/test_helper.exs, который отвечает за настройку фреймворка тестирования:
ExUnit.start()
Этот файл будет необходим Mix каждый раз перед запуском тестов. Мы можем запускать тесты с помощью:
$ mix test Compiled lib/kv.ex Generated kv app Running ExUnit with seed: 540224, max_cases: 16 .. Finished in 0.04 seconds 1 doctest, 1 test, 0 failures
Обратите внимание, что при выполнении mix test, Mix повторно скомпилировал исходные файлы и сгенерировал манифест приложения. Это происходит потому, что Mix поддерживает несколько сред, о которых мы поговорим позже в этой главе.
Кроме того, вы можете видеть, что ExUnit печатает точку для каждого успешного теста и автоматически рандомизирует тесты. Давайте заставим тест намеренно потерпеть неудачу и посмотрим, что произойдёт.
Измените утверждение в test/kv_test.exs на следующее:
assert KV.hello() == :oops
Теперь снова запустите mix test (обратите внимание, что на этот раз компиляции не будет):
1) test greets the world (KVTest)
test/kv_test.exs:5
Assertion with == failed
code: assert KV.hello() == :oops
left: :world
right: :oops
stacktrace:
test/kv_test.exs:6: (test)
.
Finished in 0.05 seconds
1 doctest, 1 test, 1 failure
Для каждой неудачи ExUnit печатает подробный отчёт, содержащий имя теста с тестовым случаем, код, в котором произошла ошибка, и значения левой и правой части оператора ==.
На второй строке сообщения об ошибке, сразу под именем теста, указано место, где был определён тест. Если вы скопируете полное местоположение теста, включая файл и номер строки, и добавите его к mix test, Mix загрузит и запустит только этот конкретный тест:
$ mix test test/kv_test.exs:5
Этот ярлык будет чрезвычайно полезен при создании проекта, позволяя быстро итерировать, запуская один тест.
И, наконец, стек-трейс относится к самой ошибке, предоставляя информацию о тесте и часто о месте, где произошла ошибка внутри исходных файлов.
Автоматическая форматирование кода
Один из файлов, созданных mix new, — .formatter.exs. Elixir поставляется с форматировщиком кода, способным автоматически форматировать наш код в соответствии с согласованным стилем. Форматировщик запускается с помощью задачи mix format. Созданный файл .formatter.exs настраивает, какие файлы должны быть отформатированы, когда запускается mix format.
Чтобы попробовать форматировщик, измените файл в каталогах lib или test, добавив лишние пробелы или дополнительные переводы строк, например, def hello do, а затем запустите mix format.
Большинство редакторов предоставляют встроенную интеграцию с форматировщиком, позволяя форматировать файл при сохранении или с помощью заданного сочетания клавиш. Если вы изучаете Elixir, интеграция с редактором даёт полезную и быструю обратную связь при изучении синтаксиса Elixir.
Для компаний и команд мы рекомендуем запускать mix format --check-formatted на серверах непрерывной интеграции, гарантируя, что весь текущий и будущий код соответствует стандарту.
Дополнительную информацию о формате кода можно получить, прочитав документацию по задаче форматирования или ознакомившись с объявлением о выпуске Elixir v1.6, первой версии, включающей этот форматировщик.
Среды
Mix предоставляет концепцию "среды". Они позволяют разработчику настраивать компиляцию и другие параметры для конкретных сценариев. По умолчанию Mix понимает три среды:
-
:dev— среда, в которой по умолчанию выполняются задачи Mix (например,compile) -
:test— используется задачейmix test -
:prod— среда, которую вы будете использовать для запуска проекта в рабочей среде
Среда применяется только к текущему проекту. Как мы увидим в последующих главах, любая зависимость, которую вы добавите в свой проект, по умолчанию будет выполняться в среде :prod.
Настройка по средам может выполняться посредством доступа к Mix.env/0 в вашем файле mix.exs, который возвращает текущую среду как атом. Именно это мы использовали в опциях :start_permanent:
def project do
[
...,
start_permanent: Mix.env() == :prod,
...
]
end
Если значение опции :start_permanent равно true, ваше приложение запускается в постоянном режиме, что означает, что виртуальная машина Erlang аварийно завершит работу, если дерево управления приложения будет закрыто. Обратите внимание, что в средах разработки и тестирования мы не хотим этого поведения, так как полезно поддерживать экземпляр виртуальной машины работающим в этих средах для целей отладки.
Mix по умолчанию будет использовать среду :dev, за исключением задачи test, которая по умолчанию будет использовать среду :test. Среду можно изменить с помощью переменной среды MIX_ENV.
$ MIX_ENV=prod mix compile
Или на Windows:
> set "MIX_ENV=prod" && mix compile
Mix в рабочей среде
Mix — это инструмент для сборки, и, как таковой, его использование в рабочей среде не ожидается. Поэтому рекомендуется обращаться к Mix.env/0 только в конфигурационных файлах и внутри mix.exs, но никогда в коде вашего приложения (lib).
Изучение
Mix предоставляет гораздо больше возможностей, и мы продолжим его изучение по мере создания нашего проекта. Обзор доступен в документации Mix, и вы всегда можете вызвать задачу help, чтобы перечислить все доступные задачи:
$ mix help $ mix help compile
Теперь давайте перейдём к добавлению первых модулей и функций в наше приложение.
© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.18.1/introduction-to-mix.html