Исходный код Введение в 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
Давайте кратко рассмотрим эти сгенерированные файлы.
Исполняемые файлы в
PATHMix — это исполняемый файл 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 обычно следуют соглашению о том, что в директории test для каждого файла в каталоге lib находится файл <filename>_test.exs. По этой причине мы уже можем найти 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 .. Finished in 0.04 seconds 1 doctest, 1 test, 0 failures Randomized with seed 540224
Обратите внимание, что, запустив 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
При значении true опция :start_permanent запускает ваше приложение в постоянном режиме, что означает, что виртуальная машина Erlang (Erlang VM) завершит работу, если дерево наблюдения приложения завершится. Обратите внимание, что такого поведения мы не хотим в средах разработки и тестирования, так как полезно поддерживать экземпляр виртуальной машины (VM) в этих средах для целей отладки.
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.16.3/introduction-to-mix.html