Permalink
Browse files

initial import

  • Loading branch information...
0 parents commit 95d2c53b0102b718e771a895ddb834c909c83b0b @tasogarepg committed Mar 11, 2012
Showing with 699 additions and 0 deletions.
  1. +22 −0 LICENSE
  2. +144 −0 README.md
  3. +132 −0 lib/node-block.js
  4. +15 −0 package.json
  5. +3 −0 test/mocha.opts
  6. +381 −0 test/node-block.test.js
  7. +1 −0 test/rsc/_a.txt
  8. +1 −0 test/rsc/_b.txt
22 LICENSE
@@ -0,0 +1,22 @@
+(The MIT License)
+
+Copyright (c) 2012 tasogarepg <tasogare.pg@gmail.com>
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+'Software'), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
144 README.md
@@ -0,0 +1,144 @@
+# node-block
+
+An async contrl-flow library for Node.js.
+Easily parallel execution and error handling.
+
+## Installation
+
+ $ npm install node-block
+
+## Example
+
+```js
+var fs = require('fs');
+var block = require('node-block.js').block;
+
+block(
+ function() {
+ fs.readFile('/path/to/file1', 'utf8', this.async('d1'));
+ fs.readFile('/path/to/file2', 'utf8', this.async('d2'));
+ },
+ function() {
+ var str = this.data.d1 + this.data.d2;
+ console.log(str);
+ }
+)();
+```
+
+### Error handling
+
+Function name is `cat` and `fin`.
+
+```js
+var fs = require('fs');
+var block = require('node-block.js').block;
+
+block(
+ function() {
+ fs.readFile('/path/to/file1', 'utf8', this.async('d1'));
+ fs.readFile('/path/to/file2', 'utf8', this.async('d2'));
+ },
+ function() {
+ this.data.d3 = this.data.d1 + this.data.d2;
+ },
+ function cat(e) { // catch
+ console.log(e);
+ throw e;
+ },
+ function fin() { // finally
+ console.log('fin'); // always run
+ }
+)();
+```
+
+### Jump to end
+
+call `this.end()` with return.
+
+```js
+var fs = require('fs');
+var block = require('node-block.js').block;
+
+block(
+ function() {
+ if (true) {
+ return this.end(); // called with return
+ }
+ },
+ function() {
+ // not run here.
+ },
+ function cat(e) { // catch
+ // when errorless, not run here.
+ },
+ function fin() { // finally
+ console.log('fin');
+ }
+)();
+```
+
+### Callback
+
+sample() is called after fin().
+
+```js
+var fs = require('fs');
+var block = require('node-block.js').block;
+
+block(
+ function() {
+ fs.readFile('/path/to/file1', 'utf8', this.async('d1'));
+ },
+ function fin() {
+ console.log('fin');
+ }
+)(sample);
+
+function sample(err){
+ console.log(this.data.d1);
+}
+```
+
+### Nesting
+
+```js
+var fs = require('fs');
+var block = require('node-block.js').block;
+
+block(
+ function() {
+ fs.readFile('/path/to/file1', 'utf8', this.async('d1'));
+ fs.readFile('/path/to/file2', 'utf8', this.async('d2'));
+ },
+ function() {
+ fs.readFile('/path/to/file3', 'utf8', this.async('d3'));
+ block(
+ function() {
+ fs.readFile('/path/to/file4', 'utf8', this.async('e1'));
+ fs.readFile('/path/to/file5', 'utf8', this.async('e2'));
+ },
+ function() {
+ fs.readFile('/path/to/file6', 'utf8', this.async('e3'));
+ }
+ )(this.async('d4'));
+ },
+ function() {
+ var str = this.data.d1 + this.data.d2 + this.data.d3 +
+ this.data.d4.e1 + this.data.d4.e2 + this.data.d4.e3;
+ console.log(str);
+ }
+)();
+```
+
+## About API
+
+### this.async([String dataName])
+Make a callback for async function. [String dataName] is name of setting result data. It's named arbitrarily.
+
+### this.end([Error err])
+Jump to end. If [Error err] is set jump to cat(), else jump to fin() or callback. If cat(), fin(), callback don't exist , exit block.
+This api must be called with 'return'.
+
+## License
+
+The MIT License
@@ -0,0 +1,132 @@
+'use strict';
+
+exports.block = block;
+
+function block() {
+ var funcs = Array.prototype.slice.call(arguments);
+ var b = new BlockInfo(funcs);
+ return b.start.bind(b);
+}
+
+function BlockInfo(funcs) {
+ this.stepList = [];
+ this.data = [];
+ this.cat = null;
+ this.fin = null;
+ this.cb = null;
+ var that = this;
+ funcs.forEach(function(func) {
+ var step = new StepInfo(that, that.stepList.length, func);
+ that.stepList.push(step);
+ if (func.name == 'cat') {
+ that.cat = step;
+ that.cat.func = function(err, data) {
+ if (!err) return;
+ func(err, data);
+ this.errBaton = null;
+ };
+ } else if (func.name == 'fin') {
+ that.fin = step;
+ }
+ });
+}
+
+BlockInfo.prototype.start = function(cb) {
+ if (this.cb) {
+ this.stepList.pop();
+ this.cb = null;
+ }
+ if (cb) {
+ this.cb = new StepInfo(this, this.stepList.length, cb);
+ this.stepList.push(this.cb);
+ }
+ this.next(null, 0);
+};
+
+BlockInfo.prototype.next = function(err, stepIndex) {
+ if (stepIndex >= this.stepList.length) {
+ return;
+ }
+ var step = this.stepList[stepIndex];
+ if (step.isDone) return;
+ step.isDone = true;
+ step.errBaton = err;
+ step.nextLock = true;
+ try {
+ step.run();
+ } catch (e) {
+ step.end(e);
+ return;
+ }
+ step.nextLock = false;
+ if (step.asyncCount <= 0 && step.endCount == 0) {
+ this.next(step.errBaton, step.stepIndex+1);
+ }
+};
+
+BlockInfo.prototype.end = function(err) {
+ err = err || null;
+ if (err && this.cat && !this.cat.isDone) {
+ this.next(err, this.cat.stepIndex);
+ } else if (this.fin && !this.fin.isDone) {
+ this.next(err, this.fin.stepIndex);
+ } else if (this.cb && !this.cb.isDone) {
+ this.next(err, this.cb.stepIndex);
+ } else {
+ if (err) throw err;
+ }
+};
+
+function StepInfo(block, stepIndex, func) {
+ this.block = block;
+ this.stepIndex = stepIndex;
+ this.asyncCount = 0;
+ this.endCount = 0;
+ this.isDone = false;
+ this.nextLock = false;
+ this.errBaton = null;
+ this.data = block.data;
+ this.func = func;
+}
+
+StepInfo.prototype.run = function() {
+ this.func(this.errBaton, this.data);
+};
+
+StepInfo.prototype.end = function(err) {
+ if (this.endCount++ === 0) {
+ this.block.end(err);
+ }
+};
+
+StepInfo.prototype.async = function(dataName) {
+ this.asyncCount++;
+ var that = new AsyncInfo(this, dataName);
+ return function(err) {
+ var step = that.step;
+ var block = step.block;
+ if (err) {
+ step.end(err);
+ return;
+ }
+ if (that.dataName) {
+ var result = Array.prototype.slice.call(arguments, 1);
+ if (result.length === 0) {
+ block.data[that.dataName] = null;
+ } else if (result.length === 1) {
+ block.data[that.dataName] = result[0];
+ } else {
+ block.data[that.dataName] = result;
+ }
+ }
+ step.asyncCount--;
+ if (step.asyncCount <= 0 && !step.nextLock) {
+ block.next(step.errBaton, step.stepIndex+1);
+ }
+ };
+};
+
+function AsyncInfo(step, dataName) {
+ this.step = step;
+ this.dataName = dataName || null;
+}
@@ -0,0 +1,15 @@
+{
+ "name": "node-block",
+ "version": "0.1.0",
+ "description": "An async contrl-flow library for Node.js. Parallelable and Nestable.",
+ "keywords": ["control-flow"],
+ "author": "tasogarepg <tasogare.pg@gmail.com>",
+ "homepage": "http://github.com/tasogarepg/node-block",
+ "repository": "git://github.com/tasogarepg/node-block.git",
+ "main": "./lib/node-block.js",
+ "engines": { "node": ">= 0.4.0" },
+ "dependencies": {},
+ "devDependencies": {
+ "mocha": "*"
+ }
+}
@@ -0,0 +1,3 @@
+--ui bdd
+--reporter spec
+--timeout 5000
Oops, something went wrong.

0 comments on commit 95d2c53

Please sign in to comment.