Poursuivant le sujet de l'utilisation d'Asciidoc (et d'autres formats similaires) pour organiser des processus de documentation en continu, je souhaite aborder le sujet de la génération automatique de documentation technique.
La génération automatique de documentation est un terme courant mais très vague. J'entends par ce terme extraction pour présentation sous une forme pratique des informations contenues dans le code source et les paramètres du programme documenté (système d'information).
Schéma général de génération automatique de documentation
, ,  —  . .
- . , . , - , , , , .  —  , JSON/YAML XML;
- ( Asciidoc, DITA, Docbook, Markdown, reStructuredText).
, (html, docx, odt, pdf ..) ( ) . , ? , . .
:
, -. Asciidoc, (reStructuredText, Markdown), ( kroki, ).
. .
, , ( Javadoc, ReST ..) .
, , , . . . , . .
.
(, , ..), .
.  — . , Junit xml report. , , ,  — Allure Framework.
, , —  . , .
(, xsd-, OpenAPI, DSL , ).
, , ( «flatten»).
( ) , .
 — 
, .
, . , , , , . .
create table geo.Strana ( id int , naimenovaniye varchar(255) , primary key (id) ); create table geo.Gorod ( id int , naimenovaniye varchar(255) , strana_id int , constraint strana_gorod foreign key (strana_id) references geo.Strana(id) );
( PostgreSQL): JSON- .
drop table if exists fk; select x.table_schema as table_schema , x.table_name , y.table_schema as foreign_table_schema , y.table_name as foreign_table_name into temp fk from information_schema.referential_constraints rc join information_schema.key_column_usage x on x.constraint_name = rc.constraint_name join information_schema.key_column_usage y on y.ordinal_position = x.position_in_unique_constraint and y.constraint_name = rc.unique_constraint_name;
select json_agg(json_build_object( 'name', t.table_schema || '.' || t.table_name , 'columns' , (select json_agg(json_build_object ( 'name', column_name ,'type', data_type )) from information_schema.columns as c where c.table_name = t.table_name and c.table_schema = t.table_schema ) , 'fk' , (select json_agg(json_build_object ( 'fk_table' , fk.foreign_table_schema || '.' || fk.foreign_table_name )) from fk where fk.table_name = t.table_name and fk.table_schema = t.table_schema ) )) from information_schema.tables as t where table_schema = 'geo';
JSON-:
[{ "name": "geo.Strana", "columns": [{ "name": "id", "type": "integer" }, { "name": "naimenovaniye", "type": "character varying" } ], "fk": null }, { "name": "geo.Gorod", "columns": [{ "name": "id", "type": "integer" }, { "name": "naimenovaniye", "type": "character varying" }, { "name": "strana_id", "type": "integer" } ], "fk": [{ "fk_table": "geo.Strana" } ] } ]
, .
,
. , .
, , .
( ) XSLT.  — Mustache.
. , Excel ods .
, , 2003 XSLT , , Ruby. 18 , , XSLT , .
Liquid JSON XSLT XML. Ruby, (1) Asciidoc — Asciidoctor —  Ruby (2) Ruby- java javascript, .
JSON-
JSON-.
PlantUML:
{% assign bl = "\n" %} {%- for table in data -%} class {{ table.name }}{{ bl }} {%- for fk in table.fk -%} {{ table.name }} "*" -- "1" {{ fk.fk_table }}{{ bl }} {%- endfor -%} {%- endfor -%}
, . PlantUML class [ ]
. .
:
class geo.Strana class geo.Gorod geo.Gorod "*" -- "1" geo.Strana
Asciidoc:
{% assign bl = "\n" %}{% assign bbl = "\n\n" %} {%- for table in data -%} [[{{ table.name }}]]{{- bl -}} . {{ table.name }}{{- bl -}} [cols="1,3,3", options="header"]{{- bl -}} |==={{- bl -}} |â„– | | {{ bl }} {%- for column in table.columns -%} |{counter:{{ table.name }}} |{{ column.name }} |{{ column.type }}{{- bl -}} {%- endfor -%} {%- if table.fk -%} 3+a| :{{- bbl -}} {%- for fk in table.fk -%} * <<{{fk.fk_table}}, {{fk.fk_table}}>>{{- bl -}} {%- endfor -%} {%- endif -%} |==={{- bbl -}} {%- endfor -%}
include:
= :lang: ru :figure-caption: :xrefstyle: short :sectnums: == (<<struktura>>). [[struktura]] . [plantuml, struktura, png, fitrect="170x240mm", srcdpi=300, width="50%"] .... skinparam dpi 300 left to right direction include::pu_sql.pu[] .... == include::adoc_sql.adoc[]
Asciidoc Asciidoc . Asciidoc . , . - ( , , ..).
,
XML-.
. , .
( xsd ) 3 — https://smev3.gosuslugi.ru/portal/inquirytype_one.jsp?id=41108&zone=fed. :
<ns1: =" 5087746429843" =" 5087746429843"> <ns1: ="5087746429843" ="2008-11-18"/> </ns1:> <ns1:> <ns1: ="77" ="770000000002990" ="7" ="6"> <fnst: ="" =""/> <fnst: ="" =" 2-"/> <fnst: ="5087746429843" ="2008-11-18"/> </ns1:> </ns1:>
, , xsd.
Asciidoc :
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:ep="uri:asciidoc:doc:automation" extension-element-prefixes="ep"> <output method="text" /><strip-space elements="*"/> <template match="/"><apply-templates/></template> <template match="*[count(@*|*) > 0 and count(ancestor::*) > 0]"> <value-of select="'\n='"/> <for-each select="ancestor::*"><value-of select="'='"/></for-each> <value-of select="' '"/> <value-of select="concat('{',local-name(),'}')"/><text>\n\n</text> <text>|===\n</text> <for-each select="(@*)|(*[./text()])"> <text>|</text><value-of select="concat('{',local-name(),'}')"/> <text>|</text><value-of select="ep:iformat(current())"/> <text>\n</text> </for-each> <text>|===\n</text> <apply-templates/> </template> <template match="text()"/> </stylesheet>
. , .  —  . , Asciidoc |
.
XML-  —  Asciidoc. xsd- :
<?xml version="1.0" encoding="UTF-8"?> <stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform" xmlns:xs="http://www.w3.org/2001/XMLSchema"> <output method="text" /> <strip-space elements="*"/> <template match="*[@name]"> <value-of select="concat(':', @name, ': ')"/> <value-of select="normalize-space(xs:annotation/xs:documentation)"/> <text>\n</text> <apply-templates/> </template> <template match="*[not(@name)]"> <apply-templates/> </template> <template match="text()"></template> </stylesheet>
Asciidoc ( , .. xsd) :
:sectnums: include::adoc_egrul_xsd.adoc[] include::adoc_egrul_xsd2.adoc[] include::adoc_egrul.adoc[]
Microsoft Word :
, : , , .
, . , Asciidoc . , . . . XML JSON , . , , .
, , , , , .
, ,  —  , , . <strip-space elements="*"/>
<text>\n</text>
. \n
. , - .
Liquid , bl
.
, .
. , XSLT apply-templates
. (template
) .
Asciidoc Asciidoc. , Open API «;
». . «;;
» Asciidoc , , , .
, , .  —  iformat
. (zero space) DD.MM.YYYY.
AsciidocDocAutomation = Class.new do def iformat(node) value = node.to_s re = /^([0-9]{4})-([0-9]{2})-([0-9]{2})$/ vm = value.match(re) value = "#{vm[3]}.#{vm[2]}.#{vm[1]}" if !!(value =~ re) "​#​" end end
Pour désactiver complètement la syntaxe Asciidoc dans les valeurs insérées, il suffit de les échapper.
conclusions
- Des technologies de génération automatique de documentation ont été développées et peuvent être utilisées efficacement dans des projets informatiques de toute complexité.
- Le langage de balisage Asciidoc est technologiquement avancé pour une utilisation dans des tâches de génération automatique de documentation.
Et une annonce : le prochain article sera consacré aux problématiques d'assurance qualité de la documentation au format Asciidoc.