• Stars
    star
    232
  • Rank 172,319 (Top 4 %)
  • Language
    JavaScript
  • License
    MIT License
  • Created about 11 years ago
  • Updated almost 5 years ago

Reviews

There are no reviews yet. Be the first to send feedback to the community and the maintainers!

Repository Details

Doc generation on steroids

Autodoc

Build Status NPM version

Autodoc lets you write tests in comments just above your JavaScript functions, then run those tests from the command line and auto-generate documentation with the same tests embedded and executing right in the browser.

Introduction

Here, we'll start with something simple: a function that checks whether a value is an integer. We'll define the function in a file called numbers.js and write out a bunch of example cases in a block comment:

/**
 * @private
 * @examples
 * isInteger(5)     // => true
 * isInteger(5.0)   // => true
 * isInteger(-5)    // => true
 * isInteger(3.14)  // => false
 * isInteger('foo') // => false
 * isInteger(NaN)   // => false
 */
function isInteger(x) {
  return x === Math.floor(x);
}

Notice the @private tag. This is necessary because we're doing nothing to expose this function (i.e., there's no module.exports for Node); so it lets Autodoc know: "This function is not exposed publicly but I want to test it anyway."

Now, without doing anything else, right away we can use Autodoc to test this function against our examples.

$ autodoc --test --verbose numbers.js

[private]

    isInteger
        isInteger(5) => true
        isInteger(5.0) => true
        isInteger(-5) => true
        isInteger(3.14) => false
        isInteger('foo') => false
        isInteger(NaN) => false

Finished in 0.006 seconds
6 tests, 6 assertions, 0 failures, 0 skipped

OK, sweet. Now let's say we've just thought up another possible implementation. Let's add that to the file:

/**
 * @private
 * @benchmarks
 * isInteger(123456789)     // using Math.floor
 * isIntegerLike(123456789) // using RegExp: ^\d+$
 */
function isIntegerLike(x) {
  return (/^\d+$/).test(String(x));
}

Now we can also use Autodoc to quickly race these two implementations against one another:

$ autodoc --perf numbers.js

isIntegerLike - using Math.floor   x 112  - 2,157,257.568 ops/second
isIntegerLike - using RegExp: ^d+$ x 104  - 1,820,548.837 ops/second

Results:

| Function      | Benchmark          | Ops/second    |
------------------------------------------------------
| isIntegerLike | using Math.floor   | 2,157,257.568 |
| isIntegerLike | using RegExp: ^d+$ | 1,820,548.837 |

All righty. Let's say we're completely delusional and actually think this library is useful, so we want to share it with the world. We'll add some simple comments describing what each function does, remove the @private tags, and wrap the library up in a semi-reasonable way so it runs in either Node or the browser:

/**
 * Just some simple number helpers.
 */
(function(Numbers) {

  /**
   * Checks if a number is an integer. Returns false for anything that isn't an
   * integer, including non-numbers.
   *
   * [...]
   */
  Numbers.isInteger = function(x) { /*...*/ };

  /**
   * Checks if a value looks like an integer. Returns true for both integers and
   * strings that represent integers, false for everything else.
   *
   * [...]
   */
  Numbers.isIntegerLike = function(x) { /*...*/ };

}(typeof module === 'object' ? (module.exports = {}) : (this.Numbers = {})));

Now that we've done that, let's go ahead and generate our API documentation. This is Autodoc's bread and butter:

$ autodoc numbers.js

Docs screenshot

Would you look at that? API docs, with the our examples and benchmarks, executing directly in the browser.

If you're sold that this is a good idea, read on for more details on how Autodoc works and how to use it. Keep in mind that as this is a brand new project, a lot of this stuff is in flux and I'm frequently changing my mind about things. So if you plan to use this tool right now you'll want to follow the project closely on GitHub to find out when things break, new features get added, etc.

Conventions

By default, the autodoc command will put the following files in the autodoc folder:

autodoc/
    index.html
    docs.js
    docs.css

You can change which folder you want this stuff dumped to w/ the -o or --output option.

To spice up your API docs with some custom JavaScript, add a file called doc_helper.js to the output folder. Autodoc will automatically detect it there and add a <script> tag referencing it to the resulting HTML. You can add other arbitrary JavaScript files by providing a comma-delimited list via the --javascripts option.

You can also specify your own template (currently only Mustache templates are supported, though that will change) using the --template option. This way you can give your docs a unique look. (Note that if you're using your own template, some other features are not guaranteed to work; e.g., Autodoc will not magically know where to add <script> tags linking to doc_helper.js or other custom JavaScript files. You'd need to put those into your custom template yourself.)

Other Options

To only generate documentation for functions with certain tags, you can specify those tags as a comma-separated list via the --tags option. By default, if you don't specify any tags, but your comments do include some functions with the @public tag, then Autodoc will assume you only want those public methods included in the API docs. Otherwise it will include everything in the docs. (Think this is a stupid idea? Let me know!)

If you just want to run specs for certain methods you can use the --grep option, which does just what you think.

To see a list of all available options, run autodoc --help. I'm pretty sure the list will change pretty regularly in the near term, so that's a better resource for now than this README will be.

Documentation

API docs will be generated based on the comments above each function. This includes information from @param and @returns tags. See JsDoc for details. You can use Markdown to format your comments.

If you have a comment at the top of your file with the @name tag, Autodoc will use that as the name of your library. You can use the @fileOverview tag to provide a high-level description. Otherwise, Autodoc will just use the topmost comment block in the file, whatever it is.

Specs

Use the @examples (or just @example) tag to define specs above any function:

/**
 * @examples
 * trim(' foo') // => 'foo'
 * trim('foo ') // => 'foo'
 */
 function trim(str) { return str.replace(/^\s+|\s+$/g, ''); }

Default Handlers

Autodoc supports the following syntaxes for defining assertions:

// The result of calling foo() should be...

// ...equal to 'bar' (works for any legal expression)
foo() // => 'bar'

// ...either 1, 2, or 3
foo() // => one of [1, 2, 3]

// ...an array starting with [1, 2, 3]
foo() // => [1, 2, 3, ...]

// ...an array ending with ['x', 'y', 'z']
foo() // => [..., 'x', 'y', 'z']

// ... an array with the elements 'foo' and 'bar' (any order)
foo() // =~ ['foo', 'bar']

// ... an array containing 'foo' and 'bar' and possibly other elements
foo() // =~ ['foo', 'bar', ...]

// ...an object with the properties { foo: 1, bar: 2 } and possibly others
foo() // => { foo: 1, bar: 2, ... }

// ...a string matching the regular expression /foo/
foo() // =~ /foo/

// ...an instance of Foo
foo() // instanceof Foo

// After calling foo(), x should equal 5
foo() // x == 5

// After calling foo(), x should NOT equal 5
foo() // x != 5

// Calling foo() should throw an exception
foo() // throws

// Calling foo(callback) should in turn call callback() exactly once
foo(callback) // calls callback 1 time

// Calling foo(callback) should call callback() twice asynchronously
foo(callback) // calls callback 2 times asynchronously

Example Helpers

Any setup code you write before your first example will be included in the output. For instance:

/**
 * @private
 * @examples
 * var num = 5,
 *     str = '5';
 *
 * isInteger(num)          // => true
 * isInteger(str)          // => false
 * isInteger(Number(str)); // => true
 */
function isInteger(x) {
  return x === Math.floor(x);
}

In some cases you may find that you have multiple functions that all share the same setup code. It can be tedious to rewrite it every time; so for shared setup code that you want to provide to all examples, include the @exampleHelpers tag in any of your comments and it will be made available:

/**
 * @exampleHelpers
 * var num = 5,
 *     str = '5';
 */

Note that in the above example, what this means is that the variables num and str will be defined and visible (essentially global) to all your examples.

Custom Handlers

You can provide custom handlers if you need to do something a little more advanced. To do this, specify a path to custom handlers file with the --handlers option, and define an exampleHandlers array that looks like this:

this.exampleHandlers = [
  {
    pattern: /pattern 1/,
    template: 'template1'
  },
  {
    pattern: /pattern 2/,
    template: 'template2'
  },
  ...
];

For every example in your comments, the expected output (the part to the right of // =>) will first be checked against all of your custom handlers (in order) to see if there's a match. This means that if you can want you can override Autodoc's defaults.

The template property of each matcher should name a Mustache template file following the naming convention template_name.js.mustache (so the example above would require two files, template1.js.mustache and template2.js.mustache). You can specify where these templates are locate with the --partials option; otherwise, Autodoc will look in the output folder as well as output/handlers.

The data passed to the template property will include the properties { actual, actualEscaped, expected, expectedEscaped, match }.

  • actual: The literal string taken directly from the comment on the left of the // =>
  • actualEscaped: An escaped version of actual suitable for, e.g., putting inside a JavaScript string in your template
  • expected: The literal string taken from the comment on the right side of the // =>
  • expectedEscaped: Same as actualEscaped, but for expected
  • match: The match data captured by the pattern property of your custom handler

For even more control, you can also add a data function to your handler which accepts the match object from your pattern and returns any arbitrary data:

this.exampleHandlers = [
  {
    pattern: /advanced pattern/,
    template: 'advanced',
    data: function(match) {
      return {
        foo: match[1],
        bar: match[2]
      };
    }
  }
];

In this case the output from your function (a { foo, bar } object in the example above) will be passed into your template instead of match.

Benchmarks

This feature isn't really a focus right now, to be honest. At the moment I'm mainly concentrating on the test running and document generation. But anyway, the preliminary functionality is there.

Use the @benchmarks tag to specify cases you want to profile for performance. The format is similar to @examples:

/**
 * @benchmarks
 * doSomething(shortString)  // short string
 * doSomething(mediumString) // medium string
 * doSomething(longString)   // long string
 */

More Repositories

1

lazy.js

Like Underscore, but lazier
JavaScript
6,026
star
2

nearest-color

Find the nearest color
JavaScript
340
star
3

safe_yaml

Parse YAML safely
Ruby
215
star
4

ConcurrentList

A thread-safe, lock-free implementation of the IList<T> interface for .NET
C#
55
star
5

lemming.js

Evaluate user-input JS code
JavaScript
44
star
6

console-highlight

Syntax highlighting in the console
CSS
35
star
7

fast-matcher

Fast matching, e.g. for autocompletes
JavaScript
31
star
8

angular-fast-matcher

Angular directive based on fast-matcher
JavaScript
27
star
9

HighTables

A JavaScript library that makes it trivial to render charts from existing HTML tables
JavaScript
24
star
10

whatever.js

Just whatever
JavaScript
18
star
11

htmlout

HTML-styled console output
JavaScript
15
star
12

slidedown

Markdown slide decks
JavaScript
12
star
13

dm-noisy-failures

Noisy (and descriptive) failures for DataMapper
Ruby
12
star
14

simplex

Simpler than regular expressions
JavaScript
10
star
15

string-table

Format an array of data objects as a textual table
CoffeeScript
10
star
16

named-args

Named arguments in JavaScript
JavaScript
9
star
17

SublimeBucket

Bitbucket plugin for Sublime Text 3
Python
8
star
18

todo-backend-express

Node.js/Express implementation of the Todo-Backend API spec
JavaScript
8
star
19

apiif

API in folders
Ruby
7
star
20

6th-css-sense

I see dead CSS selectors
JavaScript
5
star
21

PhilosopherDeveloper

A repository for the blog The Philosopher Developer
CSS
5
star
22

gulp-esprima

Parse JS to ASTs w/ esprima
JavaScript
4
star
23

updown

Let your users vote
Ruby
4
star
24

CloudDevelop

An online development tool allowing coders to write and compile snippets of source code in a variety of languages, all within a web browser
JavaScript
4
star
25

deft

JS dependency declaration
JavaScript
4
star
26

NBinarySearch

Flexible binary search for all indexed collections in .NET
C#
4
star
27

race.js

Pit JavaScript libraries against each other
JavaScript
4
star
28

sortfix

Fixes Array.prototype.sort
JavaScript
2
star
29

SimpleDevelop

A cross-platform multi-language snippet compiler?
JavaScript
2
star
30

protips

I am a pro, and these are my tips
2
star
31

truman.js

Smoke & mirrors so you can prototype quickly
JavaScript
2
star
32

just-use-markdown

Put Markdown in <script> tags
JavaScript
2
star
33

ghdb

Ruby
1
star
34

randy

Generate random stuff
Ruby
1
star
35

shmomise

Promises, shmomises
JavaScript
1
star
36

VariantCollections

A library to provide some much-needed type variance to widely used collection classes from the .NET BCL
C#
1
star
37

fancy-server

Oh server, you so fancy
JavaScript
1
star
38

writer.js

Abstraction library for writing to console, strings
JavaScript
1
star
39

superout

When stdout just isn't enough
JavaScript
1
star
40

cleanSlate.js

Reset any pending asynchronous actions in the browser
JavaScript
1
star
41

validatorsquared

The validator validator
1
star
42

django-starter

Like sourdough starter, but replace sourdough with Django
Python
1
star
43

gquery

Generic jQuery
JavaScript
1
star
44

sketchy.js

Another HTML5 canvas drawing pad
JavaScript
1
star
45

Charter

Make your own web-embeddable charts really fast and easily
JavaScript
1
star
46

RPerft

Ruby gem for performance testing w/ Perft
Ruby
1
star
47

LiveDraft

Just an idea—we'll see where it goes
JavaScript
1
star