/** * Nimble * Copyright (c) 2011 Caolan McMahon * * Nimble is freely distributable under the MIT license. * * This source code is optimized for minification and gzip compression, not * readability. If you want reassurance, see the test suite. */ (function (exports) { var keys = Object.keys || function (obj) { var results = []; for (var k in obj) { if (obj.hasOwnProperty(k)) { results.push(k); } } return results; }; var fallback = function (name, fallback) { var nativeFn = Array.prototype[name]; return function (obj, iterator, memo) { var fn = obj ? obj[name]: 0; return fn && fn === nativeFn ? fn.call(obj, iterator, memo): fallback(obj, iterator, memo); }; }; var eachSync = fallback('forEach', function (obj, iterator) { var isObj = obj instanceof Object; var arr = isObj ? keys(obj): (obj || []); for (var i = 0, len = arr.length; i < len; i++) { var k = isObj ? arr[i]: i; iterator(obj[k], k, obj); } }); var eachParallel = function (obj, iterator, callback) { var len = obj.length || keys(obj).length; if (!len) { return callback(); } var completed = 0; eachSync(obj, function () { var cb = function (err) { if (err) { callback(err); callback = function () {}; } else { if (++completed === len) { callback(); } } }; var args = Array.prototype.slice.call(arguments); if (iterator.length) { args = args.slice(0, iterator.length - 1); args[iterator.length - 1] = cb; } else { args.push(cb); } iterator.apply(this, args); }); }; var eachSeries = function (obj, iterator, callback) { var keys_list = keys(obj); if (!keys_list.length) { return callback(); } var completed = 0; var iterate = function () { var k = keys_list[completed]; var args = [obj[k], k, obj].slice(0, iterator.length - 1); args[iterator.length - 1] = function (err) { if (err) { callback(err); callback = function () {}; } else { if (++completed === keys_list.length) { callback(); } else { iterate(); } } }; iterator.apply(this, args); }; iterate(); }; var mapSync = fallback('map', function (obj, iterator) { var results = []; eachSync(obj, function (v, k, obj) { results[results.length] = iterator(v, k, obj); }); return results; }); var mapAsync = function (eachfn) { return function (obj, iterator, callback) { var results = []; eachfn(obj, function (value, i, obj, callback) { var cb = function (err, v) { results[results.length] = v; callback(err); }; var args = [value, i, obj]; if (iterator.length) { args = args.slice(0, iterator.length - 1); args[iterator.length - 1] = cb; } else { args.push(cb); } iterator.apply(this, args); }, function (err) { callback(err, results); }); }; }; var filterSync = fallback('filter', function (obj, iterator, callback) { var results = []; eachSync(obj, function (v, k, obj) { if (iterator(v, k, obj)) { results[results.length] = v; } }); return results; }); var filterParallel = function (obj, iterator, callback) { var results = []; eachParallel(obj, function (value, k, obj, callback) { var cb = function (err, a) { if (a) { results[results.length] = value; } callback(err); }; var args = [value, k, obj]; if (iterator.length) { args = args.slice(0, iterator.length - 1); args[iterator.length - 1] = cb; } else { args.push(cb); } iterator.apply(this, args); }, function (err) { callback(err, results); }); }; var reduceSync = fallback('reduce', function (obj, iterator, memo) { eachSync(obj, function (v, i, obj) { memo = iterator(memo, v, i, obj); }); return memo; }); var reduceSeries = function (obj, iterator, memo, callback) { eachSeries(obj, function (value, i, obj, callback) { var cb = function (err, v) { memo = v; callback(err); }; var args = [memo, value, i, obj]; if (iterator.length) { args = args.slice(0, iterator.length - 1); args[iterator.length - 1] = cb; } else { args.push(cb); } iterator.apply(this, args); }, function (err) { callback(err, memo); }); }; exports.each = function (obj, iterator, callback) { return (callback ? eachParallel: eachSync)(obj, iterator, callback); }; exports.map = function (obj, iterator, callback) { return (callback ? mapAsync(eachParallel): mapSync)(obj, iterator, callback); }; exports.filter = function (obj, iterator, callback) { return (callback ? filterParallel: filterSync)(obj, iterator, callback); }; exports.reduce = function (obj, iterator, memo, callback) { return (callback ? reduceSeries: reduceSync)(obj, iterator, memo, callback); }; exports.parallel = function (fns, callback) { var results = new fns.constructor(); eachParallel(fns, function (fn, k, cb) { fn(function (err) { var v = Array.prototype.slice.call(arguments, 1); results[k] = v.length <= 1 ? v[0]: v; cb(err); }); }, function (err) { (callback || function () {})(err, results); }); }; exports.series = function (fns, callback) { var results = new fns.constructor(); eachSeries(fns, function (fn, k, cb) { fn(function (err, result) { var v = Array.prototype.slice.call(arguments, 1); results[k] = v.length <= 1 ? v[0]: v; cb(err); }); }, function (err) { (callback || function () {})(err, results); }); }; }(typeof exports === 'undefined' ? this._ = this._ || {}: exports));