oocdoc, Part 1 — NaturalDocs
👋 This page was last updated ~12 years ago. Just so you know.
Documentation in ooc land has sucked for quite some time. The standard response is pretty much: "use the code, Luke!" — which is fine when doing small projects that don't matter much, but not so when you want to get serious.
So when a newcomer, beoran, asked how to generate documentation, and later told us he got NaturalDocs to work, naturally, I had to see for myself how well it worked.
The basic idea
In this series I'm talking about generated documentation, not hand-written manual. Reference docs are usually generated directly from the codebase, thanks to inline documentation like this:
/** * The star of the latest EA game. Can bark. * * @since 1.3 * @author Amos Wenger */ Dog: class { /** * Make a barking sound. That's good, right? * * @param sound Something like "woof" or "glap", depending * on your country of choice. * * @return true on success */ bark: func (sound: String) -> Bool { "%s, %s!" printfln(sound, sound) true } }
Then, a tool is used to parse the code and generate documentation from there. For Java, there's javadoc. For C/C++ and a few others, there's Doxygen. For JavaScript, there's a plethora of options, and so on.
However there's no tool yet for ooc that does exactly that. I'm planning to write one and describe my adventure in this series of blog posts, but for now I'll present another alternative that works a bit differently: NaturalDocs.
How NaturalDocs works
NaturalDocs with any language based on some symple syntactic hints. Since it has no knowledge of the structure of programs, modules, libraries, classes and functions, you have to annotate them by hand.
The example above, with NaturalDocs mark up, would look like:
/** * Class: Dog * * The star of the latest EA game. Can bark. * * Since: 1.3 * Author: Amos Wenger */ Dog: class { /** * Function: numFrames * * Make a barking sound. That's good, right? * * Parameters: * * sound - Something like "woof" or "glap", depending on your country of choice. * * Returns: * * true on success */ bark: func (sound: String) -> Bool { "%s, %s!" printfln(sound, sound) true } }
As you can see, the problem with this syntax is that it is rather long - it would be a hassle to work on a codebase that has such comments in there. There's almost no room for code!
NaturalDocs also handles Javadoc-like syntax (see previous section), but only for languages which have full support - at the time of this writing, only C# 1.1, Perl, and ActionScript.
NaturalDocs and ooc
Adding support for a language in NaturalDocs is not trivial, but
it can be done. The most important step is to add a Languages.txt
file in your NaturalDocs project directory.
Language: ooc Extensions: ooc use Shebang String: ooc Line Comments: // # Block Comment: /** */ Package Separator: / Enum Values: Under type Function Prototype Enders: { \n Variable Prototype Enders: = \n Line Extender: \
In your example, our directory structure looks something like this:
- project - source - doc - html - nd-project - Languages.txt
And the command we need to run to build docs is the following:
NaturalDocs -i source -o HTML doc/html -p doc/nd-project
How it looks
Unfortunately, I have to say it looks pretty bad. Even Javadoc seems friendly in comparison. See for yourself:
Of course, that's the default style. With a few CSS tricks, we can get something that looks almost acceptable:
But there's still the markup problem: having such a volume of comments in the code is not acceptable in my opinion, and having to repeat type and function names is seriously not DRY.
Also, the command line to launch doc generation is quite long and not trivial to remember. I much prefer tools that have a single per-project config file, that is optional, and sane defaults.
What's next?
So, even though NaturalDocs does the deed, I am not satisfied with it. Before attempting to write my own documentation generator, I'll take a look at an alternative, Sphinx, which is currently being used to generate the SDK documentation.
Here's another article just for you:
In my previous article, I said I needed to stop thinking of Rust generics as Java generics, because in Rust, generic types are erased.
Someone gently pointed out that they are also erased in Java, the difference was elsewhere. And so, let's learn the difference together.
Java generics
I learned Java first (a long, long time ago), and their approach to generics made sense to me at the time.