Do you want to pick up from where you left of?
Take me there

Dokumentowanie kodu

Jak dokumentować kod Elixira.

Adnotacje

Nieważne, jak wiele komentarzy piszemy i jak dobra jest dokumentacja, to zawsze jej jakość będzie niewystarczająca. Pomimo to wszyscy wiemy, że dokumentacja jest istotna zarówno dla nas samych, jak i dla osób, które pracują lub będą pracować z naszym kodem.

Elixir traktuje dokumentację jako byt podstawowy (ang. first-class citizen), oferując zestaw funkcji pozwalających na generowanie i pracę z dokumentacją w projekcie. Elixir dostarcza wiele różnych rozwiązań na poziomie kodu do tworzenia dokumentacji. Przyjrzyjmy się trzem z nich:

Komentowanie kodu

Najprostszą metodą dokumentowania kodu są komentarze. Podobnie jak w Pythonie i Rubym, tak w Elixirze komentarz rozpoczyna się znakiem #, zwanym kratką albo hashem.

Popatrzymy na ten skrypt (greeting.exs):

# Outputs 'Hello, chum.' to the console.
IO.puts("Hello, " <> "chum.")

Gdy go uruchomimy, Elixir zignoruje wszystko od znaku # aż do końca linii, traktując jako nieistotny i nieinterpretowany element. Komentarz nie ma żadnej wartości ani nie wpływa na szybkość wykonania kodu, jednakże może pomóc innym zrozumieć nasz kod. Tego rodzaju komentarze powinny być używane z umiarem, ponieważ w dużej liczbie zaśmiecają kod i zamiast pomagać, mogą przeszkadzać, stając się dla niektórych koszmarem.

Dokumentowanie modułów

Adnotacja @moduledoc służy do dokumentowania modułów. Zazwyczaj umieszcza się ją w linii poniżej deklaracji defmodule na górze pliku. Poniższy przykład ilustruje użycie @moduledoc.

defmodule Greeter do
  @moduledoc """
  Zawiera funkcję `hello/1` do przywitania człowieka
  """

  def hello(name) do
    "Hello, " <> name
  end
end

Dostęp do dokumentacji modułu w IEx jest możliwy z pomocą polecenia h. Możemy to sprawdzić sami, umieszczając nasz moduł Greeter w nowym pliku, greeter.ex, a następnie go kompilując:

iex> c("greeter.ex", ".")
[Greeter]

iex> h Greeter

                Greeter

Provides a function hello/1 to greet a human

Uwaga: nie musimy ręcznie kompilować naszych plików, jak zrobiliśmy to powyżej, jeśli pracujemy w projekcie Mixa. W takim przypadku możemy użyć polecenia iex -S mix, by załadować konsolę IEx dla obecnego projektu.

Dokumentowanie funkcji

Elixir poza adnotacją pozwalającą na dokumentowanie modułów ma też adnotację służącą do dokumentowania poszczególnych funkcji. Adnotacja @doc pozwala na tworzenie wbudowanej dokumentacji na poziomie funkcji. Jest umieszczana nad dokumentowaną funkcją.

defmodule Greeter do
  @moduledoc """
  ...
  """

  @doc """
  Wyświetla wiadomość powitalną.

  ## Parametry

    - name: Łańcuch znaków reprezentujący imię osoby.

  ## Przykłady

      iex> Greeter.hello("Sean")
      "Hello, Sean"

      iex> Greeter.hello("pete")
      "Hello, pete"

  """
  @spec hello(String.t()) :: String.t()
  def hello(name) do
    "Hello, " <> name
  end
end

W IEx za pomocą polecenia h możemy też dostać się do dokumentacji funkcji:

iex> c("greeter.ex", ".")
[Greeter]

iex> h Greeter.hello

                def hello(name)

  @spec hello(String.t()) :: String.t()

Wyświetla wiadomość powitalną.

Parametry

   name: Łańcuch znaków reprezentujący imię osoby.

Przykłady

    iex> Greeter.hello("Sean")
    "Hello, Sean"

    iex> Greeter.hello("pete")
    "Hello, pete"

iex>

Zauważ, jak za pomocą znaczników umożliwiliśmy terminalowi sformatowanie dokumentacji. Poza tym, że fajnie to wygląda i jest nowatorskim rozwiązaniem w ekosystemie Elixira, to daje nam duże możliwości przy generowaniu HTML-a z pomocą narzędzia ExDoc.

Uwaga: adnotacja @spec jest używana do statycznej analizy kodu. Jeśli chcesz dowiedzieć się więcej na ten temat, zajrzyj do lekcji Specyfikacje i typy.

ExDoc

ExDoc jest oficjalnym projektem zespołu Elixira służącym do generowania HTML-a (HyperText Markup Language) i dokumentacji online dla projektów tworzonych w Elixirze, które można znaleźć na GitHub. Na początek stwórzmy nowy projekt Mixa:

$ mix new greet_everyone

* creating README.md
* creating .gitignore
* creating mix.exs
* creating lib
* creating lib/greet_everyone.ex
* creating test
* creating test/test_helper.exs
* creating test/greet_everyone_test.exs

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

    cd greet_everyone
    mix test

Run "mix help" for more commands.

$ cd greet_everyone

Teraz skopiujmy adnotację @doc do pliku lib/greeter.ex i upewnijmy się, że nadal działa on z linii poleceń. Jako że pracujemy z Mixem, uruchommy IEx korzystając z polecenia iex -S mix i wpiszmy:

iex> h Greeter.hello

                def hello(name)

  @spec hello(String.t()) :: String.t()

Wyświetla wiadomość powitalną.

Parametry

  • name: Łańcuch znaków reprezentujący imię osoby.

Przykłady

    iex> Greeter.hello("Sean")
    "Hello, Sean"

    iex> Greeter.hello("pete")
    "Hello, pete"

Instalacja

Jak możemy wnioskować z powyższego komunikatu, jesteśmy już gotowi, by skonfigurować ExDoc. W pliku mix.exs musimy dodać zależności :earmark i :ex_doc.

  def deps do
    [{:ex_doc, "~> 0.21", only: :dev, runtime: false}]
  end

Podając opcję only: :dev mówimy Mixowi, że nie chcemy pobierać i kompilować tych zależności na środowisku innym niż deweloperskie.

ex_doc doda również inną bibliotekę, Earmark.

Earmark jest parserem znaczników napisanym dla Elixira, służącym ExDocowi do zamiany dokumentacji z adnotacji @moduledoc i @doc na elegancki kod HTML.

Oczywiście nie jesteśmy ograniczeni tylko do Earmarka. Jak chcesz możesz zamienić go na Pandoc, Hoedown albo Cmark; to wymaga trochę dodatkowej konfiguracji, o której poczytasz tutaj (ang.). Na potrzeby tej lekcji pozostaniemy jednak przy Earmarku.

Generowanie dokumentacji

Idąc dalej w linii poleceń wydajemy dwie komendy:

$ mix deps.get # pobiera ExDoc + Earmark.
$ mix docs # generuje dokumentację.

Docs successfully generated.
View them at "doc/index.html".

Jeżeli wszystko poszło zgodnie z planem powinieneś zobaczyć komunikat taki jak wyżej. Jeżeli zajrzymy teraz do naszego projektu, to w katalogu doc/ odnajdziemy wygenerowaną dokumentację. Jeżeli otworzysz plik index.html w przeglądarce, powinieneś zobaczyć:

ExDoc Screenshot 1

Jak widać Earmark stworzył z naszych znaczników dokumentację, a ExDoc wyświetla ją w czytelny sposób.

ExDoc Screenshot 2

Możemy ją teraz umieścić na GitHubie, naszej stronie, albo w serwisie HexDocs.

Dobre praktyki

Zasady tworzenia dokumentacji powinny być opisane w przewodniku dobrych praktyk języka. Jako że Elixir jest jeszcze bardzo młodym językiem, to wiele elementów jego ekosystemu musi zostać zestandaryzowanych, co oznacza, że dobre praktyki dla dokumentacji są tworzone przede wszystkim przez społeczność programistów. Można o tym poczytać, w dokumencie TheElixir Style Guide.

defmodule Greeter do
  @moduledoc """
  To jest dobra dokumentacja.
  """

end
defmodule Greeter do
  @moduledoc false

end
defmodule Greeter do
  @moduledoc """
  ...

  Ten moduł zawiera również funkcję `hello/1`.
  """

  def hello(name) do
    IO.puts("Hello, " <> name)
  end
end
defmodule Greeter do
  @moduledoc """
  ...

  Ten moduł zawiera również funkcję `hello/1`.
  """

  alias Goodbye.bye_bye
  # and so on...

  def hello(name) do
    IO.puts("Hello, " <> name)
  end
end
defmodule Greeter do
  @moduledoc """
  ...
  """

  @doc """
  Wyświetla wiadomość powitalną.

  ## Parametry

    - name: Łańcuch znaków reprezentujący imię osoby.

  ## Przykłady

      iex> Greeter.hello("Sean")
      "Hello, Sean"

      iex> Greeter.hello("pete")
      "Hello, pete"

  """
  @spec hello(String.t()) :: String.t()
  def hello(name) do
    "Hello, " <> name
  end
end
Caught a mistake or want to contribute to the lesson? Edit this lesson on GitHub!