- Ruby 100%
| assets | ||
| lib | ||
| spec | ||
| .gitignore | ||
| ex-doc-include.gemspec | ||
| LICENSE | ||
| README.adoc | ||
ex-doc-include is an AsciiDoctor plug-in aiming to support C/C++ developers in keeping documentation as close as possible to the related code by embedding parts that naturally fit into source code comments.
The basic AsciiDoctor include directive assumes the referenced files are valid AsciiDoc and allows for cherry-picking smaller regions that match specific tags. Of course this approach is perfectly fine and works in every practical case, but still it does not leverage the structure that the included file inherently has.
In the case of external documentation for C and C++ libraries, it is sensible and fairly common to document elements placing a block comment right before it. Due to the widespread of Doxygen as documentation generator, it is very common to have those comment blocks marked with either an initial exclamation mark, or an asterisk.
/*! This is a fancy function!
Maybe it requires some more documentation details... */
std::string fancy( std::string arg);
/** This is a fancy function!
Maybe this requires some more documentation details...
... and even more... */
std::string fancy( std::string arg);
The basic inclusion feature requires to mark both the start and the end of the block on a specific line. Of course those new line should be inside the function documentation block resulting in more noise in the code.
/*!
tag:doc[]
This is a fancy function!
Maybe it requires some more documentation details...
end:doc[] */
std::string fancy( std::string arg );
The idea behind ex-doc-include is to focus on the use case and leverage the language-defined block structure.
ex-doc-include implicitly use its own tags to mark the region of the file to be included. That is it will include the region between:
-
a line starting with
/*! #ex-doc[1] (after leading spaces have been trimmed); -
a line ending with
*/(including any content found on the line on the left of the marker)
The allowed comment block is more concise and the tag use more clearly referred to the intent of the comment block:
/*! #ex-doc
This is a fancy function!
Maybe it requires some more documentation details... */
std::string fancy( std::string arg )
single-line comment format
In addition to block comments, ex-doc-include also supports sequences of single-line comments using the /// prefix.
/// #ex-doc [.api-ref]
/// int add( int x, int y)
///
/// Somma due interi
int add( int x, int y )
{
return x + y;
}
The single-line comment block:
-
Starts with a line containing
/// #ex-doc(after leading spaces have been trimmed) -
Continues with consecutive lines starting with
/// -
Ends when a line without
///is encountered
Both block and single-line formats can be used within the same file.
installation
ex-doc-include is distributed as a Gem. As usual to install it you can run:
gem install ex-doc-include.
use
When you want to use AsciiDoctor with the ex-doc-include plug-in enabled, add
-r ex-doc-include to your command line; as in:
asciidoctor test/sample.adoc -r ex-doc-include --out sample.html
modified include directive
The ex-doc-include plug-in goes into action when one of the following file type gets included in the master document:
-
.h
-
.hpp
-
.cpp
By default, the included document is linked rather than expanded at the
inclusion location.
That is, another document is created for you and a link to it is added
in place of the original include.
The default behavior can be overridden setting the expand attribute.
== Master document
Some initial notes..
=== features
include:features/feature_a.hpp[link="feature a", articles-dir=features] (1) (2)
include:features/feature_a.hpp[expand=true]
| 1 | The optional link attribute provides the text that will be used for the
link. |
| 2 | The optional articles-dir attribute controls the target directory where
the linked documents are rendered. It is relative to the folder of the main
output document. |
| The linked document borrows all the attributes from the master document. |
more features
first block role
Perhaps the comment block provides to the including document a block with specific semantic and needs to carry it in the rendered document in a way that is section-unrelated.
To fulfill this purpose, ex-doc-include allows the first included AsciiDoctor paragraph
to be optionally given a role indicated directly in the block open sequence as in:
/*! #ex-doc [<_user defined role_>] for block comments or
/// #ex-doc [<_user defined role_>] for single-line comments.
/*! #ex-doc [.api-ref]
OutIt stlext::transform( const ContainerT& c, OutIt out, F func)
Applies the provided transformation function to each of the elements in the
container and puts the results in the provided output iterator.
... */
template <typename ContainerT, typename OutIt, typename F>
OutIt transform( const ContainerT& c, OutIt out, F func )
{
return std::transform( std::begin( c ), std::end( c ), out, func );
}
The same can be achieved using single-line comments:
/// #ex-doc [.api-ref]
/// OutIt stlext::transform( const ContainerT& c, OutIt out, F func)
///
/// Applies the provided transformation function to each of the elements in the
/// container and puts the results in the provided output iterator.
template <typename ContainerT, typename OutIt, typename F>
OutIt transform( const ContainerT& c, OutIt out, F func )
{
return std::transform( std::begin( c ), std::end( c ), out, func );
}
indentation
Perhaps the subject of the included documentation is indented and is visually pleasing to have the documentation comment indented at the same level.
In the master document, indentation carries the specific semantics assigned by AsciiDoctor; therefore, the block must be realigned, while preserving any intentional indentation provided as part of the AsciiDoctor content.
To help users document their code naturally and keep it visually clear even within the source, ex-doc-include determines the indentation level by referencing the position of the block open sequence.
namespace details{
// ...
class Storage {
// ...
/*! #ex-doc [.method] (1)
bool contains( PredT p ) const
Checks whether the range contains an element satisfying the predicate
received. */
template <typename F>
bool contains( F f ) const {
return std::find_if( m_begin, m_end, f ) != m_end;
}
}
} // namespace details
| 1 | Block recognized at 4 space indentation; the content will be unindented accordingly. |
The same indentation handling applies to single-line comments:
namespace details{
// ...
class Storage {
// ...
/// #ex-doc [.method]
/// bool contains( PredT p ) const
///
/// Checks whether the range contains an element satisfying the predicate
/// received.
template <typename F>
bool contains( F f ) const {
return std::find_if( m_begin, m_end, f ) != m_end;
}
}
} // namespace details
assumption when referencing documents
The references used when including documents processed by ex-doc-include are interpreted as relative to the master document.
Assuming that you have a project structure like:
. ├── include │ └── your-lib │ ├── simple.h │ └── transitive.h └── master.adoc
With the master document including content from simple.h and transitively
from transitive.h.
The reference from the master document will take the form of:
include::include/your-lib/simple.h[expand=true], while content in simple
may refer to transitive with: include::include/your-lib/transitive.h.
Notice then that the references are not relative to the file you are working on, which may be undesirable. Instead of attempting a generalized solution to this notoriously complex problem, ex-doc-include aims for consistency. It lets users handle path resolution, for example via an attribute conventionally set by the master document that includes documentation comments.
== Master document
Content of the master document
Unresolved directive in <stdin> - include::include/your-lib/simple.h[expand=true]
/*! #ex-doc
=== Simple.h
Some more content extracted from the header file.
include::{your-lib-res}/transitive.h[expand=true] /*
destination folder for linked documents
When an included ex-doc-include document is linked rather than expanded in place, the
referred document is created by default at the same location as the master
document.
This behavior can be altered providing the additional attribute articles-dir
at the inclusion point.