After reading Ronald Treur’s article about Duckumentation on tiDev I decided to give JSDuck a try for some projects and a new widget I was working on. In this blog I want to share my approach for documenting Alloy widgets. I’m looking forward to hear your ideas, so please leave a comment!
New Alloy Form widget
The new widget I’ve used as an example here is a widget to create a Ti.UI.TableView
based form which is both easy to implement, customise and extend.
- Source code: https://github.com/FokkeZB/nl.fokkezb.form/tree/master
- Documentation: http://form.fokkezb.nl
- Test app: https://github.com/FokkeZB/nl.fokkezb.form/tree/test
GitHub pages
I wanted to publish the documentation online with minimal effort. Since the widget lives on GitHub, using GitHub pages was the logical choice. This requires the repo to have a gh-pages branch which will be served as a website.
Working copies
Because JSDuck generates most of the documentation from inline docblocks in the code, I have set up multiple working copies on my local machine as follows:
~/form/master
: the master branch.~/form/gh-pages
: the gh-pages branch.~/form/test
: the test branch.
This way I can keep the master
repo clean by having all jsduck-*.json
files in the gh-pages
repo, just like I do for testing. When I execute $ jsduck
in the gh-pages
branch it looks for code in ../master
, as the jsduck.json file shows:
{
"--title": "Alloy Form Widget - Documentation",
"--": [
"../master"
],
"--output": "docs",
"--welcome": "../master/README.md",
"--categories": "jsduck-categories.json",
"--guides": "jsduck-guides.json",
"--warnings": "-image_unused",
..
}
Re-using README
To stay DRY, I have re-used the master
branch’s README as the welcome page. I also wanted to use the test
branch README for the testing guide, but this unfortunately copied the whole test app into the guides. Of course I could still use Grunt to copy only the README before running jsduck
if I wanted.
Namespacing
I want to be able to also use JSDuck to generate documentation for an app, including this and other widgets it uses. This is why I namespaced the widget controllers and libraries as Widgets.nlFokkezbForm.controllers.*
instead of just. controllers.field
. In an app’s documentation this will look like:
NOTE: I was in doubt between
nlFokkeZB
andnl.fokkezb.form
. The last would also group different widgets undernl.fokkezb.*
, but make the tree deeper and thus more difficult to navigate.
Constructors
The code you’re writing as Alloy controllers are ultimately wrapped by Alloy in a Controller
function exported as the CommonJS module.
..
function Controller() {
..
var $ = this;
// Your view XML compiled to JS
// Your controller JS
..
_.extend($, exports);
}
..
module.exports = Controller;
Since I can’t inject a docblock here, but also because I like to keep my controller code organized, I always wrap the controller’s code to be executed at creation in a self-executing method like this:
(function constructor(args) {
// my controller 'constructor' code
})(arguments[0] || {});
Now I can simply document this as:
/**
* Constructor.
*
* @method Controller
* @param args Arguments passed to the controller.
*/
(function constructor(args) {
..
If I’d leave out @method
then JSDuck would warn about finding an unnamed method, because it’s self-executing. If I’d use @constructor
instead, then JSDuck would use the class and show something like:
- new Widgets.nlFokkezbForm.controllers.widget( args ) : Widgets.nlFokkezbForm.controllers.widget
Instead I use @method Controller
so that the documentation stays close to how it works in the compiled Alloy controller code.
Comments
Manuel Lehner
This is really cool. Thanks for sharing your experiences – I will definitely use JSDuck for my next projects.