var fs = require('fs'), path = require('path'), crypto = require('crypto'), extend = require('soak').mixin, inherit = require('soak').inherit, metrics = require('./metrics'), undefsafe = require('undefsafe'), EventEmitter = require('events').EventEmitter; module.exports = { // Create a base observable object that inherits from EventEmitter. This // allows us to create new objects that can trigger events very easily. // // Example: // // var Store = Observable.extend({ // save: function () {} // }); Observable: inherit(EventEmitter), // Helper function for creating an index file in a directory. It loads all // modules within the provided directory excluding the file provided as // "indexpath". These will then be returned. // // Example: // // module.exports = utils.index(__dirname, __filename); index: function (dirname, indexpath) { var extensions = {js: 1}, modules = {}; indexpath = indexpath || path.join(dirname, 'index.js'); // Load all exported objects into a single module. fs.readdirSync(dirname).forEach(function (filename) { var fullpath = path.join(dirname, filename), parts = filename.split('.'), module, name; if (fullpath !== indexpath && extensions[parts.pop()] && '.' !== filename[0]) { name = parts.join('.'); module = require(fullpath); // Grab the function name or module name if possible. if (typeof module.name === 'string') { name = module.name; } modules[name] = module; } }); return modules; }, // Takes an object and a series of method names. Each method will be // re-assigned to the object with the object bound as the methods scope. This // is generally useful for defining callback methods. // // An array of method names can also be passed. // // Example: // // object = {onData: function () {}, onEnd: function () {}); // utils.bindAll(object, 'onData', 'onEnd'); // // // Same as doing. // object.onData = object.onData.bind(object); // object.onEnd = object.onEnd.bind(object); bindAll: function (object /* args */) { var methods = [].slice.call(arguments, 1); if (arguments.length === 2 && Array.isArray(arguments[1])) { methods = arguments[1]; } methods.forEach(function (method) { if (typeof object[method] === 'function') { object[method] = object[method].bind(object); } }); return object; }, // Takes a namespace string, and object and a series of method names. // // When each method is called that will be incrememented in the metrics // using the namespace and the method name. // // An array of method names can also be passed. // // Example: // // object = {onData: function () {}, onEnd: function () {}); // utils.bindMetrics('object', object, 'onData', 'onEnd'); // bindMetrics: function (namespace, object /* args */) { var methods = [].slice.call(arguments, 2); if (arguments.length === 3 && Array.isArray(arguments[2])) { methods = arguments[2]; } methods.forEach(function (method) { if (typeof object[method] === 'function' && method !== 'constructor') { var original = object[method]; object[method] = function () { metrics.increment(namespace + '.method.' + method); original.apply(object, [].slice.call(arguments)); }; } }); return object; }, // Extends the first argument with the properties of the subsequent // arguments. extend: extend, // Simplifies the process of extending existing objects. inherit: inherit, extract: function (obj /* keys */) { var keys = [].slice.call(arguments, 1), collected = {}; keys.forEach(function (key) { if (obj[key]) { collected[key] = obj[key]; } }); return collected; }, isAjax: function (req) { return (req.get('X-Requested-With') || '').toLowerCase() === 'xmlhttprequest'; }, shortcode: function (length) { var vowels = 'aeiou', consonants = 'bcdfghjklmnpqrstvwxyz', word = '', index = 0, set; if (length === undefined) { length = 3; } for (; index < length; index += 1) { set = (index % 2 === 0) ? consonants : vowels; word += set[Math.floor(Math.random() * set.length)]; } return word; }, // Returns a gravatar url for the email address provided. An optional size // parameter can be provided to specify the size of the avatar to generate. gravatar: function (email, size) { email = (email || '').trim().toLowerCase(); var hash = crypto.createHash('md5').update(email).digest('hex'); return 'http://www.gravatar.com/avatar/' + hash + '?s=' + (size || 29); // 26 }, re: { flatten: /\s+/g, body: /