Created
January 17, 2012 22:43
-
-
Save AdrianRossouw/1629491 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Underscore mixing for partial functions and async calls. | |
// Based on this microsoft post: http://msdn.microsoft.com/en-us/scriptjunkie/gg575560 | |
_.mixin({ | |
// Turn a normal function into an asynchronous version. | |
// It will return a function that expect's the last argument | |
// to be a callback expecting (err, result) as arguments. | |
wrapAsync: function(fn) { | |
return function() { | |
var args = _(arguments).toArray(); | |
var next = args.pop(); | |
var result = fn.apply(null, args); | |
next(null, result); | |
} | |
}, | |
// Generate a closure with parts of the arguments already filled out. | |
// This does not bind 'this', so it is left up the caller to use the right | |
// context. | |
partial: function(fn){ | |
var aps = Array.prototype.slice; | |
var argsOrig = aps.call(arguments, 1); | |
return function(){ | |
var args = [], | |
argsPartial = aps.call(arguments), | |
i = 0; | |
// Iterate over all the originally-specified arguments. If that | |
// argument was the `_.__` placeholder, use the next just- | |
// passed-in argument, otherwise use the originally-specified | |
// argument. | |
for ( ; i < argsOrig.length; i++ ) { | |
args[i] = argsOrig[i] === _.__ | |
? argsPartial.shift() | |
: argsOrig[i]; | |
} | |
// If any just-passed-in arguments remain, add them to the end. | |
return fn.apply( this, args.concat( argsPartial ) ); | |
}; | |
}, | |
// Wrap a non-async call with a partial. | |
partialAsync: function() { | |
var pArgs = _(arguments).toArray(); | |
var fn = pArgs.shift(); | |
pArgs.unshift(_.wrapAsync(callback)); | |
return _.partial.apply(null, pArgs); | |
}, | |
__: {}, // Identity of placeholder fields | |
}); |
Here's the version just using async.js, before I added the partial mixins. note all the extra functions created in the recurseFns to do simple processing on it.
function rmTree(filepath, next) {
function _joinPath(f) { return path.join(filepath, f); }
var recurseFns = [
async.apply(fs.readdir, filepath),
function(files, next) { next(null, _(files).toArray()); },
function(files, next) { next(null, _(files).map(_joinPath)); },
function(files, next) { async.forEachSeries(files, rmTree, next); },
async.apply(fs.rmdir, filepath)
];
async.waterfall([
async.apply(fs.lstat, filepath),
function(stat, next) {
if (stat.isFile() || stat.isSymbolicLink()) return fs.unlink(filepath, next);
if (!stat.isDirectory()) return next(new Error('Unrecognized file.'));
async.waterfall(recurseFns, next);
}
], next);
}
This is the version using Step I started out with. I don't like how step overloads this
and uses it as a callback. Async plays nicely with the node.js standard mechanism for callbacks and error handling.
// Recursive rm.
function rm(filepath, callback) {
var killswitch = false;
fs.lstat(filepath, function(err, stat) {
if (err) return callback(err);
if (stat.isFile() || stat.isSymbolicLink()) return fs.unlink(filepath, callback);
if (!stat.isDirectory()) return callback(new Error('Unrecognized file.'));
Step(function() {
fs.readdir(filepath, this);
},
function(err, files) {
if (err) throw err;
if (files.length === 0) return this(null, []);
var group = this.group();
_(files).each(function(file) {
rm(path.join(filepath, file), group());
});
},
function(err) {
if (err) return callback(err);
fs.rmdir(filepath, callback);
});
});
};
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I wrote these to use with caolan's async.js.
I was getting annoyed having to make functions for every little thing, like using underscore map in async.waterfall.
Here's an example of it being used :