Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

[init] Initial commit

  • Loading branch information...
commit a73e535e09c780022620224e081135c41589c2e8 0 parents
@3rd-Eden authored
1  .gitignore
@@ -0,0 +1 @@
+node_modules
42 README.md
@@ -0,0 +1,42 @@
+# Flow control? Why not zoidberg?
+
+### Module status: Work in progress
+
+First of all, fuck yea, this module name wasn't taken, (\/)(;,,;)(\/) whoop
+whoop whoop.
+
+What zoidberg makes special is that is everything is run inside a domain. This
+ensures that the callback is ALWAYS called even when the iterators throw a
+function. No more worries, fucking awesome yo.
+
+Also, a flow control library is something you should have build once in your
+Node.js career.
+
+### API
+
+```js
+var zoidberg = require('zoidberg');
+
+// iterate over an array
+zoidberg.forEach(arrayish, function forEach(item, callback) {
+ callback(new Error('Foo Bar'));
+}, function done(err) {
+ // Error...
+});
+
+function done(err) {
+ console.log(err.message); // Operation timed out
+}
+
+// if the callback is not fired in x then it will return with an error
+done.timeout = 987429;
+
+// iterate over an array with timeout
+zoidberg.forEach(arrayish, function forEach(item, callback) {
+ callback(new Error('Foo Bar'));
+}, done);
+```
+
+### LICENSE
+
+MIT
30 package.json
@@ -0,0 +1,30 @@
+{
+ "name": "zoidberg",
+ "version": "0.0.0",
+ "description": "Flow control? Why not zoidberg?",
+ "main": "zoidberg.js",
+ "directories": {
+ "test": "test"
+ },
+ "devDependencies": {
+ "mocha": "~1.8.1",
+ "chai": "~1.4.2"
+ },
+ "bundledDependencies": [
+ "mocha"
+ ],
+ "scripts": {
+ "test": "./node_modules/.bin/mocha $(shell find test -name '*.test.js')"
+ },
+ "repository": "",
+ "keywords": [
+ "flow",
+ "control",
+ "flow control",
+ "async",
+ "zoidberg",
+ "whoopwhoopwhoop"
+ ],
+ "author": "Arnout Kazemier",
+ "license": "MIT"
+}
60 test/api.test.js
@@ -0,0 +1,60 @@
+describe('zoidberg', function () {
+ 'use strict';
+
+ /**
+ * Assertations.
+ */
+ var chai = require('chai')
+ , expect = chai.expect;
+
+ chai.Assertion.includeStack = true;
+
+ /**
+ * whoopwhoopwhoop.
+ */
+ var zoidberg = require('../zoidberg');
+
+ describe('#forEach', function () {
+ var obj = { one: 1, two: 2, three: 3, four: 4 }
+ , arr = [1, 2, 3, 4];
+
+ it('accepts Arrays', function (done) {
+ zoidberg.forEach(arr, function forEach(item, callback) {
+ expect(item).to.be.a('number');
+ expect(callback).to.be.a('function');
+
+ callback();
+ }, done);
+ });
+
+ it('captures sync thrown errors', function (done) {
+ zoidberg.forEach(arr, function forEach(item, callback) {
+ throw new Error('throw an error');
+ }, function processed(err) {
+ expect(err).to.be.a('error');
+ expect(err.message).to.equal('throw an error');
+
+ done();
+ });
+ });
+
+ it('captures async thrown errors', function (done) {
+ zoidberg.forEach(arr, function forEach(item, callback) {
+ process.nextTick(function () {
+ throw new Error('throw an error');
+ });
+ }, function processed(err) {
+ expect(err).to.be.a('error');
+ expect(err.message).to.equal('throw an error');
+
+ done();
+ });
+ });
+
+ it('accepts Objects', function (done) {
+ zoidberg.forEach(obj, function forEach(key, callback) {
+ callback();
+ }, done);
+ });
+ });
+});
2  test/mocha.opts
@@ -0,0 +1,2 @@
+--reporter spec
+--ui bdd
74 zoidberg.js
@@ -0,0 +1,74 @@
+'use strict';
+
+/**
+ * Domains support is the on of THE reasons that this library exists.
+ *
+ * Woop Woop (\/)(;,,;)(\/)
+ */
+var d = require('domain');
+
+/**
+ * Simple iteration helper that allows us to iterate over arrays and objects.
+ *
+ * @param {Array|Object} collection
+ * @param {Function} iterator
+ * @param {Mixed} context
+ * @api private
+ */
+function each(collection, iterator, context) {
+ if ('forEach' in collection) return collection.forEach(iterator, context);
+
+ for (var i = 0, keys = Object.keys(collection), l = keys.lenght, key; i < l; i++) {
+ key = keys[i];
+
+ iterator.call(context, key, collection[key], i, collection, keys);
+ }
+}
+
+/**
+ * Pointless noop function for when people don't supply a callback or to
+ * override a callback when it's been called with an error.
+ *
+ * @type {Function}
+ * @api private
+ */
+function noop() {}
+
+exports.forEach = function forEach(collection, iterator, callback, context) {
+ if (!callback) callback = noop;
+
+ var domain = d.create()
+ , completed = 0
+ , size = Array.isArray(collection)
+ ? collection.length
+ : Object.keys(collection).length
+ , timeout;
+
+ function forEaching(item) {
+ iterator.call(context, item, function iterating(err) {
+ if (err) {
+ callback.call(context, err);
+ domain.dispose();
+ return callback = noop;
+ }
+
+ if (++completed === size) {
+ domain.dispose();
+ callback.call(context);
+ }
+ });
+ }
+
+ domain.once('error', callback);
+ domain.run(function run() {
+ each(collection, forEaching);
+ });
+
+ //
+ // Optional timeout for when the operation takes to long.
+ //
+ if (callback.timeout) timeout = setTimeout(function kill() {
+ callback(new Error('Operation timed out'));
+ callback = noop;
+ }, callback.timeout);
+};
Please sign in to comment.
Something went wrong with that request. Please try again.