---
title: "Документирование кода Crystal"
date: 2022-10-13T21:22:47+03:00
draft: true
tags: [crystal, tutorial, development]
---

## О статье

Это мой вольный перевод оригинальной
[статьи](https://crystal-lang.org/reference/1.8/syntax_and_semantics/documenting_code.html)
из документации по **Crystal**.

> Если есть желание внести правки, пожалуйста пишите.  
> Если остались вопросы, также пишите.

## Документирование кода

Документация для функций API может быть написана в комментариях к коду, непосредственно предшествующих определению соответствующей функции.

По умолчанию все общедоступные методы, макросы, типы и константы считаются частью документации API.

Команда компилятора `crystal docs` автоматически извлекает документацию API и создает веб-сайт для её представления.

## Ассоциация

Комментарии должны располагаться непосредственно над документируемым объектом.  
Последовательные строки комментариев объединяются в один блок комментариев.  
Любая пустая строка разрывает связь с задокументированным объектом.

```crystal
# Этот комментарий не связан с классом.

# Первая строка документации для класса Unicorn.
# Вторая строка документации для класса Unicorn.
class Unicorn
end
```

## Форматирование

Комментарии документации поддерживают
[Markdown](https://daringfireball.net/projects/markdown/) форматирование.

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

Дополнительные сведения и инструкции по использованию должны содержаться в последующих параграфах.

Напрмиер:

```crystal
# Возвращает количество рогов, которые есть у этого единорога.
#
# Всегда возвращает `1`.
def horns
  1
end
```

Рекомендуется использовать в написании комментариев настоящее время от третьего лица:  
"_Возвращает количество рогов, которые есть у этого единорога_".

## Разметка

### Linking

Ссылки на другие функции API могут быть заключены в знаки апострофа.
Они автоматически преобразуются в ссылки на соответствующую функцию.

```crystal
class Unicorn
  # Создает новый экземпляр `Unicorn`.
  def initialize
  end
end
```

Правила поиска применяются те же, что и в Crystal code. К функциям в задокументированном в настоящее время пространстве имен можно получить доступ по относительными именами:

* На методы экземпляра ссылаются с помощью хэш-префикса: `#horns`.
* На методы класса ссылаются с помощью префикса точки: `.new`.
* На константы и типы ссылаются по их имени: `Unicorn`.

На объекты в других пространствах имен ссылаются с помощью полного пути к типу: `Unicorn#horns`, `Unicorn.new`, `Unicorn::CONST`.

Различные перегрузки метода могут быть идентифицированы по полной сигнатуре `.new(name)`, `.new(name, age)`.

### Параметры

При обращении к параметрам рекомендуется писать их название курсивом (`*выделено_курсивом*`):

```crystal
# Создает единорога с указанным количеством *рогов*.
def initialize(@horns = 1)
  raise "Не единорог" if @horns != 1
end
```

### Примеры кода

Примеры кода могут быть размещены в блоках кода Markdown.  
Если языковой тег не указан, блок кода считается кодом на языке Crystal.

```crystal
# Пример:
# ```
# unicorn = Unicorn.new
# unicorn.horns # => 1
# ```
class Unicorn
end
```

Чтобы обозначить блок кода как обычный текст, он должен быть явно помечен тегом.

```crystal
# Вывод:
# ```plain
# "Я единорог"
# ```
def say
  puts "Я единорог"
end
```

Также можно использовать другие языковые теги.

Чтобы отобразить значение выражения внутри блоков кода, используйте `# =>`.

```crystal
1 + 2             # => 3
Unicorn.new.speak # => "Я единорог"
```

### Предупреждения

Поддерживаются несколько ключевых слов-предупреждений для визуального выделения проблем,
заметок и/или возможных проблем.

* `BUG`
* `DEPRECATED`
* `EXPERIMENTAL`
* `FIXME`
* `NOTE`
* `OPTIMIZE`
* `TODO`
* `WARNING`

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

```crystal
# Заставляет единорога говорить в STDOUT
#
# NOTE: Хотя единороги обычно не разговаривают, этот особенный
# TODO: Проверить, спит ли единорог, и вызвать исключение, если он не может говорить
# TODO: Создать другой метод `speak`, который принимает и печатает строку
def speak
  puts "Я единорог"
end

# Заставляет единорога говорить в STDOUT
#
# DEPRECATED: Используйте `speak`
def talk
  puts "Я единорог"
end
```

Компилятор неявно добавляет некоторые предостережения к комментариям документации:

* Аннотация `@[Deprecated]` добавляет предупреждение `DEPRECATED`.
* Аннотация `@[Experimental]` добавляет предупреждение `EXPERIMENTAL`.

## Директивы

Директивы сообщают генератору документации, как обращаться с документацией для конкретной функции.

### `ditto`

Если два последовательно определенных объекта имеют одинаковую документацию,
`:ditto:` можно использовать для копирования одного и того же комментария к документу
из предыдущего определения.

```crystal
# Возвращает количество рогов.
def horns
  horns
end

# :ditto:
def number_of_horns
  horns
end
```

Директива должна быть в отдельной строке, но дополнительная документация
может быть добавлена в других строках.
Директива `:ditto:` просто заменяется содержимым предыдущего комментария к документу.

### `nodoc`

Общедоступные функции могут быть скрыты из документов API с помощью директивы `:nodoc:`.
Частные и защищенные функции всегда скрыты.

```crystal
# :nodoc:
class InternalHelper
end
```

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

### `inherit`

_Смотри [Наследование документации](#наследование-документации)_.

## Наследование документации

Когда метод экземпляра не имеет комментария документации,
но метод с такой же сигнатурой существует в родительском типе,
документация наследуется от родительского метода.

Пример:

```crystal
abstract class Animal
  # Возвращает имя из `self`.
  abstract def name : String
end

class Unicorn < Animal
  def name : String
    "единорог"
  end
end
```

Документация для `Unicorn#name` была бы:

```text
Описание скопировано из класса `Animal`

Возвращает имя из `self`.
```

The child method can use `:inherit:` to explicitly copy the parent's documentation, without the `Description copied from ...` text. `:inherit:` can also be used to inject the parent's documentation into additional documentation on the child.

Пример:

```crystal
abstract class Parent
  # Некоторая документация, общая для каждого *id*.
  abstract def id : Int32
end

class Child < Parent
  # Some documentation specific to *id*'s usage within `Child`.
  #
  # :inherit:
  def id : Int32
    -1
  end
end
```

Документация для `Child#id` была бы:

```text
Some documentation specific to *id*'s usage within `Child`.

Some documentation common to every *id*.
```

> Наследование документации работает только с методами экземпляра, не являющимися конструкторами.

## Полный пример

```crystal
# A unicorn is a **legendary animal** (see the `Legendary` module) that has been
# described since antiquity as a beast with a large, spiraling horn projecting
# from its forehead.
#
# To create a unicorn:
#
# ```
# unicorn = Unicorn.new
# unicorn.speak
# ```
#
# The above produces:
#
# ```text
# "I'm a unicorn"
# ```
#
# Check the number of horns with `#horns`.
class Unicorn
  include Legendary

  # Creates a unicorn with the specified number of *horns*.
  def initialize(@horns = 1)
    raise "Not a unicorn" if @horns != 1
  end

  # Returns the number of horns this unicorn has
  #
  # ```
  # Unicorn.new.horns # => 1
  # ```
  def horns
    @horns
  end

  # :ditto:
  def number_of_horns
    horns
  end

  # Makes the unicorn speak to STDOUT
  def speak
    puts "I'm a unicorn"
  end

  # :nodoc:
  class Helper
  end
end
```
