Spec-Zone.ru › Elixir 1.18

Исходный код Введение в 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

Важно отметить несколько моментов:

  1. файл теста — это файл скрипта Elixir (.exs). Это удобно, потому что нам не нужно компилировать файлы тестов перед их запуском;

  2. мы определяем модуль теста под названием KVTest, в котором мы use ExUnit.Case для вставки API тестирования;

  3. мы используем одну из импортированных макросов, ExUnit.DocTest.doctest/1, чтобы указать, что модуль KV содержит doctests (мы рассмотрим их в следующей главе);

  4. мы используем макрос 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

Теперь давайте перейдём к добавлению первых модулей и функций в наше приложение.

← Предыдущая страница Языки доменной области (DSL)
Следующая страница → Простое управление состоянием с агентами

Загрузить версию ePub

Создано с помощью ExDoc (v0.36.1) для языка программирования Elixir

© 2012-2024 The Elixir Team
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.18.1/introduction-to-mix.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API