Writing user's guide in Ada specification
Since I often forget to update some external documentation, I've found convenient to have it close to the implementation within the code. I'm not speaking about a reference documentation that explains every type, function or procedure provided by an Ada package. I'm talking about a programmer's guide.
The solution I've used is to write a small programmer's guide within some Ada package specification. The programmer's guide is written within comments before the package declaration. It is then extracted and merged with other package documentation to create the final programmer's guide. One benefit in having such small programmer's guide in the package specification is that it also brings some piece of documentation to developers: the user's guide is close to the specification.
The documentation is written using Markdown syntax and put before the package declaration. The extraction tool recognizes a number of formatting patterns and commands that help in merging the different pieces in one or several files.
First the small programmer's guide must start with a section header introduced by at least one
= (equal) sign. The programmer's guide documentation ends with the start of the Ada
package declaration. Unlike AdaBrowse and AdaDoc, the package specification is not parsed and not used.
-- = Streams = -- The `Util.Streams` package provides several types and operations to allow the -- composition of input and output streams. Input streams can be chained together so that -- ... ... package Util.Streams is ...
When an Ada package specification includes such comment, a documentation file is created. The generated file name is derived from the package name found after the
package keyword. The
. (dot) are replaced by
_ (underscore) and the
.md extension is added. In this example, the generated file is
Merging with @include <file>
include command indicates that the small programmer's guide from the given file must be included. For example, the Streams support of Ada Utility Library is provided by several packages, each being a child of the
Util.Streams package. The different pieces of the programmer's guide are merged together by using the following comments:
-- @include util-streams-buffered.ads -- @include util-streams-texts.ads -- @include util-streams-files.ads -- @include util-streams-pipes.ads -- @include util-streams-sockets.ads -- @include util-streams-raw.ads -- @include util-streams-buffered-encoders.ads
To avoid having links in the Ada comments, an auto-link feature is used so that some words or short sentences can be turned into links automatically. The auto-link feature works by using a simple text file that indicates words or sequence or words that should be changed to a link. The text file contains one link definition per line, composed of a set of words that must match and the associated link.
Java Bean https://en.wikipedia.org/wiki/JavaBean Java Log4j https://logging.apache.org/log4j/2.x/ Log4cxx https://logging.apache.org/log4cxx/latest_stable/index.html RFC7231 https://tools.ietf.org/html/rfc7231
The auto-link feature is very basic. To match a link, a sequence of several words must be present on the same comment line. For example, the following documentation extract:
-- = Logging = -- The `Util.Log` package and children provide a simple logging framework inspired -- from the Java Log4j library. It is intended to provide a subset of logging features
will generate the following Markdown extract with a link for the "
Java Log4j" word sequence:
# Logging The `Util.Log` package and children provide a simple logging framework inspired from the [Java Log4j](https://logging.apache.org/log4j/2.x/) library...
Having code examples is important for a programmer's guide and I've made the choice to have them as part of the comment. The extraction tool recognizes them by assuming that they are introduced by an empty line and indented by at least 4 spaces. The code extractor will use the Markdown fenced code block (```) to enclose them.
-- is free but using the full package name is helpful to control precisely the logs. -- -- with Util.Log.Loggers; -- package body X.Y is -- Log : constant Util.Log.Loggers := Util.Log.Loggers.Create ("X.Y"); -- end X.Y; -- -- == Logger Messages ==
Extracting documentation from Ada specification
Once the documentation is written, the Dynamo command is used to extract, merge and generate the documentation. The
build-doc sub-command scans the project files, reading the Ada specification, some project XML files and generates the documentation in Markdown format. The
-pandoc option tells the documentation generator to write the documentation for a book oriented organization formatted with Pandoc. It will generate them in the
dynamo build-doc -pandoc docs
Putting it all together
Pandoc being a versatile document converter, it allows to format all the generated documentation with some other files and produce a final PDF document. Several files are not generated by Dynamo and they are written either as LaTeX (
pagebreak.tex) or Markdown, for example the cover page, the introduction and installation chapters.
By using a custom LaTeX template (eisvogel.tex) and using several configuration option some nice PDF is generated.
pandoc -f markdown -o util-book.pdf --listings --number-sections \ --toc --template=./docs/eisvogel.tex docs/title.md docs/pagebreak.tex \ docs/intro.md docs/pagebreak.tex docs/Installation.md docs/pagebreak.tex \ docs/Util_Log.md docs/pagebreak.tex docs/Util_Properties.md docs/pagebreak.tex \ docs/Util_Dates.md doc/pagebreak.tex docs/Util_Beans.md docs/pagebreak.tex \ docs/Util_Http.md docs/pagebreak.tex docs/Util_Streams.md docs/pagebreak.tex \ docs/Util_Encoders.md docs/pagebreak.tex docs/Util_Events_Timers.md \ docs/pagebreak.tex docs/Util_Measures.md
Here is the final PDF file: Ada Utility Library Programmer's Guide
Publishing the programmer's guide
Read the Docs offers a free documentation hosting with a complete build and publication environment. They are able to connect to a GitHub repository and be notified each time some changes are pushed to build automatically the documentation.
The documentation is produced by MkDocs and the
mkdocs.yml configuration file allows to configure how the documentation is built, organized and presented:
site_name: Ada Utility Library docs_dir: doc pages: - Introduction: index.md - Installation: Installation.md - Log: Util_Log.md - Properties: Util_Properties.md - Dates: Util_Dates.md - Ada Beans: Util_Beans.md - HTTP: Util_Http.md - Streams: Util_Streams.md - Encoders: Util_Encoders.md - Measures: Util_Measures.md - Timers: Util_Events_Timers.md theme: readthedocs
Here is the final programmer's guide: Ada Utility Library Users' Guide.
I've found quite useful to write the programmer's guide within the Ada specification. Doing so also helps during the design of a new package because it forces to think a little bit on how the package is going to be used. There are some drawbacks in using this model:
- Each time the documentation must be fixed, the Ada specification file is modified,
- The layout of a programmer's guide does not always follow a package organization,
- Merging the documentation from different parts could bring some complexity when you have to find out where some documentation actually comes from.