--- 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 ```