Blog/content/posts/2022/crystal/documenting-code.md
2022-11-12 15:44:49 +03:00

332 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: "Документирование кода Crystal"
date: 2022-10-13T21:22:47+03:00
draft: true
tags: [crystal, tutorial, development]
---
## О статье
Это мой вольный перевод оригинальной
[статьи](https://crystal-lang.org/reference/1.6/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
```