docu
Simple documentation done simply
Customising Templates
So you've followed the getting started guide and would like to know how to customise your templates? Great!
Docu uses the Spark view engine to produce it's pages, which makes customisation really easy. You can use loops, conditions, include partials, write macros, and even use plain C# in your views if you so desire. It's important to note that docu's support for customisation is unpolished, there's very little you can't do, but what you can might not be the silkiest yet. I'm working on it.
Special names
A very simple feature of docu, but one that's extremely useful, is special names. There
are a few (currently only two!) special names that you can call your files and folders that mark
them for special treatment by the docu processor. For example, if you call a file !type.spark
then when it's used for generating the docs, docu will create a new page for each type in your assembly
using that template; so if you have 10 types, then docu will create 10 pages from that template, each with
only that specific type in.
The currently available special names are: !namespace and !type.
These names can also be applied to directories, and are scope limiting. If you create a directory
called !namespace, you'll get a new directory for each namespace. Any templates inside that
directory will be created for each namespace too; so, if you create a !type.spark template
inside a !namespace directory, you'll end up with a directory for each namespace, with a page
for each type in that namespace. Very simple, but pretty powerful.
It's important to note that namespaces are not considered to be in a tree as you might expect. The .Net CLR flattens all namespaces, so if you have the namespaceExamplewith a sub-namespace calledFirst, what the CLR actually stores is two namespaces:ExampleandExample.First, notExamplewith a child ofFirst. Docu sticks to this structure for simplicity; this may, or may not, change in the future.
Template properties and helpers
Each template has access to several properties that it can use to output the documentation; these properties expose the underlying document model that is generated by docu.
Every template has access to: Assemblies, Namespaces, and Types;
these each contain all their respective members for the whole of the documented codebase.
Templates that are of or inside the special name !namespace have a Namespace property
that represents the current namespace you're "inside"; the namespace exposed has a collection of types that
can be iterated over which has only the types that are of that namespace.
Templates that are of or inside the special name !type have a Type property
that represents the current type you're "inside"; this property has several properties that can be used
to generate the documentation. There's Type.Methods and Type.Properties that
contain the public methods and properties of the type, as well as Parent and Interfaces
properties that expose the base-class and any directly implemented interfaces.
The document model is under-developed and only contains what was needed to produce the basic documentation used by Fluent NHibernate; it's more than likely that there are features that are missing or not exposed. If there is anything that you need that isn't available, please post a message on the mailing list.
An example from the default template (in !namespace/index.spark):
<div class="header">
<p class="class"><strong>Namespace</strong> ${Namespace.Name}</p>
</div>
<div class="sub-header">
<h3 class="section">Types</h3>
<ul>
<for each="var type in Namespace.Types">
<li><a href="${type.Name}.htm">${h(type.PrettyName)}</a></li>
</for>
</ul>
</div>
You can see this template outputs the namespace name, followed by a list of all the types. You'll
note the use of a h call and type.PrettyName. Well h is one
of a few methods available to templates, this one in particular replaces < and > characters
with their html friendly equivalent (it will eventually be a full html sanitizer, but it isn't there
yet); PrettName on the other hand outputs the full generic name with all generic types
resolved, if possible.
Some other methods that are available are:
OutputMethodParams(Method), this outputs a comma-delimted list of the parameters of a given method, handy to not have to do the comma processingWriteInterfaces(IList)does a similar thing but for the interfaces of a typeWriteSummary(Summary)writes out the summary comment of a method/type with all types fully expanded and internally referenced if possibleWriteReference(Reference), resolves a documentation reference (which could be a method parameter, a return type, or just a <see /> block from a comment) and either outputs a simple text representation if it's an external reference, or a link if it's part of the assembly being documented.
A note on comment blocks: XML comments can be simple text, or a complex hierarchy of XML tags. Due to this, there is no flat representation of a comment; comments are always a list ofICommentinstances. Each instance can be output in a different way, hence why it's a good idea to useWriteSummary.
These methods are not exhaustive and are pretty underdeveloped and overly specific. They will be changing in the future to a more managable structure, but for the time being most things can be catered for.
Transforming templates
A template is discerned by it's extension, .spark; any files that have that extension are
transformed into a .htm file at generation-time, with the exception of any files beginning with
an underscore (these are deemed to be partials and are left alone).
Any directories are recursively evaluated for templates, if they contain any the they will be copied to the output directory; similarly any untransformed files that aren't spark templates will also be copied (such as css files).
As already explained, any templates or directories that have a special name get transformed into multiple html files and folders depending on their name.
So given the following directory structure:
templates/
!namespaces/
!type.spark
index.spark
css/
main.css
index.spark
Combine that with an assembly that has two namespaces (First and Second
respectively) each with several types, you will see the following output:
output/
First/
TypeOne.htm
TypeTwo.htm
TypeThree.htm
index.htm
Second/
TypeFour.htm
TypeFive.htm
index.htm
css/
main.css
index.htm
That's it, that's all I can think of right now. Watch out for badly formed templates because exceptions are mostly unhandled currently. Big bang. Drop by on the mailing list if you need any help.