Docu: Simple documentation done simply
What's a docu?
A documentation generator for .Net that isn't complicated, awkward, or difficult to use. Given an assembly and the XML that's generated by Visual Studio, docu can produce an entire website of documentation with a single command.
Can I use it yet?
Yep, just don't expect the world. Docu has been tested against Fluent NHibernate and is currently in production use; however, it's only been tested in that one situation so there may be peculiarities of your setup that haven't been catered for.
What's so special about docu?
One command to build your entire documentation
Static html, nothing fancy, no dependencies
Templates built using the Spark view engine
No GAC, no hard-coded paths; completely redistributable
Now what?
Either get the code or download the alpha, then take a look at the getting started guide. If you've got any comments or suggestions feel free to drop by the mailing list.
Getting started
Have you downloaded a binary or built the source? Good, we can continue. For this part of the guide I'm going to assume you're perfectly happy with the default appearance of the documentation (which is similar to the standard rdoc style), so I'm only going to cover how to actually produce the documentation.
Docu is comprised of a small console application with a templates directory; this directory contains all the Spark views that are used to build your documentation. These two need to stick together where-ever you put docu, but apart from that it doesn't care where it lives.
To generate documentation with docu, there are two things it needs: at least one assembly and it's associated XML documentation file that's generated by Visual Studio. You need to supply docu with the locations of the assembly (it can discover the XML file if it's in the same directory as the assembly) from the command-line. When you start it, docu interrogates the XML and the assembly to build up your documentation.
Running Docu is easy. Just run docu your-assembly-name.dll
from the command-line and you're away. Currently your documentation will be put in an output
folder in where-ever you ran docu; this will be customisable, but isn't just yet. So running the above command will result in the following console output.
----------------------------------------
docu: simple documentation done simply
----------------------------------------
Starting documentation generation
Generation complete
With that, you'll now have an output folder with several html files and folders. This directory is fully self contained so you can zip it up and ship it out to anywhere without any concerns about external references. That's it, that's all there is to using Docu.
Customising Templates
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 namespace
Example
with a sub-namespace calledFirst
, what the CLR actually stores is two namespaces:Example
andExample.First
, notExample
with 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 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 of
IComment
instances. 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.
FAQs
What is a docu? A documentation generator for .Net that isn't complicated, awkward, or difficult to use.
How mature is docu? Not very, it's only a few days old; however, it is capable of producing the docs for Fluent NHibernate, so you might be ok with it.
Can you produce such-and-such format? Most likely not, unless the format you want is html. Docu is meant to be simple, and it's designed to do one thing and one thing well. If you want a CHM generator, or a Word doc generator, then you need a different tool.
What styles do you have available? Only the default rdoc inspired style currently, but there is a customisable template system that you can use to produce your own templates, and there are plans to extend the default set of templates in the future.
Can I output private/protected members? Not yet, docu was designed for use with a public API and thus didn't need to expose private members. It will be a customisation option in the future, but it isn't implemented yet.
What's wrong with Sandcastle? Nothing, if you like pain. I don't.