Własne funkcje Mix'a

Tworzenie własnych funkcji Mix’a dla projektów w Elixirze.

Wprowadzenie

Nie jest niczym niezwykłym chęć rozszerzenia funkcjonalności aplikacji napisanych w Elixirze poprzez dodanie własnych funkcji Mixa. Zanim zobaczymy jak to zrobić, przyjrzyjmy się jednej z już istniejących:

$ mix phx.new my_phoenix_app

* creating my_phoenix_app/config/config.exs
* creating my_phoenix_app/config/dev.exs
* creating my_phoenix_app/config/prod.exs
* creating my_phoenix_app/config/prod.secret.exs
* creating my_phoenix_app/config/test.exs
* creating my_phoenix_app/lib/my_phoenix_app.ex
* creating my_phoenix_app/lib/my_phoenix_app/endpoint.ex
* creating my_phoenix_app/test/views/error_view_test.exs
...

Jak możemy zobaczyć wyżej, framework Phoenix posiada własną funkcję do generowania nowego projektu. A co, jeśli chciałbyś mieć coś podobnego w swoim projekcie? Nie ma problemu — Elixir daje nam taką możliwość i czyni cały proces bardzo prostym do wykonania.

Konfiguracja

Utwórzmy prostą aplikację Mixa.

$ mix new hello

* creating README.md
* creating .formatter.exs
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/hello.ex
* creating test
* creating test/test_helper.exs
* creating test/hello_test.exs

Your Mix project was created successfully.
You can use "mix" to compile it, test it, and more:

cd hello
mix test

Run "mix help" for more commands.

A teraz, w pliku lib/hello.ex, który został dla nas wygenerowany, napiszmy funkcję, która wypisze na ekranie “Hello, World!”.

defmodule Hello do
  @doc """
  Wypisuje `Hello, World!`.
  """
  def say do
    IO.puts("Hello, World!")
  end
end

Własne funkcje Mixa

Stwórzmy własną funkcję Mixa. Najpierw utwórz nowy katalog i plik hello/lib/mix/tasks/hello.ex. W tym pliku zamieść poniższy kod:

defmodule Mix.Tasks.Hello do
  @moduledoc "The hello mix task: `mix help hello`"
  use Mix.Task

  @shortdoc "Wywołuje funkcję Hello.say/0."
  def run(_) do
    # Wywołanie funkcji Hello.say(), którą wcześniej napisaliśmy
    Hello.say()
  end
end

Zwróć uwagę na instrukcję defmodule — nazwę, której chcemy używać w wierszu poleceń, poprzedamy prefiksem Mix.Tasks. W drugiej linii wprowadzamy use Mix.Task, co pozwala nam skorzystać z zachowania Mix.Task w przestrzeni nazw. Następnie definiujemy funkcję run, w której ignorujemy przekazywany argument. W ciele tej funkcji wołamy funkcję say z naszego modułu Hello.

Ładowanie aplikacji

Mix nie uruchamia automatycznie naszej aplikacji ani żadnych jej zależności, co jest w porządku w większości przypadków użycia funkcji Mixa. Co jednak, jeśli potrzebujemy użyć Ecto i pracować z bazą danych? W tym przypadku powinniśmy się upewnić, że aplikacja stojąca za Ecto.Repo została uruchomiona. Są dwa sposoby, by to osiągnąć: możemy bezpośrednio uruchomić tę aplikację lub uruchomić nasz program, który z kolei uruchomi pozostałe.

Spójrzmy, jak możemy zmienić napisaną przez nas funkcję Mixa tak, by uruchomiła naszą aplikację i jej zależności:

defmodule Mix.Tasks.Hello do
  @moduledoc "The hello mix task: `mix help hello`"
  use Mix.Task

  @shortdoc "Wywołuje funkcję Hello.say/0."
  def run(_) do
    # To polecenie uruchomi naszą aplikację
    Mix.Task.run("app.start")

    Hello.say()
  end
end

Funkcje Mixa w akcji

Wypróbujmy naszą nową funkcję Mixa. Dopóki jesteśmy katalogu głównym naszego projektu, wszystko powinno działać. Z wiersza poleceń wywołajmy komendę mix hello, powinniśmy zobaczyć:

$ mix hello
Hello, World!

Mix jest bardzo przyjazny w użyciu. Wie, że każdy może popełnić literówkę, więc używa techniki zwanej dopasowaniem rozmytym (ang. fuzzy string matching), by w takim przypadku podpowiedzieć nam właściwą komendę:

$ mix hell
** (Mix) The task "hell" could not be found. Did you mean "hello"?

Zwróciłeś uwagę, że wykorzystaliśmy nowy atrybut modułu, @shortdoc? Jest on bardzo pomocny przy dystrybuowaniu aplikacji, szczególnie gdy użytkownik skorzysta z komendy mix help w konsoli.

$ mix help

mix app.start         # Starts all registered apps
...
mix hello             # Simply calls the Hello.say/0 function.
...

Uwaga: Nasz kod musi być skompilowany, zanim nowe funkcje pojawią się w informacji zwracanej przez mix help. Możemy to zrobić zarówno używając wprost polecenia mix compile, jak i wywołując naszą funkcję, tak jak zrobiliśmy to z mix hello, co uruchomi dla nas proces kompilacji.

Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!