Создание структурированной документации из прокомментированного кода

#asciidoc #asciidoctor

#asciidoc #asciidoctor

Вопрос:

Как мне получить Asciidoc (tor) для генерации, например. хорошее общее описание функции из нескольких комментариев к коду и некоторого кода, включая сигнатуру функции, без использования тегов в моем коде?

AFAIK Asciidoc поддерживает только внешние включения в свой файл Asciidoc через окружающие теги в коде, например

 # tag::mytag[] 
<CODE TO INCLUDE HERE>
# end::mytag[]
 

что было бы довольно шумно вокруг каждого описывающего комментария в теле одной функции и вокруг каждой подписи функции.
Возможно, существует экзотический, менее подробный способ, например, пометка однострочных комментариев «нравится #! » и однострочных тегов, которые указывают Asciidoctor читать только одну строку относительно этих тегов.

Рассмотрим этот крошечный пример.

 def uber_func(to_uber: str) -> str:
    """
    This is an overall description. Delivers some context.
    """

    # Trivial code here

    # To uber means <include code below>
    result = to_uber   " IS SOOO "   to_uber   "!!!"

    # Trivial code here

    # Function only returns upper case.
    return result.upper()
 

Мой наивный подход Asciidoc для включения всех значимых комментариев, строки документа и подписи функции из приведенного выше кода выглядел бы ужасно, плюс Asciidoc не распознает и не удаляет метки комментариев, поэтому результирующая документация тоже может быть не такой красивой.

Вместо этого очень некрасиво

 # tag::uber_func[]
def uber_func(to_uber: str) -> str:
    """
    This is an overall description. Delivers some context.
    """
# end::uber_func[]

    # Trivial code here

    # tag::uber_func[]
    # To uber means
    result = to_uber   " IS SOOO "   to_uber   "!!!"
    # end::uber_func[]

    # Trivial code here

    # tag::uber_func[]
    # Function only returns upper case.
    # end::uber_func[]
    return result.upper()
 

Я хотел бы использовать что-то вроде (псевдо):

 def uber_func(to_uber: str) -> str:
    # tag::uber_func[readline:-1,ignore-comment-marks,doc-comment:#!]
    #! This is an overall description. Delivers some context.

    # Trivial code here

    #! To uber means
    # tag::uber_func[readline: 1]
    result = to_uber   " IS SOOO "   to_uber   "!!!"

    # Trivial code here

    #! Function only returns upper case.
    return result.upper()
    # end::uber_func[]
 

Я думаю, что общая проблема заключается в том, что Asciidoc — это просто инструмент форматирования текста, а это значит, что если я хочу, чтобы он генерировал структурированную документацию в основном из моего кода, мне нужно будет предоставить эту структуру в моем коде и в моем файле .adoc.
Генераторы документации, такие как Doxygen, с другой стороны, автоматически распознают эту структуру и документирующие комментарии.
Я очень ценю эту функцию, так как некоторые генераторы позволяют вам писать код и красивую документацию бок о бок, что значительно снижает общие усилия.
Если Asciidoc не позволяет мне сделать это разумным способом, мне придется искать что-то другое.

Ответ №1:

Я думаю, вам нужно было бы написать скребок, который помещает комментарии в структуру, а затем переносит эту структуру в ваш AsciiDoc. Таким образом, комментарии могут быть внутренне отформатированы с помощью разметки AsciiDoc, и вы можете выводить их в сгенерированных Asciidoctor документах, но вам не понадобится Asciidoctor для непосредственного чтения исходных файлов.

Я бы попробовал использовать систему # для комментариев, не публикуемых, и ## для комментариев, которые вы хотите опубликовать, или наоборот, или добавить a # к тем, которые предназначены для публикации документов. А также те, которые обозначены """ обозначением. Затем ваш скребок может прочитать имя блока ( uber_func или любую другую важную часть), а затем очистить комментарии хранителя и весь буквальный код, расположив их все в файле. В приведенном ниже файле большинство комментариев помечено как text , комментарии, не относящиеся к хранителю, удалены, а содержимое без комментариев — как code :

 # tag::function__uber_func[]
# tag::function__uber_func_form[]
uber_func(to_uber: str) -> str:
# end::function__uber_func_form[]
# tag::function__uber_func_desc[]
This is an overall description. Delivers some context.
# end::function__uber_func_desc[]
# tag::function__uber_func_body[]
# tag::function__uber_func_text[]
To uber means
# end::function__uber_func_text[]
# tag::function__uber_func_code[]
----
result = to_uber   " IS SOOO "   to_uber   "!!!"
----
# end::function__uber_func_code[]
# tag::function__uber_func_text[]
Function only returns upper case.
# end::function__uber_func_text[]
# tag::function__uber_func_code[]
----
return result.upper()
----
# end::function__uber_func_code[]
# end::function__uber_func[]
 

Я знаю, что это выглядит отвратительно, но это очень полезно для шаблона AsciiDoc. Например, используйте только:

 uber_func::
include::includes/api-stuff.adoc[tags="function__uber_func_form"]
 
include::includes/api-stuff.adoc[tags="function__uber_func_desc"]
 
include::includes/api-stuff.adoc[tags="function__uber_func_body"] 
 

Это было бы еще лучше, если бы вы проанализировали его в формате данных (например, JSON или YAML), а затем динамически вставили его в шаблон AsciiDoc. Но вы могли бы поддерживать что-то вроде вышеупомянутого, если бы оно не было слишком массивным. При определенном размере (20 таких записей?) вам нужен промежуточный источник данных (эфемерный файл данных, созданный в результате очистки), и в определенном большем масштабе (> 100 блоков кода / конечных точек?), Вам, вероятно, понадобится система, специализирующаяся на документации API, такая как Doxygen и др.