Blog/content/posts/2022/crystal/documenting-code.md

332 lines
12 KiB
Markdown
Raw Normal View History

2022-11-12 15:44:49 +03:00
---
title: "Документирование кода Crystal"
date: 2022-10-13T21:22:47+03:00
draft: true
tags: [crystal, tutorial, development]
---
## О статье
Это мой вольный перевод оригинальной
2023-06-25 21:11:33 +03:00
[статьи](https://crystal-lang.org/reference/1.8/syntax_and_semantics/documenting_code.html)
2022-11-12 15:44:49 +03:00
из документации по **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
```