update Ox.doc; add (some) inline comments in Ox.test

This commit is contained in:
rolux 2012-05-30 00:26:25 +02:00
parent 250db05abc
commit f7e58b05e9

View file

@ -20,6 +20,8 @@ Ox.doc <f> Generates documentation for annotated JavaScript
file <s> File name file <s> File name
line <n> Line number line <n> Line number
name <s> Name of the item name <s> Name of the item
order <[s]> Order of signature, arguments, properties
Present if the type of the item is "function"
properties <[o]|u> Properties (array of doc objects) properties <[o]|u> Properties (array of doc objects)
Present if the <code>type</code> of the item is Present if the <code>type</code> of the item is
<code>"event"</code>, <code>"function"</code> <code>"event"</code>, <code>"function"</code>
@ -30,10 +32,10 @@ Ox.doc <f> Generates documentation for annotated JavaScript
line <n> Line line <n> Line
type <s> Type (see Ox.tokenize for a list of types) type <s> Type (see Ox.tokenize for a list of types)
value <s> Value value <s> Value
summary <s> One-line summary returns <[o]> Return values (array of doc objects)
usage <[o]> Usage (array of doc objects)
Present if the <code>type</code> of the item is Present if the <code>type</code> of the item is
<code>"function"</code>. <code>"function"</code>.
summary <s> One-line summary
tests <[o]> Tests (array of test objects) tests <[o]> Tests (array of test objects)
expected <s> Expected result expected <s> Expected result
statement <s> Statement statement <s> Statement
@ -66,9 +68,9 @@ Ox.doc <f> Generates documentation for annotated JavaScript
'Magic constant' 'Magic constant'
> Ox.test.doc[1].description > Ox.test.doc[1].description
'Bar per baz is a good indicator of an item\'s foo-ness.' 'Bar per baz is a good indicator of an item\'s foo-ness.'
> Ox.test.doc[1].usage[0].types > Ox.test.doc[1].signature[0].types
['number'] ['number']
> Ox.test.doc[1].usage[0].summary > Ox.test.doc[1].signature[0].summary
'Bar per baz, or NaN' 'Bar per baz, or NaN'
> Ox.test.doc[1].tests[1] > Ox.test.doc[1].tests[1]
{expected: 'NaN', statement: 'My.foo({})'} {expected: 'NaN', statement: 'My.foo({})'}
@ -78,9 +80,9 @@ Ox.doc = (function() {
item: /^(.+?) <(.+?)> (.+?)$/, item: /^(.+?) <(.+?)> (.+?)$/,
multiline: /^\/\*\@.*?\n([\w\W]+)\n.*?\@?\*\/$/, multiline: /^\/\*\@.*?\n([\w\W]+)\n.*?\@?\*\/$/,
script: /\n(\s*<script>s*\n[\w\W]+\n\s*<\/script>s*)/g, script: /\n(\s*<script>s*\n[\w\W]+\n\s*<\/script>s*)/g,
signature: /(\(.*?\)) \->(.*)/,
singleline: /^\/\/@\s*(.*?)\s*$/, singleline: /^\/\/@\s*(.*?)\s*$/,
test: /\n(\s*> .+\n.+?)/g, test: /\n(\s*> .+\n.+?)/g,
usage: /\(.*?\)/
}, },
types = { types = {
a: 'array', b: 'boolean', d: 'date', a: 'array', b: 'boolean', d: 'date',
@ -110,17 +112,21 @@ Ox.doc = (function() {
return matches && ( return matches && (
matches[2].indexOf('/') == -1 || matches[2].indexOf('/') == -1 ||
'\'"'.indexOf(matches[2].slice(-2, -1)) > -1 '\'"'.indexOf(matches[2].slice(-2, -1)) > -1
) ? Ox.extend({ ) ? Ox.extend(
name: parseName(matches[1].trim()), parseName(matches[1]),
summary: matches[3].trim() parseType(matches[2]),
}, parseType(matches[2])) : null; {summary: matches[3].trim()}
) : null;
} }
function parseName(string) { function parseName(string) {
var matches = re.usage.exec(string); var matches = re.signature.exec(string);
return matches ? matches[0] : string; return matches
? {signature: matches[1], name: matches[2].trim()}
: {name: string};
} }
function parseNode(node) { function parseNode(node) {
var item = parseItem(node.line), subitem; var item = parseItem(node.line), order = [];
item.name = item.name.replace(/^\./, '');
node.nodes && node.nodes.forEach(function(node) { node.nodes && node.nodes.forEach(function(node) {
var key, line = node.line, subitem; var key, line = node.line, subitem;
if (!/^#/.test(node.line)) { if (!/^#/.test(node.line)) {
@ -130,17 +136,21 @@ Ox.doc = (function() {
item.tests = item.tests || []; item.tests = item.tests || [];
item.tests.push(parseTest(line)); item.tests.push(parseTest(line));
} else if ((subitem = parseItem(line))) { } else if ((subitem = parseItem(line))) {
if (/^\(/.test(subitem.name)) { if (subitem.signature) {
item.usage = item.usage || []; item.returns = item.returns || [];
item.usage.push(parseNode(node)); item.returns.push(parseNode(node));
order.push('returns');
} else if (subitem.types[0] == 'event') { } else if (subitem.types[0] == 'event') {
item.events = item.events || []; item.events = item.events || [];
item.events.push(parseNode(node)); item.events.push(parseNode(node));
order.push('events');
} else { } else {
key = item.types[0] == 'function' key = item.types[0] == 'function'
? 'arguments' : 'properties' && !/^\./.test(subitem.name)
? 'arguments' : 'properties';
item[key] = item[key] || []; item[key] = item[key] || [];
item[key].push(parseNode(node)); item[key].push(parseNode(node));
order.push(key);
} }
} else { } else {
item.description = item.description item.description = item.description
@ -148,6 +158,9 @@ Ox.doc = (function() {
} }
} }
}); });
if (item.types[0] == 'function') {
item.order = Ox.unique(order);
}
return item; return item;
} }
function parseScript(string) { function parseScript(string) {
@ -183,6 +196,7 @@ Ox.doc = (function() {
.replace(re.script, encodeLinebreaks) .replace(re.script, encodeLinebreaks)
.replace(re.test, encodeLinebreaks) .replace(re.test, encodeLinebreaks)
.split('\n'), .split('\n'),
parent,
tree = parseTree(lines); tree = parseTree(lines);
if (re.item.test(tree.line)) { if (re.item.test(tree.line)) {
// parse the tree's root node // parse the tree's root node
@ -200,8 +214,17 @@ Ox.doc = (function() {
} else { } else {
// property of a function item // property of a function item
lastItem = items[items.length - 1]; lastItem = items[items.length - 1];
lastItem.properties = lastItem.properties || []; parent = lastItem.types[0] == 'function'
lastItem.properties.push(item); && lastItem.returns
&& lastItem.returns[0].types[0] == 'object'
? lastItem.returns[0] : lastItem;
parent.properties = parent.properties || [];
parent.properties.push(item);
if (
parent.order && !Ox.contains(parent.order, 'properties')
) {
parent.order.push('properties');
}
// include leading linebreaks and whitespace // include leading linebreaks and whitespace
lastItem.source = lastItem.source.concat( lastItem.source = lastItem.source.concat(
parseTokens(tokens[i], true) parseTokens(tokens[i], true)
@ -597,6 +620,7 @@ Ox.test <f> Takes JavaScript, runs inline tests, returns results
section <s|u> Section in the file section <s|u> Section in the file
statement <s> Test statement statement <s> Test statement
passed <b> True if actual result and expected result are equal passed <b> True if actual result and expected result are equal
.data <o> undocumented
<script> <script>
Ox.test.foo = function(item) { Ox.test.foo = function(item) {
return item.bar / item.baz; return item.bar / item.baz;
@ -620,9 +644,16 @@ Ox.test <f> Takes JavaScript, runs inline tests, returns results
undefined undefined
@*/ @*/
Ox.test = function(argument, callback) { Ox.test = function(argument, callback) {
Ox.print('Ox.test', argument, '----------------------------------') // Ansynchronous functions can be tested by calling Ox.test(actual,
// expected) in the callback. If Ox.test is called inside a test statement
// (unless at the beginning of the statement, which is a test for Ox.test),
// the call to Ox.test is patched by inserting the test statement string as
// the first argument of the Ox.test call, and Ox.test will branch when
// called with three arguments.
function runTests(items) { function runTests(items) {
var id = Ox.uid(), regexp = /(.+Ox\.test\()/, results = []; var id = Ox.uid(), regexp = /(.+Ox\.test\()/, results = [];
// We have to create a globally accessible object so that synchronous
// and asynchronous tests can read, write and return the same data.
Ox.test.data[id] = { Ox.test.data[id] = {
callback: callback, callback: callback,
done: false, done: false,
@ -635,18 +666,20 @@ Ox.test = function(argument, callback) {
}) && item.tests.forEach(function(test) { }) && item.tests.forEach(function(test) {
var actual, isAsync = regexp.test(test.statement); var actual, isAsync = regexp.test(test.statement);
if (isAsync) { if (isAsync) {
// Add a pending test
Ox.test.data[id].tests[test.statement] = { Ox.test.data[id].tests[test.statement] = {
name: item.name, name: item.name,
section: item.section section: item.section
}; };
Ox.Log('TEST', 'XXX', test.statement); // Patch the test statement
test.statement = test.statement.replace( test.statement = test.statement.replace(
regexp, regexp,
"$1'" + test.statement.replace(/'/g, "\\'") + "', " "$1'" + test.statement.replace(/'/g, "\\'") + "', "
); );
} }
if (test.expected || test.statement.match(/Ox\.test\./)) { if (test.expected || test.statement.match(/Ox\.test\./)) {
// don't eval script tags without assignment to Ox.test.foo // Eval the statement, unless it's a script tag that doesn't
// add a property to Ox.test
Ox.Log('TEST', test.statement); Ox.Log('TEST', test.statement);
actual = eval(test.statement); actual = eval(test.statement);
} }
@ -671,12 +704,15 @@ Ox.test = function(argument, callback) {
} }
if (arguments.length == 2) { if (arguments.length == 2) {
if (Ox.typeOf(argument) == 'string' && Ox.contains(argument, '\n')) { if (Ox.typeOf(argument) == 'string' && Ox.contains(argument, '\n')) {
// source code
runTests(Ox.doc(argument)) runTests(Ox.doc(argument))
} else { } else {
argument = Ox.makeArray(argument); argument = Ox.makeArray(argument);
if (Ox.typeOf(argument[0]) == 'string') { if (Ox.typeOf(argument[0]) == 'string') {
// files
Ox.doc(argument, runTests); Ox.doc(argument, runTests);
} else { } else {
// doc objects
runTests(argument); runTests(argument);
} }
} }