332 lines
12 KiB
Markdown
332 lines
12 KiB
Markdown
---
|
||
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
|
||
```
|