[Из песочницы] Создание Elixir-приложения на примере. От инициализации до публикации

image


Пишу данную статью для того, чтобы закрепить знания полученные в процессе изучения языка Elixir и его инфраструктуры. Надеюсь, что данная статья будет полезна программистам решившим писать Elixir-приложения.


Вступление


«Elixir — динамический, функциональный язык программирования, разработанный для создания масштабируемых и легко поддерживаемых систем.» — elixir-lang.org


Используя Elixir для создания ваших приложений вы обязательно столкнётесь с Mix. Он станет вам незаменимым помощником, так как через него вы сможете выполнять такие команды как создание, сборка, тестирование и публикация приложений, а также управление зависимостями и многое другое. Если вы знакомы с Ruby, то этот инструмент очень похож на Bundler, RubyGems и Rake, вместе взятые. В двух словах Mix — это удобный инструмент, который поставляется с Elixir и выполняет не меньше задач, чем швейцарский нож.


Инициализация нового приложения


Шаблон своего будущего mix-приложения проще всего создать с использованием команды 'mix new app_name'.


$ mix new quadratic_equation

Данная команда создаст своего рода скелет вашего приложение. А именно папку с названием quadratic_equation и следующей структурой файлов и папок:


.gitignore                    # список файлов игнорируемых гитом
README.md                     # описание приложения в markdown стиле
config/
  config.exs                  # конфигурации приложения и зависимостей
lib/
  quadratic_equation.ex       # модуль верхнего уровня вашего приложения
mix.exs                       # mix-файл c перечнем внешних зависимостей
test/
  quadratic_equation_test.exs # тесты на модуль верхнего уровня
  test_helper.exs             # конфигурации и вспомогательные средства тестов

Есть несколько соглашений об именах и содержании файлов, знание которых вам пригодятся:


  • Используйте имя главного модуля приложения в именах подмодулей для уменьшения вероятности коллизии имен;
  • Каждый модуль должен располагаться в отдельном файле, и обратное, каждый файл должен содержать один модуль;
  • Имена файлов должны быть в snake_case стиле;
  • Имена модулей должны быть в CamelCase стиле;
  • Структура папок должна повторять именную структуру модулей.

Соблюдайте принятую структуру в приложениях, и это позволит компилятору осуществлять загрузку кода без лишних ошибок.


Тестирование приложения


Для размещения тестов при генерации нового mix-приложения была создана папка test/. Тестирование приложения является важной (но не неотъемлемой) частью написания работоспособного (но не обязательно качественного) кода.


Запуск тестов производится командой mix test из корневой папки приложения, для более информативного вывода используется опция --trace.


$ mix test --trace

Это команда также создаст папку _build и скомпилирует в неё ваше приложение в тестовой среде поместив всё .beam файлы.


Сборка и запуск приложения в iex


iex — это интерактивная консоль для работы с приложениями поставляемая вместе с Elixir. Относительно Ruby это аналог irb.


Запустить mix-приложение можно с помощью команды iex -S mix. Данная команда предварительно скомпилирует ваш код, если это требуется, и запустит интерактивную консоль, подгрузив в неё ваше приложение.


$ iex -S mix
Erlang/OTP 19 [erts-8.1] [source-e7be63d] [64-bit] [async-threads:10] [hipe] [kernel-poll:false]

Interactive Elixir (1.3.4) - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> 

Отдельно скомпилировать ваше приложение можно командой mix compile.


Написание кода приложения


В силу простоты приложения, весь код мы будем размещать в теле модуля верхнего уровня, а именно в QuadraticEquation.


# lib/quadratic_equation.ex

defmodule QuadraticEquation do
  @moduledoc """
    The module with the logic of the solution of the quadratic equation
  """

end

Для поставленной задачи, нам потребуется 1 публичная и несколько приватных функций. Публичная функция будет содержать логику решения уравнения, а приватные функции будут выводить на экран исходное квадратное уравнение и варианты полученных решений.


Пожалуй начнём с написания тестов. Как раз определимся с вариантами ответов нашего публичного метода. Тесты мы будем размещать в специальном файле сгенерированным для модуля верхнего уровня.


# test/quadratic_equation_test.exs

defmodule QuadraticEquationTest do
  use ExUnit.Case
  doctest QuadraticEquation

end

Из курса школы мы помним, что квадратное уравнение имеет два, иногда одинаковых, корня, или не имеет решения вовсе.


# test/quadratic_equation_test.exs

defmodule QuadraticEquationTest do
  use ExUnit.Case
  doctest QuadraticEquation

  test "when discriminant less than zero" do
    assert QuadraticEquation.calculation(1, 2, 3) ==
      {:fail, [error: "Discriminant less than zero!"]}
  end

  test "when discriminant equal zero" do
    assert QuadraticEquation.calculation(2, 4, 2) ==
      {:success, [x1: -1.0, x2: -1.0, d: 0.0]}
  end

  test "when discriminant more than zero" do
    assert QuadraticEquation.calculation(2, 3, 1) ==
      {:success, [x1: -0.5, x2: -1.0, d: 1.0]}
  end
end

Не будем запускать тесты прямо сейчас, для начала определим функцию calculation в QuadraticEquation. Данная функция будет принимать три числовых значения, а именно переменные a, b и с присущие квадратному уравнению в традиционной форме записи.


# lib/quadratic_equation.ex

...
@doc """
  See the description of the module.
"""
def calculation(a, b, c) do
end
...

Теперь запустим тесты и удостоверимся, что они не прошли.


Добавим решение квадратного уравнения в нашу функцию. А также укажем ожидаемые нашими тестами возвращаемые значения функции.


# lib/quadratic_equation.ex

...
def calculation(a, b, c) do
  # print_equation(a, b, c)

  d = :math.pow(b, 2) - 4 * a * c

  if d >= 0 do
    x1 = (-1 * b + :math.sqrt(d)) / (2 * a)
    x2 = (-1 * b - :math.sqrt(d)) / (2 * a)

    # print_success(x1, x2, d)

    {:success, [x1: x1, x2: x2, d: d]}
  else
    # print_fail(d)

    {:fail, [error: "Discriminant less than zero!"]}
  end
end
...

Приватные функции определяются с помощью следующей конструкции …


defp method_name do
end

Не буду приводить приватные методы в статье, они есть в исходном коде примера на GitHub.com.


Примечание. Аннотации @moduledoc и @doc необходимы для развёрнутого описания сути модуля и для описания сути функции.


Создание mix задачи


Написание задачи для данного примера кода не является обязательной, но для статьи в общем данная часть будет полезна.


В mix-приложениях все задачи принято располагать в отведённой для этого папке lib/mix/tasks. Так что первым делом добавьте эту папку себе в приложение.


$ mkdir -p lib/mix/tasks

Затем создайте в данной папке для задач файл с именем содержащим имя основного модуля приложения и название задачи.


$ touch lib/mix/tasks/quadratic_equation.example.ex

Задача будет не сложной, в её обязанности входит вызов функции calculation модуля QuadraticEquation.


# lib/mix/tasks/quadratic_equation.example.ex

defmodule Mix.Tasks.QuadraticEquation.Example do
  use Mix.Task

  @shortdoc "QuadraticEquation. Example of calculation."

  def run(_) do
    QuadraticEquation.calculation(2, 3, 1)
  end
end

Аннотация @shortdoc необходима как для краткого описания сути вашей задачи, так и для того, чтобы она начала отображаться в списке вывода команды mix help.


$ mix help

Публикация приложения в Hex


Hex — библиотека Erlang и Elixir приложений.


Перед тем как опубликовать своё mix-приложение в mix.exs файл необходимо добавить описание и метаданные проекта. Часть метаданных была сгенерирована автоматически командой mix new ....


# mix.exs

@version "0.1.0"

def project do
  [app: :quadratic_equation,
   version: @version,
   elixir: "~> 1.3",
   build_embedded: Mix.env == :prod,
   start_permanent: Mix.env == :prod,
   package: package,
   homepage_url: "https://hexdocs.pm/quadratic_equation",
   source_url: "https://github.com/folklore/quadratic_equation",
   description: "Example of creating a Mix-application - from initialization to publication.",
   deps: deps]
end

def package do
  [name: :quadratic_equation,
   files: ["lib", "mix.exs"],
   maintainers: ["Stanislav Gordanov"],
   licenses: ["MIT"],
   links: %{"Github" => "https://github.com/folklore/quadratic_equation"}]
end

Для публикации вам также потребуется профиль на hex.pm. Если у вас его ещё нет, то самый простой способ его создания, это воспользоваться командой …


$ mix hex.user register

Вам потребуется указать username, email и пароль. А также подтвердить введённый вами email пройдя по ссылке из отправленного вам письма.


Перед тем как мы к публикации приложения, нам нужно сгенерировать документацию. В случае, если вы не достаточно покрыли ваш код описанием, напоминаю, что модули документируются с помощью @moduledoc, а функции с помощью @doc.


Вы также можете добавить в документацию README файл, для этого включите его в конфигурацию приложения.


# mix.exs

def project do
  [#...
   docs: [extras: ["README.md"]]
  ]
end

Для генерации документации используйте команду …


$ mix docs

Когда все предварительные шаги сделаны, можно приступить к публикации приложения в пакетный менеджер. Сама публикация не замысловата, и производится следующей командой …


$ mix hex.publish

Теперь ваше приложение доступно по адресу https://hex.pm/packages/quadratic_equation.


Заключение


Как вы можете видеть генерация скелета приложения с помощью Mix дело не хитрое, так же как и его публикация в менеджер пакетов. Писать свои приложения на Elixir не так уж и сложно. Изучайте язык, находите идеи и реализуйте их. Вперёд!


Литература


» Introduction to Mix
» Organising your Elixir project with Mix
» Create a Mix Task for an Elixir Project
» Write and publish your first Elixir library
» Writing and Publishing an Elixir Library
» Creating Elixir libraries as OTP applications
» Elixir With José Valim | Protal
» Quadratic equation

Комментарии (0)

© Habrahabr.ru