From 47066e70e1621ff74bd2cd6b5853ca3c5841aba6 Mon Sep 17 00:00:00 2001
From: Misko Hevery
Date: Thu, 4 Nov 2010 14:24:31 -0700
Subject: added documentation for ng:include and ng:widget and test for doc
collector.
---
docs/collect.js | 33 ++++++---
docs/filter.template | 2 +-
docs/index.html | 16 +++-
docs/overview.template | 7 +-
docs/spec/collectSpec.js | 47 ++++++++++++
docs/specs.js | 21 ++++++
docs/widget.template | 28 +++++++
gen_docs.sh | 2 +-
lib/jasmine-1.0.1/index.js | 180 +++++++++++++++++++++++++++++++++++++++++++++
src/Angular.js | 14 ++--
src/validators.js | 4 +-
src/widgets.js | 51 ++++++++++++-
12 files changed, 374 insertions(+), 31 deletions(-)
create mode 100644 docs/spec/collectSpec.js
create mode 100644 docs/specs.js
create mode 100644 docs/widget.template
create mode 100644 lib/jasmine-1.0.1/index.js
diff --git a/docs/collect.js b/docs/collect.js
index f85f2c6b..c16366ab 100644
--- a/docs/collect.js
+++ b/docs/collect.js
@@ -1,8 +1,10 @@
+require.paths.push("./lib");
+require.paths.push(__dirname);
var fs = require('fs'),
spawn = require('child_process').spawn,
- mustache = require('../lib/mustache'),
- callback = require('./callback'),
- markdown = require('../lib/markdown');
+ mustache = require('mustache'),
+ callback = require('callback'),
+ markdown = require('markdown');
var documentation = {
section:{},
@@ -44,7 +46,7 @@ var work = callback.chain(function () {
mergeTemplate('wiki_widgets.js', 'wiki_widgets.js', documentation, callback.chain());
console.log('DONE');
});
-work();
+if (!this.testmode) work();
////////////////////
function noop(){}
@@ -78,6 +80,10 @@ function mergeTemplate(template, output, doc, callback){
}
+function trim(string) {
+ return string.replace(/^[\s\n\r]+/g, '').replace(/[\s\n\r]+$/g, '');
+}
+
function unknownTag(doc, name) {
var error = "[" + doc.raw.file + ":" + doc.raw.line + "]: unknown tag: " + name;
console.log(error);
@@ -93,7 +99,7 @@ function escapedHtmlTag(doc, name, value) {
}
function markdownTag(doc, name, value) {
- doc[name] = markdown.toHTML(value);
+ doc[name] = markdown.toHTML(value.replace(/^#/gm, '##'));
}
var TAG = {
@@ -103,8 +109,10 @@ var TAG = {
namespace: valueTag,
css: valueTag,
see: valueTag,
+ usageContent: valueTag,
'function': valueTag,
description: markdownTag,
+ TODO: markdownTag,
returns: markdownTag,
name: function(doc, name, value) {
doc.name = value;
@@ -113,13 +121,13 @@ var TAG = {
param: function(doc, name, value){
doc.param = doc.param || [];
doc.paramRest = doc.paramRest || [];
- var match = value.match(/^({([^\s=]+)(=)?}\s*)?([^\s]+|\[(\S+)+=([^\]]+)\])\s+(.*)/);
+ var match = value.match(/^({([^\s=]+)(=)?}\s*)?(([^\s=]+)|\[(\S+)+=([^\]]+)\])\s+(.*)/);
if (match) {
var param = {
type: match[2],
- name: match[4] || match[5],
- 'default':match[6],
- description:match[7]};
+ name: match[6] || match[5],
+ 'default':match[7],
+ description:match[8]};
doc.param.push(param);
if (!doc.paramFirst) {
doc.paramFirst = param;
@@ -138,11 +146,11 @@ function parseNgDoc(doc){
var atText;
var match;
doc.raw.text.split(/\n/).forEach(function(line, lineNumber){
- if (match = line.match(/^@(\w+)(\s+(.*))?/)) {
+ if (match = line.match(/^\s*@(\w+)(\s+(.*))?/)) {
// we found @name ...
// if we have existing name
if (atName) {
- (TAG[atName] || unknownTag)(doc, atName, atText.join('\n'));
+ (TAG[atName] || unknownTag)(doc, atName, trim(atText.join('\n')));
}
atName = match[1];
atText = [];
@@ -178,8 +186,9 @@ function findNgDoc(file, callback) {
if (inDoc && line.match(/\*\//)) {
doc.raw.text = doc.raw.text.join('\n');
doc.raw.text = doc.raw.text.replace(/^\n/, '');
- if (doc.raw.text.match(/@ngdoc/))
+ if (doc.raw.text.match(/@ngdoc/)){
callback(doc);
+ }
doc = null;
inDoc = false;
}
diff --git a/docs/filter.template b/docs/filter.template
index f9005782..0602aff9 100644
--- a/docs/filter.template
+++ b/docs/filter.template
@@ -15,7 +15,7 @@ angular.filter.{{shortName}}({{paramFirst.name}}{{#paramRest}}, {{name}}{{/param
Parameters
{{#param}}
- {{name}}{{#type}}({{type}}){{/type}} : {{description}}
+ {{name}}:{{#type}}{{type}}{{/type}}{{^type}}:*{{/type}}{{#default}}={{default}}{{/default}} : {{{description}}}
{{/param}}
diff --git a/docs/index.html b/docs/index.html
index f61893a4..a2cad87e 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -6,19 +6,29 @@
+
-
+
diff --git a/docs/overview.template b/docs/overview.template
index dbb91e2a..c4c899e2 100644
--- a/docs/overview.template
+++ b/docs/overview.template
@@ -1 +1,6 @@
-{{{description}}}
\ No newline at end of file
+{{name}}
+{{{description}}}
+
+
+{{{example}}}
+
\ No newline at end of file
diff --git a/docs/spec/collectSpec.js b/docs/spec/collectSpec.js
new file mode 100644
index 00000000..2d1b559c
--- /dev/null
+++ b/docs/spec/collectSpec.js
@@ -0,0 +1,47 @@
+console.log(__dirname);
+require.paths.push(__dirname + "/../");
+require.paths.push(__dirname + "/../../");
+var fs = require('fs');
+var Script = process.binding('evals').Script;
+var collect = load('docs/collect.js');
+
+describe('collect', function(){
+ describe('TAG', function(){
+ var TAG = collect.TAG;
+ describe('@param', function(){
+ var doc;
+ beforeEach(function(){
+ doc = {};
+ });
+ it('should parse with no default', function(){
+ TAG.param(doc, 'param',
+ '{(number|string)} number Number to format.');
+ expect(doc.param).toEqual([{
+ type : '(number|string)',
+ name : 'number',
+ 'default' : undefined,
+ description : 'Number to format.' }]);
+ });
+ it('should parse with default', function(){
+ TAG.param(doc, 'param',
+ '{(number|string)=} [fractionSize=2] desc');
+ expect(doc.param).toEqual([{
+ type : '(number|string)',
+ name : 'fractionSize',
+ 'default' : '2',
+ description : 'desc' }]);
+ });
+ });
+ });
+});
+
+function load(path){
+ var sandbox = {
+ require: require,
+ console: console,
+ __dirname: __dirname,
+ testmode: true
+ };
+ Script.runInNewContext(fs.readFileSync(path), sandbox, path);
+ return sandbox;
+}
diff --git a/docs/specs.js b/docs/specs.js
new file mode 100644
index 00000000..5f1cd153
--- /dev/null
+++ b/docs/specs.js
@@ -0,0 +1,21 @@
+require.paths.push("./lib");
+var jasmine = require('jasmine-1.0.1');
+var sys = require('sys');
+
+for(var key in jasmine) {
+ global[key] = jasmine[key];
+}
+
+var isVerbose = false;
+var showColors = true;
+process.argv.forEach(function(arg){
+ switch(arg) {
+ case '--color': showColors = true; break;
+ case '--noColor': showColors = false; break;
+ case '--verbose': isVerbose = true; break;
+ }
+});
+
+jasmine.executeSpecsInFolder(__dirname + '/spec', function(runner, log){
+ process.exit(runner.results().failedCount);
+}, isVerbose, showColors);
\ No newline at end of file
diff --git a/docs/widget.template b/docs/widget.template
new file mode 100644
index 00000000..cf82eac9
--- /dev/null
+++ b/docs/widget.template
@@ -0,0 +1,28 @@
+{{name}}
+Usage
+In HTML Template Binding
+
+
+<{{shortName}}{{#param}} {{#default}}[ {{/default}}{{name}}="..."{{#default}}] {{/default}}{{/param}}>{{#usageContent}}
+
+ {{usageContent}}
+{{/usageContent}}</{{shortName}}>
+
+
+
+Parameters
+
+ {{#param}}
+ {{name}}:{{#type}}{{type}}{{/type}}{{^type}}:*{{/type}}{{#default}}={{default}}{{/default}} : {{{description}}}
+ {{/param}}
+
+
+CSS
+{{{css}}}
+
+Description
+{{{description}}}
+
+
+{{{example}}}
+
\ No newline at end of file
diff --git a/gen_docs.sh b/gen_docs.sh
index d883fd34..575287e9 100755
--- a/gen_docs.sh
+++ b/gen_docs.sh
@@ -1,3 +1,3 @@
#!/bin/sh
-/usr/local/bin/node docs/collect.js
+/usr/local/bin/node docs/specs.js --noColor && /usr/local/bin/node docs/collect.js
diff --git a/lib/jasmine-1.0.1/index.js b/lib/jasmine-1.0.1/index.js
new file mode 100644
index 00000000..6c57d20a
--- /dev/null
+++ b/lib/jasmine-1.0.1/index.js
@@ -0,0 +1,180 @@
+var fs = require('fs');
+var sys = require('sys');
+var path = require('path');
+
+var filename = __dirname + '/jasmine.js';
+global.window = {
+ setTimeout: setTimeout,
+ clearTimeout: clearTimeout,
+ setInterval: setInterval,
+ clearInterval: clearInterval
+};
+var src = fs.readFileSync(filename);
+var jasmine = process.compile(src + '\njasmine;', filename);
+delete global.window;
+
+function noop(){}
+
+jasmine.executeSpecsInFolder = function(folder, done, isVerbose, showColors, matcher){
+ var log = [];
+ var columnCounter = 0;
+ var start = 0;
+ var elapsed = 0;
+ var verbose = isVerbose || false;
+ var fileMatcher = new RegExp(matcher || "\.js$");
+ var colors = showColors || false;
+ var specs = jasmine.getAllSpecFiles(folder, fileMatcher);
+
+ var ansi = {
+ green: '\033[32m',
+ red: '\033[31m',
+ yellow: '\033[33m',
+ none: '\033[0m'
+ };
+
+ for (var i = 0, len = specs.length; i < len; ++i){
+ var filename = specs[i];
+ require(filename.replace(/\.*$/, ""));
+ }
+
+ var jasmineEnv = jasmine.getEnv();
+ jasmineEnv.reporter = {
+ log: function(str){
+ },
+
+ reportSpecStarting: function(runner) {
+ },
+
+ reportRunnerStarting: function(runner) {
+ sys.puts('Started');
+ start = Number(new Date);
+ },
+
+ reportSuiteResults: function(suite) {
+ var specResults = suite.results();
+ var path = [];
+ while(suite) {
+ path.unshift(suite.description);
+ suite = suite.parentSuite;
+ }
+ var description = path.join(' ');
+
+ if (verbose)
+ log.push('Spec ' + description);
+
+ specResults.items_.forEach(function(spec){
+ if (spec.failedCount > 0 && spec.description) {
+ if (!verbose)
+ log.push(description);
+ log.push(' it ' + spec.description);
+ spec.items_.forEach(function(result){
+ log.push(' ' + result.trace.stack + '\n');
+ });
+ }
+ });
+ },
+
+ reportSpecResults: function(spec) {
+ var result = spec.results();
+ var msg = '';
+ if (result.passed())
+ {
+ msg = (colors) ? (ansi.green + '.' + ansi.none) : '.';
+// } else if (result.skipped) { TODO: Research why "result.skipped" returns false when "xit" is called on a spec?
+// msg = (colors) ? (ansi.yellow + '*' + ansi.none) : '*';
+ } else {
+ msg = (colors) ? (ansi.red + 'F' + ansi.none) : 'F';
+ }
+ sys.print(msg);
+ if (columnCounter++ < 50) return;
+ columnCounter = 0;
+ sys.print('\n');
+ },
+
+
+ reportRunnerResults: function(runner) {
+ elapsed = (Number(new Date) - start) / 1000;
+ sys.puts('\n');
+ log.forEach(function(log){
+ sys.puts(log);
+ });
+ sys.puts('Finished in ' + elapsed + ' seconds');
+
+ var summary = jasmine.printRunnerResults(runner);
+ if(colors)
+ {
+ if(runner.results().failedCount === 0 )
+ sys.puts(ansi.green + summary + ansi.none);
+ else
+ sys.puts(ansi.red + summary + ansi.none);
+ } else {
+ sys.puts(summary);
+ }
+ (done||noop)(runner, log);
+ }
+ };
+ jasmineEnv.execute();
+};
+
+jasmine.getAllSpecFiles = function(dir, matcher){
+ var specs = [];
+
+ if (fs.statSync(dir).isFile() && dir.match(matcher)) {
+ specs.push(dir);
+ } else {
+ var files = fs.readdirSync(dir);
+ for (var i = 0, len = files.length; i < len; ++i){
+ var filename = dir + '/' + files[i];
+ if (fs.statSync(filename).isFile() && filename.match(matcher)){
+ specs.push(filename);
+ }else if (fs.statSync(filename).isDirectory()){
+ var subfiles = this.getAllSpecFiles(filename, matcher);
+ subfiles.forEach(function(result){
+ specs.push(result);
+ });
+ }
+ }
+ }
+
+ return specs;
+};
+
+jasmine.printRunnerResults = function(runner){
+ var results = runner.results();
+ var suites = runner.suites();
+ var msg = '';
+ msg += suites.length + ' test' + ((suites.length === 1) ? '' : 's') + ', ';
+ msg += results.totalCount + ' assertion' + ((results.totalCount === 1) ? '' : 's') + ', ';
+ msg += results.failedCount + ' failure' + ((results.failedCount === 1) ? '' : 's') + '\n';
+ return msg;
+};
+
+function now(){
+ return new Date().getTime();
+}
+
+jasmine.asyncSpecWait = function(){
+ var wait = jasmine.asyncSpecWait;
+ wait.start = now();
+ wait.done = false;
+ (function innerWait(){
+ waits(10);
+ runs(function() {
+ if (wait.start + wait.timeout < now()) {
+ expect('timeout waiting for spec').toBeNull();
+ } else if (wait.done) {
+ wait.done = false;
+ } else {
+ innerWait();
+ }
+ });
+ })();
+};
+jasmine.asyncSpecWait.timeout = 4 * 1000;
+jasmine.asyncSpecDone = function(){
+ jasmine.asyncSpecWait.done = true;
+};
+
+for ( var key in jasmine) {
+ exports[key] = jasmine[key];
+}
\ No newline at end of file
diff --git a/src/Angular.js b/src/Angular.js
index 8997045b..0e26a829 100644
--- a/src/Angular.js
+++ b/src/Angular.js
@@ -144,13 +144,6 @@ var _undefined = undefined,
*
*
* @example
- * //TODO this example current doesn't show up anywhere because the overview template doesn't
- * // render it.
- *
- * The following example filter reverses a text string. In addition, it conditionally makes the
- * text upper-case (to demonstrate optional arguments) and assigns color (to demonstrate DOM
- * modification).
-
+ The following example filter reverses a text string. In addition, it conditionally makes the
+ text upper-case (to demonstrate optional arguments) and assigns color (to demonstrate DOM
+ modification).
+
+
{{"hello"|reverse}} : {{"hello"|reverse}}
{{"hello"|reverse:true}} : {{"hello"|reverse:true}}
{{"hello"|reverse:true:"blue"}} :
{{"hello"|reverse:true:"blue"}}
- * //TODO: I completely dropped a mention of using the other option (setter method), it's
+ * @TODO: I completely dropped a mention of using the other option (setter method), it's
* confusing to have two ways to do the same thing. I just wonder if we should prefer using the
* setter way over direct assignment because in the future we might want to be able to intercept
* filter registrations for some reason.
diff --git a/src/validators.js b/src/validators.js
index 3eb11f78..fd18d66c 100644
--- a/src/validators.js
+++ b/src/validators.js
@@ -1,4 +1,4 @@
-foreach({
+extend(angularValidator, {
'noop': function() { return _null; },
'regexp': function(value, regexp, msg) {
@@ -132,4 +132,4 @@ foreach({
return inputState.error;
}
-}, function(v,k) {angularValidator[k] = v;});
+});
diff --git a/src/widgets.js b/src/widgets.js
index 5eda5345..7a06fd6c 100644
--- a/src/widgets.js
+++ b/src/widgets.js
@@ -244,13 +244,28 @@ angularWidget('option', function(){
});
-/*ng:doc
- * @type widget
- * @name ng:include
+/**
+ * @ngdoc widget
+ * @name angular.widget.ng:include
*
* @description
+ * Include external HTML fragment.
+ *
+ * Keep in mind that Same Origin Policy applies to included resources
+ * (e.g. ng:include won't work for file:// access).
+ *
+ * @param {string} src expression evaluating to URL.
+ * @param {Scope=} [scope=new_child_scope] expression evaluating to angular.scope
*
* @example
+ *
+ * date filter
+ * html filter
+ * (blank)
+ *
+ * url = {{url}}
+ *
+ *
*
* @scenario
*/
@@ -299,6 +314,36 @@ angularWidget('ng:include', function(element){
}
});
+/**
+ * @ngdoc widget
+ * @name angular.widget.ng:switch
+ *
+ * @description
+ * Conditionally change the DOM structure.
+ *
+ * @usageContent
+ * ...
+ * ...
+ * ...
+ * ...
+ *
+ * @param {*} on expression to match against ng:switch-when .
+ *
+ * @example
+
+ settings
+ home
+
+ switch={{switch}}
+
+
+ Settings Div
+ Home Span
+
+
+ *
+ * @scenario
+ */
var ngSwitch = angularWidget('ng:switch', function (element){
var compiler = this,
watchExpr = element.attr("on"),
--
cgit v1.2.3