diff --git a/content/posts/2022/crystal/documenting-code.md b/content/posts/2022/crystal/documenting-code.md new file mode 100644 index 0000000..827498f --- /dev/null +++ b/content/posts/2022/crystal/documenting-code.md @@ -0,0 +1,331 @@ +--- +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 +```