Document Blaze.Var, check in doctool.js

This commit is contained in:
David Greenspan
2014-04-29 11:05:03 -07:00
parent 310dcc5528
commit e9c388933f
6 changed files with 450 additions and 11 deletions

View File

@@ -1,9 +1,87 @@
// `[new] Blaze.Var(initializer[, equalsFunc])`
//
// A Var is a reactive mutable variable which may be initialized with a
// value or a with a reactive function. If the initializer is a reactive
// function, a Deps Computation is kicked off from the constructor
// that updates the reactive variable.
/**
* ## [new] Blaze.Var(initializer[, equalsFunc])
*
* A reactive mutable variable which may be initialized with a value
* or with a function to immediately autorun.
*
* * `initializer` - A function or a non-function value to use to
* initialize the Var. If a function is given, it is called in
* a `Deps.autorun` nested within the current Deps computation.
*
* * `equalsFunc` - A comparator function that takes two arguments
* and returns a boolean. The value of the Var is only considered
* to have changed (for the purpose of invalidating Computations)
* if `equalsFunc(newValue, oldValue)` is truthy. If `equalsFunc`
* is not given, `===` is used.
*
* Blaze.Var holds a single reactive value, providing `get` and `set`
* methods that obey the usual reactive contract of a Deps data
* source. (Namely, calling `get` causes the current Computation to
* depend on the value, and calling `set` invalidates any dependent
* Computations if it changes the value.)
*
* If a function is provided as an initializer, it is called to set
* the initial value of the Var, and a Computation is started that
* sets the value of the Var each time it re-runs. Because this new
* (inner) Computation is nested in the current (outer) Computation,
* when the outer Computation is invalidated, the inner Computation
* is stopped. A Var whose Computation is stopped continues to be
* reactively gettable and settable in the usual way.
*
* To avoid runaway Vars, an outer Computation is required to create a
* Var with a function as initializer. As long as the outer Computation
* is eventually invalidated or stopped, the Var will eventually
* stop recomputing its value.
*
* Example:
*
* ```
var a = Blaze.Var(1);
var b = Blaze.Var(1);
Deps.autorun(function () {
console.log('LOG:', a.get() + b.get());
});
// => LOG: 2
// These statements are assumed to be typed one at a time
// at the console, giving the autorun a chance to re-run
// between them.
b.set(2); // => LOG: 3
a.set(2); // => LOG: 4
a.set(10), b.set(10); // => LOG: 20 (printed once)
* ```
*
* To use a Var with an initializer function, an outer autorun is necessary
* and is used to stop the recomputation.
*
* Example:
*
* ```
var a = Blaze.Var(1);
var b = Blaze.Var(1);
var handle = Deps.autorun(function () {
var c = Blaze.Var(function () {
return a.get() + b.get();
});
Deps.autorun(function () {
console.log('LOG:', c.get());
});
});
// => LOG: 2
// These statements are assumed to be typed one at a time
// at the console.
b.set(2); // => LOG: 3
a.set(2); // => LOG: 4
a.set(10), b.set(10); // => LOG: 20 (printed once)
handle.stop();
a.set(1); // nothing printed
* ```
*/
Blaze.Var = function (initializer, equalsFunc) {
var self = this;
@@ -35,12 +113,24 @@ Blaze.Var = function (initializer, equalsFunc) {
};
_.extend(Blaze.Var.prototype, {
/**
* ## Blaze.Var#get()
*
* Returns the current value of the Var, causing the current
* Deps Computation (if any) to depend on the value.
*/
get: function () {
if (Deps.active)
this.dep.depend();
return this.curValue;
},
/**
* ## Blaze.Var#set(newValue)
*
* Sets the current value of the Var, causing any dependent
* Computations to be invalidated.
*/
set: function (newValue) {
var equals = this.equalsFunc;
var oldValue = this.curValue;
@@ -55,6 +145,12 @@ _.extend(Blaze.Var.prototype, {
this.curValue = newValue;
this.dep.changed();
},
/**
* ## Blaze.Var#toString()
*
* Returns a String representation of the Var, which
* includes the string form of its value.
*/
toString: function () {
return 'Var{' + this.get() + '}';
}

102
packages/blaze/var.md Normal file
View File

@@ -0,0 +1,102 @@
*This file is automatically generated from [`var.js`](var.js).*
## [new] Blaze.Var(initializer[, equalsFunc])
A reactive mutable variable which may be initialized with a value
or with a function to immediately autorun.
* `initializer` - A function or a non-function value to use to
initialize the Var. If a function is given, it is called in
a `Deps.autorun` nested within the current Deps computation.
* `equalsFunc` - A comparator function that takes two arguments
and returns a boolean. The value of the Var is only considered
to have changed (for the purpose of invalidating Computations)
if `equalsFunc(newValue, oldValue)` is truthy. If `equalsFunc`
is not given, `===` is used.
Blaze.Var holds a single reactive value, providing `get` and `set`
methods that obey the usual reactive contract of a Deps data
source. (Namely, calling `get` causes the current Computation to
depend on the value, and calling `set` invalidates any dependent
Computations if it changes the value.)
If a function is provided as an initializer, it is called to set
the initial value of the Var, and a Computation is started that
sets the value of the Var each time it re-runs. Because this new
(inner) Computation is nested in the current (outer) Computation,
when the outer Computation is invalidated, the inner Computation
is stopped. A Var whose Computation is stopped continues to be
reactively gettable and settable in the usual way.
To avoid runaway Vars, an outer Computation is required to create a
Var with a function as initializer. As long as the outer Computation
is eventually invalidated or stopped, the Var will eventually
stop recomputing its value.
Example:
```
var a = Blaze.Var(1);
var b = Blaze.Var(1);
Deps.autorun(function () {
console.log('LOG:', a.get() + b.get());
});
// => LOG: 2
// These statements are assumed to be typed one at a time
// at the console, giving the autorun a chance to re-run
// between them.
b.set(2); // => LOG: 3
a.set(2); // => LOG: 4
a.set(10), b.set(10); // => LOG: 20 (printed once)
```
To use a Var with an initializer function, an outer autorun is necessary
and is used to stop the recomputation.
Example:
```
var a = Blaze.Var(1);
var b = Blaze.Var(1);
var handle = Deps.autorun(function () {
var c = Blaze.Var(function () {
return a.get() + b.get();
});
Deps.autorun(function () {
console.log('LOG:', c.get());
});
});
// => LOG: 2
// These statements are assumed to be typed one at a time
// at the console.
b.set(2); // => LOG: 3
a.set(2); // => LOG: 4
a.set(10), b.set(10); // => LOG: 20 (printed once)
handle.stop();
a.set(1); // nothing printed
```
## Blaze.Var#get()
Returns the current value of the Var, causing the current
Deps Computation (if any) to depend on the value.
## Blaze.Var#set(newValue)
Sets the current value of the Var, causing any dependent
Computations to be invalidated.
## Blaze.Var#toString()
Returns a String representation of the Var, which
includes the string form of its value.

View File

@@ -10,15 +10,15 @@ templates during compilation.
var UL = HTML.UL, LI = HTML.LI, B = HTML.B;
HTML.toHTML(
UL({id: 'mylist'},
LI({'class': 'item'}, "Hello ", B("world"), "!"),
LI({'class': 'item'}, "Goodbye, world")))
UL({id: 'mylist'},
LI({'class': 'item'}, "Hello ", B("world"), "!"),
LI({'class': 'item'}, "Goodbye, world")))
```
```
<ul id="mylist">
<li class="item">Hello <b>world</b>!</li>
<li class="item">Goodbye, world</li>
<li class="item">Hello <b>world</b>!</li>
<li class="item">Goodbye, world</li>
</ul>
```

154
scripts/doctool.js Executable file
View File

@@ -0,0 +1,154 @@
#!/usr/bin/env node
/// # doctool.js
///
/// Usage: `doctool.js ...jsfiles...`
///
/// Reads each `.js` file and writes a `.md` file in the same directory.
/// The output file consists of the concatenation of the "doc comments"
/// in the input file, which are assumed to contain Markdown content,
/// including any section headings necessary to organize the file.
///
/// A "doc comment" must begin at the start of a line or after
/// whitespace. There are two kinds of doc comments: `/** ... */`
/// (block) comments and `/// ...` (triple-slash) comments.
///
/// If a file begins with the magic string "///!README", the output
/// filename is changed to `README.md`.
///
/// Examples:
///
/// ```
/// /**
/// * This is a block comment. The parser strips the sequence,
/// * [optional whitespace, `*`, optional single space] from
/// * every line that has it.
/// *
/// For lines that don't, no big deal.
///
/// Leading whitspace will be preserved here.
///
/// * We can create a bullet list in here:
/// *
/// * * This is a bullet
/// */
/// ```
///
/// ```
/// /** Single-line block comments are also ok. */
/// ```
///
/// ```
/// /**
/// A block comment whose first line doesn't have a `*` receives
/// no stripping of `*` characters on any line.
///
/// * This is a bullet
///
/// */
/// ```
///
/// ```
/// /// A triple-slash comment starts with `///` followed by an
/// /// optional space (i.e. one space is removed if present).
/// /// Multiple consecutive lines that start with `///` are
/// /// treated together as a single doc comment.
/// /** Separate doc comments get separate paragraphs. */
/// ```
var fs = require('fs');
var path = require('path');
process.argv.slice(2).forEach(function (fileName) {
var text = fs.readFileSync(fileName, "utf8");
var outFileName = fileName.replace(/\.js$/, '') + '.md';
if (text.slice(0, 10) === '///!README') {
outFileName = path.join(path.dirname(fileName), 'README.md');
text = text.slice(10);
}
var docComments = [];
for (;;) {
// This regex breaks down as follows:
//
// 1. Start of line
// 2. Optional whitespace (not newline!)
// 3. `///` (capturing group 1) or `/**` (group 2)
// 4. Looking ahead, NOT `/` or `*`
var nextOpener = /^[ \t]*(?:(\/\/\/)|(\/\*\*))(?![\/\*])/m.exec(text);
if (! nextOpener)
break;
text = text.slice(nextOpener.index + nextOpener[0].length);
if (nextOpener[1]) {
// triple-slash
text = text.replace(/^[ \t]/, ''); // optional space
var comment = text.match(/^[^\n]*/)[0];
text = text.slice(comment.length);
var match;
while ((match = /^\n[ \t]*\/\/\/[ \t]?/.exec(text))) {
// multiple lines in a row become one comment
text = text.slice(match[0].length);
var restOfLine = text.match(/^[^\n]*/)[0];
text = text.slice(restOfLine.length);
comment += '\n' + restOfLine;
}
if (comment.trim())
docComments.push(['///', comment]);
} else if (nextOpener[2]) {
// block comment
var rawComment = text.match(/^[\s\S]*?\*\//);
if ((! rawComment) || (! rawComment[0]))
continue;
rawComment = rawComment[0];
text = text.slice(rawComment.length);
rawComment = rawComment.slice(0, -2); // remove final `*/`
if (rawComment.slice(-1) === ' ')
// make that ' */' for the benefit of single-line blocks
rawComment = rawComment.slice(0, -1);
var lines = rawComment.split('\n');
var stripStars = false;
if (lines[0].trim().length === 0) {
// The comment has a newline after the `/**` (with possible whitespace
// between). This is like most comments, though occasionally people
// may write `/** foo */` on one line. Skip the blank line.
lines.splice(0, 1);
if (! lines.length)
continue;
// Now we determine whether this is block comment with a column of
// asterisks running down the left side, so we can strip them.
stripStars = /^[ \t]*\*/.test(lines[1]);
} else {
// Trim beginning of line after `/**`
lines[0] = lines[0].replace(/^\s*/, '');
}
lines = lines.map(function (s) {
// Strip either up to an asterisk and then an optional space,
// or just an optional space, depending on `stripStars`.
if (stripStars)
return s.replace(/^[ \t]*\* ?/, '');
else
return s;
});
var result = lines.join('\n');
if (result.trim())
docComments.push(['/**', result]);
}
}
if (docComments.length) {
var output = docComments.map(function (x) { return x[1]; }).join('\n\n');
var fileShortName = path.basename(fileName);
output = '*This file is automatically generated from [`' +
fileShortName + '`](' + fileShortName + ').*\n\n' + output;
fs.writeFileSync(outFileName, output, 'utf8');
console.log("Wrote " + docComments.length + " comments to " + outFileName);
}
});

57
scripts/doctool.md Normal file
View File

@@ -0,0 +1,57 @@
*This file is automatically generated from [`doctool.js`](doctool.js).*
# doctool.js
Usage: `doctool.js ...jsfiles...`
Reads each `.js` file and writes a `.md` file in the same directory.
The output file consists of the concatenation of the "doc comments"
in the input file, which are assumed to contain Markdown content,
including any section headings necessary to organize the file.
A "doc comment" must begin at the start of a line or after
whitespace. There are two kinds of doc comments: `/** ... */`
(block) comments and `/// ...` (triple-slash) comments.
If a file begins with the magic string "///!README", the output
filename is changed to `README.md`.
Examples:
```
/**
* This is a block comment. The parser strips the sequence,
* [optional whitespace, `*`, optional single space] from
* every line that has it.
*
For lines that don't, no big deal.
Leading whitspace will be preserved here.
* We can create a bullet list in here:
*
* * This is a bullet
*/
```
```
/** Single-line block comments are also ok. */
```
```
/**
A block comment whose first line doesn't have a `*` receives
no stripping of `*` characters on any line.
* This is a bullet
*/
```
```
/// A triple-slash comment starts with `///` followed by an
/// optional space (i.e. one space is removed if present).
/// Multiple consecutive lines that start with `///` are
/// treated together as a single doc comment.
/** Separate doc comments get separate paragraphs. */
```

30
scripts/doctool.md.md Normal file
View File

@@ -0,0 +1,30 @@
*This file is automatically generated from [`doctool.md`](doctool.md).*
This is a block comment. The parser strips the sequence,
[optional whitespace, `*`, optional single space] from
every line that has it.
For lines that don't, no big deal.
Leading whitspace will be preserved here.
We can create a bullet list in here:
* This is a bullet
Single-line block comments are also ok.
A block comment whose first line doesn't have a `*` receives
no stripping of `*` characters on any line.
* This is a bullet
A triple-slash comment starts with `///` followed by an
optional space (i.e. one space is removed if present).
Multiple consecutive lines that start with `///` are
treated together as a single doc comment.
Separate doc comments get separate paragraphs.