A sexy DSL for parsing the arguments passed into functions.
MIT License
I was working on one of my JavaScript libraries and noticed I was doing something silly:
Karait (https://github.com/bcoe/karait)
exports.Queue = function(params, onQueueReady) {
if (typeof(params) === 'function') {
onQueueReady = params;
params = {};
}
var defaults = {
host: 'localhost',
port: 27017,
database: 'karait',
queue: 'messages',
averageMessageSize: 8192,
queueSize: 4096
};
extend(this, defaults, params);
}
There's a lot of ritual around dealing with optional arguments and default parameters!
I did a little digging, and found this problem was pretty widespread:
Node MongoDB Native (https://github.com/christkv/node-mongodb-native)
Collection.prototype.insertAll = function insertAll (docs, options, callback) {
if('function' === typeof options) callback = options, options = {};
if(options == null) options = {};
if(!('function' === typeof callback)) callback = null;
// ... Function body.
}
Express (https://github.com/visionmedia/express)
res.sendfile = function(path, options, fn){
var self = this
, req = self.req
, next = this.req.next
, options = options || {};
// support function as second arg
if ('function' == typeof options) {
fn = options;
options = {};
}
// ... Function body.
};
JSDom (https://github.com/tmpvar/jsdom)
exports.jQueryify = exports.jsdom.jQueryify = function (window /* path [optional], callback */) {
var args = Array.prototype.slice.call(arguments),
callback = (typeof(args[args.length - 1]) === 'function') && args.pop(),
path,
jQueryTag = window.document.createElement("script");
if (args.length > 1 && typeof(args[1] === 'string')) {
path = args[1];
}
// ... Function body.
}
sexy-args is DSL for:
sexy-args enforces sane defaults:
So,
exports.func = function(options, callback) {
if (typeof(options) === 'function') {
callback = options;
options = {};
}
callback = callback || function() {};
// ... Function body.
}
Becomes:
exports.func = function(options, callback) {
sexy.args([this], function() {
// ... Function body.
});
}
Here's what those prior examples would look like if they were using sexy-args:
Karait
exports.Queue = function(params, onQueueReady) {
sexy.args([this, ['object1', 'function1'], 'function1'], {
object1: {
host: 'localhost',
port: 27017,
database: 'karait',
queue: 'messages',
averageMessageSize: 8192,
queueSize: 4096
}
}, function() {
sexy.extend(this, params);
});
}
Express
res.sendfile = function(path, options, fn){
sexy.args([this, 'string1', ['object1', 'function1'], 'function1'], function() {
var self = this,
req = self.req,
next = this.req.next;
// ... Function body.
});
};
JSDom
exports.jQueryify = exports.jsdom.jQueryify = function (window, path, callback) {
sexy.args([this, 'object1', ['string1', 'function1'], 'function1'], function() {
var jQueryTag = window.document.createElement("script");
// ... Function body.
});
}
I think this is much cleaner, which is the goal of sexy-args. Why repeat ritualistic syntax over and over again.
To simplify your life, sexy.args exposes a shorthand for extending objects.
exports.foo = function(path, options, fn){
sexy.args([this, 'string1', ['object1', 'function1'], 'function1'], function() {
sexy.extend(this, options);
});
};
The above code would extend an instance of foo with the options object.
Copyright (c) 2011 Attachments.me. See LICENSE.txt for further details.