Permalink
Browse files

Added documentatino for most of the utilities, only a few are missing…

… like async, il8n, and log.
  • Loading branch information...
1 parent 4eff4fa commit 2e5bec8a698cccfdb17b3ebc73069bd4616a9a58 @larzconwell larzconwell committed Sep 20, 2012
Showing with 736 additions and 262 deletions.
  1. +2 −1 lib/array.js
  2. +30 −34 lib/core.js
  3. +31 −1 lib/event_buffer.js
  4. +257 −156 lib/file.js
  5. +23 −10 lib/request.js
  6. +267 −20 lib/sorted_collection.js
  7. +42 −34 lib/uri.js
  8. +13 −6 test/array.js
  9. +71 −0 test/file.js
View
3 lib/array.js
@@ -47,7 +47,8 @@ var array = new (function () {
@name array#included
@public
@function
- @return {Array/Boolean} If `item` is included the `array` is returned otherwise false
+ @return {Array/Boolean} If `item` is included the `array` is
+ returned otherwise false
@description Checks if an `item` is included in an `array`
@param {Any} item The item to look for
@param {Array} array The array to check
View
64 lib/core.js
@@ -65,43 +65,39 @@ var core = new (function () {
* 'merge' recurses, to merge object sub-properties together instead
* of just overwriting with the source object.
*/
- this.mixin = (function () {
- return function () {
- var args = Array.prototype.slice.apply(arguments),
- merge = false,
- targ, sources;
- if (args.length > 2) {
- if (typeof args[args.length - 1] == 'boolean') {
- merge = args.pop();
- }
- }
- targ = args.shift();
- sources = args;
- for (var i = 0, ii = sources.length; i < ii; i++) {
- _mix(targ, sources[i], merge);
+ this.mixin = function () {
+ var args = Array.prototype.slice.apply(arguments),
+ merge = false,
+ targ, sources;
+ if (args.length > 2) {
+ if (typeof args[args.length - 1] == 'boolean') {
+ merge = args.pop();
}
- return targ;
- };
- }).call(this);
+ }
+ targ = args.shift();
+ sources = args;
+ for (var i = 0, ii = sources.length; i < ii; i++) {
+ _mix(targ, sources[i], merge);
+ }
+ return targ;
+ };
- this.enhance = (function () {
- return function () {
- var args = Array.prototype.slice.apply(arguments),
- merge = false,
- targ, sources;
- if (args.length > 2) {
- if (typeof args[args.length - 1] == 'boolean') {
- merge = args.pop();
- }
- }
- targ = args.shift();
- sources = args;
- for (var i = 0, ii = sources.length; i < ii; i++) {
- _mix(targ, sources[i], merge, true);
+ this.enhance = function () {
+ var args = Array.prototype.slice.apply(arguments),
+ merge = false,
+ targ, sources;
+ if (args.length > 2) {
+ if (typeof args[args.length - 1] == 'boolean') {
+ merge = args.pop();
}
- return targ;
- };
- }).call(this);
+ }
+ targ = args.shift();
+ sources = args;
+ for (var i = 0, ii = sources.length; i < ii; i++) {
+ _mix(targ, sources[i], merge, true);
+ }
+ return targ;
+ };
})();
View
32 lib/event_buffer.js
@@ -14,7 +14,9 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*
+*/
+/*
This is a very simple buffer for a predetermined set of events. It is unbounded.
It forwards all arguments to any outlet emitter attached with sync().
@@ -29,7 +31,12 @@ Example:
source.emit('data', 'abcdef');
source.emit('data', '123456');
buff.sync(dest);
+*/
+/**
+ @name EventBuffer
+ @namespace EventBuffer
+ @constructor
*/
var EventBuffer = function (src, events) {
@@ -48,6 +55,15 @@ var EventBuffer = function (src, events) {
};
EventBuffer.prototype = new (function () {
+ /**
+ @name EventBuffer#proxyEmit
+ @public
+ @function
+ @description Emit an event by name and arguments or add it to the buffer if
+ no outlet is set
+ @param {String} name The name to use for the event
+ @param {Array} args An array of arguments to emit
+ */
this.proxyEmit = function (name, args) {
if (this.outlet) {
this.emit(name, args);
@@ -57,14 +73,28 @@ EventBuffer.prototype = new (function () {
}
};
+ /**
+ @name EventBuffer#emit
+ @public
+ @function
+ @description Emit an event by name and arguments
+ @param {String} name The name to use for the event
+ @param {Array} args An array of arguments to emit
+ */
this.emit = function (name, args) {
// Prepend name to args
var outlet = this.outlet;
Array.prototype.splice.call(args, 0, 0, name);
outlet.emit.apply(outlet, args);
};
- // Flush the buffer and continue piping new events to the outlet
+ /**
+ @name EventBuffer#sync
+ @public
+ @function
+ @description Flush the buffer and continue piping new events to the outlet
+ @param {Object} outlet The emitter to send events too
+ */
this.sync = function (outlet) {
var buffer = this.eventBuffer
, bufferItem;
View
413 lib/file.js
@@ -16,6 +16,11 @@
*
*/
+/**
+ @name file
+ @namespace file
+*/
+
var fs = require('fs')
, path = require('path')
, JS_PAT = /\.(js|coffee)$/
@@ -36,161 +41,179 @@ var logger = new (function () {
})();
var fileUtils = new (function () {
- var _copyFile = function(fromPath, toPath, opts) {
- var from = path.normalize(fromPath)
- , to = path.normalize(toPath)
- , options = opts || {}
- , fromStat
- , toStat
- , destExists
- , destDoesNotExistErr
- , content
- , filename
- , dirContents
- , targetDir;
-
- fromStat = fs.statSync(from);
+ var _copyFile
+ , _readDir
+ , _rmDir
+ , _watch;
+
+ // Recursively copy files and directories
+ _copyFile = function(fromPath, toPath, opts) {
+ var from = path.normalize(fromPath)
+ , to = path.normalize(toPath)
+ , options = opts || {}
+ , fromStat = fs.statSync(from)
+ , toStat
+ , destExists
+ , destDoesNotExistErr
+ , content
+ , filename
+ , dirContents
+ , targetDir;
+ // Check if the destination path exists then set the path stat
+ try {
+ toStat = fs.statSync(to);
+ destExists = true;
+ }
+ catch (err) {
+ destDoesNotExistErr = err;
+ destExists = true;
+ }
+
+ // Destination exists so copy into directory or overwrite file
+ if (destExists) {
+ // If rename option is given use it otherwise
+ // use original name
+ filename = options.rename || path.basename(from);
+
+ // Copying a directory
+ if (fromStat.isDirectory()) {
+ dirContents = fs.readdirSync(from);
+ targetDir = path.join(to, filename);
+
+ // Overwrite to directory
try {
- //console.dir(to + ' destExists');
- toStat = fs.statSync(to);
- destExists = true;
- }
- catch(e) {
- //console.dir(to + ' does not exist');
- destDoesNotExistErr = e;
- destExists = false;
+ fs.mkdirSync(targetDir, options.mode || 0755)
}
- // Destination dir or file exists, copy into (directory)
- // or overwrite (file)
- if (destExists) {
-
- // If there's a rename-via-copy file/dir name passed, use it.
- // Otherwise use the actual file/dir name
- filename = options.rename || path.basename(from);
-
- // Copying a directory
- if (fromStat.isDirectory()) {
- dirContents = fs.readdirSync(from);
- targetDir = path.join(to, filename);
- // We don't care if the target dir already exists
- try {
- fs.mkdirSync(targetDir, options.mode || 0755);
- }
- catch(e) {
- if (e.code != 'EEXIST') {
- throw e;
- }
- }
- for (var i = 0, ii = dirContents.length; i < ii; i++) {
- //console.log(dirContents[i]);
- _copyFile(path.join(from, dirContents[i]), targetDir);
- }
- }
- // Copying a file
- else {
- content = fs.readFileSync(from);
- // Copy into dir
- if (toStat.isDirectory()) {
- //console.log('copy into dir ' + to);
- fs.writeFileSync(path.join(to, filename), content);
- }
- // Overwrite file
- else {
- //console.log('overwriting ' + to);
- fs.writeFileSync(to, content);
- }
+ catch (err) {
+ if (err.code != 'EEXIST') {
+ throw err;
}
}
- // Dest doesn't exist, can't create it
+
+ // Copy all files
+ for (var i = 0, len = dirContents.length; i < len; i++) {
+ _copyFile(path.join(from, dirContents[i]), targetDir);
+ }
+ }
+ // Copying a file
+ else {
+ content = fs.readFileSync(from);
+
+ // Copying into a directory
+ if (toStat.isDirectory()) {
+ fs.writeFileSync(path.join(to, filename), content)
+ }
+ // Overwriting a file
else {
- throw destDoesNotExistErr;
+ fs.writeFileSync(to, content);
}
}
+ }
+ // Destination dosn't exist
+ else {
+ throw destDoesNotExistErr;
+ }
+ };
+
+ // Return the contents of a given directory
+ _readDir = function (dirPath) {
+ var dir = path.normalize(dirPath)
+ , paths = []
+ , ret = [dir];
- , _copyDir = function (from, to, opts) {
- var createDir = opts.createDir;
+ try {
+ paths = fs.readdirSync(dir);
+ }
+ catch (err) {
+ throw new Error('Could not read path ' + dir);
+ }
+
+ paths.forEach(function (p) {
+ var curr = path.join(dir, p)
+ , stat = fs.statSync(curr);
+
+ if (stat.isDirectory()) {
+ ret = ret.concat(_readDir(curr));
}
+ else {
+ ret.push(curr);
+ }
+ });
- , _readDir = function (dirPath) {
- var dir = path.normalize(dirPath)
- , paths = []
- , ret = [dir];
+ return ret;
+ };
- try {
- paths = fs.readdirSync(dir);
- }
- catch (e) {
- throw new Error('Could not read path ' + dir);
- }
+ // Remove the given directory
+ _rmDir = function (dirPath) {
+ var dir = path.normalize(dirPath)
+ , paths = fs.readdirSync(dir);
- paths.forEach(function (p) {
- var curr = path.join(dir, p);
- var stat = fs.statSync(curr);
- if (stat.isDirectory()) {
- ret = ret.concat(_readDir(curr));
- }
- else {
- ret.push(curr);
- }
- });
+ // Remove each child path
+ paths.forEach(function (p) {
+ var curr = path.join(dir, p)
+ , stat = fs.statSync(curr);
- return ret;
+ if (stat.isDirectory()) {
+ _rmDir(curr);
}
+ else {
+ fs.unlinkSync(curr);
+ }
+ });
- , _rmDir = function (dirPath) {
- var dir = path.normalize(dirPath)
- , paths = [];
- paths = fs.readdirSync(dir);
- paths.forEach(function (p) {
- var curr = path.join(dir, p);
- var stat = fs.statSync(curr);
- if (stat.isDirectory()) {
- _rmDir(curr);
- }
- else {
- fs.unlinkSync(curr);
- }
- });
- fs.rmdirSync(dir);
+ fs.rmdirSync(dir);
+ };
+
+ // Recursively watch js/cs files with a callback
+ _watch = function (p, callback) {
+ fs.stat(p, function (err, stats) {
+ if (err) {
+ return false;
}
- // Recursively watch files with a callback
- , _watch = function (path, callback) {
- fs.stat(path, function (err, stats) {
+ // If file then watch it
+ if (stats.isFile() && JS_PAT.test(p)) {
+ fs.watchFile(p, callback);
+ }
+ // If directory then recursively watch all it's children
+ else if (stats.isDirectory()) {
+ fs.readdir(p, function (err, files) {
if (err) {
- return false;
+ return log.fatal(err);
}
- if (stats.isFile() && JS_PAT.test(path)) {
- fs.watchFile(path, callback);
- }
- else if (stats.isDirectory()) {
- fs.readdir(path, function (err, files) {
- if (err) {
- return log.fatal(err);
- }
- for (var f in files) {
- _watch(path + '/' + files[f], callback);
- }
- });
+
+ for (var f in files) {
+ _watch(path.join(p, files[f]), callback);
}
});
- };
+ }
+ });
+ };
- this.cpR = function (fromPath, toPath, options) {
+ /**
+ @name file#cpR
+ @public
+ @function
+ @description Copies a directory/file to a destination
+ @param {String} fromPath The source path to copy from
+ @param {String} toPath The destination path to copy to
+ @param {Object} opts Options to use
+ @param {Boolean} [opts.silent] If false then will log the command
+ */
+ this.cpR = function (fromPath, toPath, opts) {
var from = path.normalize(fromPath)
, to = path.normalize(toPath)
, toStat
, doesNotExistErr
, paths
, filename
- , opts = options || {};
+ , options = opts || {};
- if (!opts.silent) {
+ if (!options.silent) {
logger.log('cp -r ' + fromPath + ' ' + toPath);
}
-
- opts = {}; // Reset
+ options = {}; // Reset
if (from == to) {
throw new Error('Cannot copy ' + from + ' to itself.');
@@ -200,28 +223,30 @@ var fileUtils = new (function () {
try {
toStat = fs.statSync(to);
}
- catch(e) {
- doesNotExistErr = e;
+ catch (err) {
+ doesNotExistErr = err;
// Get abs path so it's possible to check parent dir
if (!this.isAbsolute(to)) {
- to = path.join(process.cwd() , to);
+ to = path.join(process.cwd(), to);
}
// Save the file/dir name
filename = path.basename(to);
+
// See if a parent dir exists, so there's a place to put the
/// renamed file/dir (resets the destination for the copy)
to = path.dirname(to);
+
try {
toStat = fs.statSync(to);
}
- catch(e) {}
+ catch (err) {}
+
if (toStat && toStat.isDirectory()) {
// Set the rename opt to pass to the copy func, will be used
// as the new file/dir name
- opts.rename = filename;
- //console.log('filename ' + filename);
+ options.rename = filename;
}
else {
throw doesNotExistErr;
@@ -231,6 +256,14 @@ var fileUtils = new (function () {
_copyFile(from, to, opts);
};
+ /**
+ @name file#mkdirP
+ @public
+ @function
+ @description Create the given directory(ies) using the given mode permissions
+ @param {String} dir The directory to create
+ @param {Number} mode The mode to give the created directory(ies)(Default: 0755)
+ */
this.mkdirP = function (dir, mode) {
var dirPath = path.normalize(dir)
, paths = dirPath.split(/\/|\\/)
@@ -240,60 +273,101 @@ var fileUtils = new (function () {
if (paths[0] == '' || /^[A-Za-z]+:/.test(paths[0])) {
currPath = paths.shift() || '/';
currPath = path.join(currPath, paths.shift());
- //console.log('basedir');
}
- while ((next = paths.shift())) {
+
+ while (paths.length) {
+ next = paths.shift();
+
if (next == '..') {
currPath = path.join(currPath, next);
continue;
}
currPath = path.join(currPath, next);
+
try {
- //console.log('making ' + currPath);
fs.mkdirSync(currPath, mode || 0755);
}
- catch(e) {
- if (e.code != 'EEXIST') {
+ catch (err) {
+ if (err.code != 'EEXIST') {
throw e;
}
}
}
};
+ /**
+ @name file#readdirR
+ @public
+ @function
+ @return {Array} Returns the contents as an Array, can be configured via opts.format
+ @description Reads the given directory returning it's contents
+ @param {String} dir The directory to read
+ @param {Object} opts Options to use
+ @param {String} [opts.format] Set the format to return(Default: Array)
+ */
this.readdirR = function (dir, opts) {
var options = opts || {}
, format = options.format || 'array'
- , ret;
- ret = _readDir(dir);
+ , ret = _readDir(dir);
+
return format == 'string' ? ret.join('\n') : ret;
};
- this.rmRf = function (p, options) {
+ /**
+ @name file#rmRf
+ @public
+ @function
+ @description Deletes the given directory/file
+ @param {String} p The path to delete, can be a directory or file
+ @param {Object} opts Options to use
+ @param {String} [opts.silent] If false then logs the command
+ */
+ this.rmRf = function (p, opts) {
var stat
- , opts = options || {};
- if (!opts.silent) {
+ , options = opts || {};
+
+ if (!options.silent) {
logger.log('rm -rf ' + p);
}
+
try {
stat = fs.statSync(p);
+
if (stat.isDirectory()) {
_rmDir(p);
}
else {
fs.unlinkSync(p);
}
}
- catch (e) {}
+ catch (err) {}
};
+ /**
+ @name file#isAbsolute
+ @public
+ @function
+ @return {Boolean/String} If it's absolute the first char is returned otherwise false
+ @description Checks if a given path is absolute or relative
+ @param {String} p Path to check
+ */
this.isAbsolute = function (p) {
var match = /^[A-Za-z]+:\\|^\//.exec(p);
+
if (match && match.length) {
return match[0];
}
return false;
};
+ /**
+ @name file#absolutize
+ @public
+ @function
+ @return {String} Returns the absolute path for the given path
+ @description Returns the absolute path for the given path
+ @param {String} p The path to get the absolute path for
+ */
this.absolutize = function (p) {
if (this.isAbsolute(p)) {
return p;
@@ -306,11 +380,13 @@ var fileUtils = new (function () {
this.basedir = function (p) {
var str = p || ''
, abs = this.isAbsolute(p);
+
if (abs) {
return abs;
}
// Split into segments
str = str.split(/\\|\//)[0];
+
// If the path has a leading asterisk, basedir is the current dir
if (str.indexOf('*') > -1) {
return '.';
@@ -321,29 +397,38 @@ var fileUtils = new (function () {
}
};
- // Search for a directory in parent directories if it can't be found in cwd
- this.searchParentPath = function(location, callback) {
- var cwd = process.cwd();
-
- if(!location) {
+ /**
+ @name file#searchParentPath
+ @public
+ @function
+ @description Search for a directory/file in the current directory and parent directories
+ @param {String} p The path to search for
+ @param {Function} callback The function to call once the path is found
+ */
+ this.searchParentPath = function(p, callback) {
+ if (!p) {
// Return if no path is given
return;
}
- var relPath = ''
+ var cwd = process.cwd()
+ , relPath = ''
, i = 5 // Only search up to 5 directories
, pathLoc
, pathExists;
- while(--i >= 0) {
- pathLoc = path.join(cwd, relPath, location);
+ while (--i >= 0) {
+ pathLoc = path.join(cwd, relPath, p);
pathExists = this.existsSync(pathLoc);
- if(pathExists) {
+ // If path exists call the callback with the full path
+ if (pathExists) {
callback && callback(undefined, pathLoc);
break;
- } else {
+ }
+ // Path doesn't exist so search the parent
+ else {
// Dir could not be found
- if(i === 0) {
+ if (i === 0) {
callback && callback(new Error("Path \"" + pathLoc + "\" not found"), undefined);
break;
}
@@ -356,6 +441,14 @@ var fileUtils = new (function () {
}
};
+ /**
+ @name file#watch
+ @public
+ @function
+ @description Watch a given path then calls the callback once a change occurs
+ @param {String} path The path to watch
+ @param {Function} callback The function to call when a change occurs
+ */
this.watch = function () {
_watch.apply(this, arguments);
};
@@ -366,25 +459,33 @@ var fileUtils = new (function () {
// Compatibility for fs.existsSync(0.8) and path.existsSync(0.6)
this.existsSync = (typeof fs.existsSync === 'function') ? fs.existsSync : path.existsSync;
- // Require a module locally, i.e., in the node_modules directory
- // in the current directory
+ /**
+ @name file#requireLocal
+ @public
+ @function
+ @return {Object} The given module is returned
+ @description Require a local module from the node_modules in the current directory
+ @param {String} module The module to require
+ @param {String} message An option message to throw if the module doesn't exist
+ */
this.requireLocal = function(module, message) {
// Try to require in the application directory
try {
dep = require(path.join(process.cwd(), 'node_modules', module));
}
- catch(err) {
- if(message) {
+ catch (err) {
+ if (message) {
throw new Error(message);
}
+
throw new Error('Module "' + module + '" could not be found as a ' +
'local module.\n Please make sure there is a node_modules directory in the ' +
'current directory,\n and install it by doing "npm install ' +
module + '"');
}
+
return dep;
};
-
})();
module.exports = fileUtils;
View
33 lib/request.js
@@ -37,14 +37,27 @@ var formatters = {
}
}
-var request = function (options, callback) {
+/**
+ @name request
+ @namespace request
+ @public
+ @function
+ @description Sends requests to the given url sending any data if the method is POST or PUT
+ @param {Object} opts The options to use for the request
+ @param {String} [opts.url] The URL to send the request to
+ @param {String} [opts.method=GET] The method to use for the request
+ @param {Object} [opts.headers] Headers to send on requests
+ @param {String} [opts.data] Data to send on POST and PUT requests
+ @param {String} [opts.dataType] The type of data to send
+*/
+var request = function (opts, callback) {
var client
- , opts = options || {}
- , parsed = url.parse(opts.url)
+ , options = opts || {}
+ , parsed = url.parse(options.url)
, path
, requester = parsed.protocol == 'http:' ? http : https
- , method = (opts.method && opts.method.toUpperCase()) || 'GET'
- , headers = core.mixin({}, opts.headers || {})
+ , method = (options.method && options.method.toUpperCase()) || 'GET'
+ , headers = core.mixin({}, options.headers || {})
, contentLength
, port
, clientOpts;
@@ -62,8 +75,8 @@ var request = function (options, callback) {
}
if (method == 'POST' || method == 'PUT') {
- if (opts.data) {
- contentLength = opts.data.length;
+ if (options.data) {
+ contentLength = options.data.length;
}
else {
contentLength = 0
@@ -92,7 +105,7 @@ var request = function (options, callback) {
, err;
// Successful response
if ((stat > 199 && stat < 300) || stat == 304) {
- dataType = opts.dataType || uri.getFileExtension(parsed.pathname);
+ dataType = options.dataType || uri.getFileExtension(parsed.pathname);
if (formatters[dataType]) {
try {
if (data) {
@@ -119,8 +132,8 @@ var request = function (options, callback) {
callback(e, null);
});
- if ((method == 'POST' || method == 'PUT') && opts.data) {
- client.write(opts.data);
+ if ((method == 'POST' || method == 'PUT') && options.data) {
+ client.write(options.data);
}
client.end();
View
287 lib/sorted_collection.js
@@ -16,6 +16,12 @@
*
*/
+/**
+ @name SortedCollection
+ @namespace SortedCollection
+ @constructor
+*/
+
var SortedCollection = function (d) {
this.count = 0;
this.items = {}; // Hash keys and their values
@@ -26,14 +32,30 @@ var SortedCollection = function (d) {
};
SortedCollection.prototype = new (function () {
- // Interface methods
+ /**
+ @name SortedCollection#addItem
+ @public
+ @function
+ @return {Any} The given val is returned
+ @description Adds a new key/value to the collection
+ @param {String} key The key for the collection item
+ @param {Any} val The value for the collection item
+ */
this.addItem = function (key, val) {
if (typeof key != 'string') {
throw('Hash only allows string keys.');
}
return this.setByKey(key, val);
};
+ /**
+ @name SortedCollection#getItem
+ @public
+ @function
+ @return {Any} The value for the given identifier is returned
+ @description Retrieves the value for the given identifier that being a key or index
+ @param {String/Number} p The identifier to look in the collection for, being a key or index
+ */
this.getItem = function (p) {
if (typeof p == 'string') {
return this.getByKey(p);
@@ -43,28 +65,63 @@ SortedCollection.prototype = new (function () {
}
};
+ /**
+ @name SortedCollection#setItem
+ @public
+ @function
+ @return {Any} The given val is returned
+ @description Sets the item in the collection with the given val, overwriting the existsing item
+ if identifier is an index
+ @param {String/Number} p The identifier set in the collection, being either a key or index
+ @param {Any} val The value for the collection item
+ */
this.setItem = function (p, val) {
if (typeof p == 'string') {
- this.setByKey(p, val);
+ return this.setByKey(p, val);
}
else if (typeof p == 'number') {
- this.setByIndex(p, val);
+ return this.setByIndex(p, val);
}
};
+ /**
+ @name SortedCollection#removeItem
+ @public
+ @function
+ @return {Boolean} Returns true if the item has been removed, false otherwise
+ @description Removes the item for the given identifier
+ @param {String/Number} p The identifier to delete the item for, being a key or index
+ */
this.removeItem = function (p) {
if (typeof p == 'string') {
- this.removeByKey(p);
+ return this.removeByKey(p);
}
else if (typeof p == 'number') {
- this.removeByIndex(p);
+ return this.removeByIndex(p);
}
};
+ /**
+ @name SortedCollection#getByKey
+ @public
+ @function
+ @return {Any} The value for the given key item is returned
+ @description Retrieves the value for the given key
+ @param {String} key The key for the item to lookup
+ */
this.getByKey = function (key) {
return this.items[key];
};
+ /**
+ @name SortedCollection#setByKey
+ @public
+ @function
+ @return {Any} The given val is returned
+ @description Sets a item by key assigning the given val
+ @param {String} key The key for the item
+ @param {Any} val The value to set for the item
+ */
this.setByKey = function (key, val) {
var v = null;
if (typeof val == 'undefined') {
@@ -79,6 +136,14 @@ SortedCollection.prototype = new (function () {
return this.items[key];
};
+ /**
+ @name SortedCollection#removeByKey
+ @public
+ @function
+ @return {Boolean} If the item was removed true is returned, false otherwise
+ @description Removes a collection item by key
+ @param {String} key The key for the item to remove
+ */
this.removeByKey = function (key) {
if (typeof this.items[key] != 'undefined') {
var pos = null;
@@ -91,25 +156,55 @@ SortedCollection.prototype = new (function () {
}
this.order.splice(pos, 1); // Remove the key
this.count--; // Decrement the length
+ return true;
+ }
+ else {
+ return false;
}
};
+ /**
+ @name SortedCollection#getByIndex
+ @public
+ @function
+ @return {Any} The value for the given index item is returned
+ @description Retrieves the value for the given index
+ @param {Number} ind The index to lookup for the item
+ */
this.getByIndex = function (ind) {
return this.items[this.order[ind]];
};
+ /**
+ @name SortedCollection#setByIndex
+ @public
+ @function
+ @return {Any} The given val is returned
+ @description Sets a item by index assigning the given val
+ @param {Number} ind The index for the item
+ @param {Any} val The value to set for the item
+ */
this.setByIndex = function (ind, val) {
if (ind < 0 || ind >= this.count) {
throw('Index out of bounds. Hash length is ' + this.count);
}
this.items[this.order[ind]] = val;
+ return this.items[this.order[ind]];
};
- this.removeByIndex = function (pos) {
- var ret = this.items[this.order[pos]];
+ /**
+ @name SortedCollection#removeByIndex
+ @public
+ @function
+ @return {Boolean} If the item was removed true is returned, false otherwise
+ @description Removes a collection item by index
+ @param {Number} ind The index for the item to remove
+ */
+ this.removeByIndex = function (ind) {
+ var ret = this.items[this.order[ind]];
if (typeof ret != 'undefined') {
- delete this.items[this.order[pos]]
- this.order.splice(pos, 1);
+ delete this.items[this.order[ind]]
+ this.order.splice(ind, 1);
this.count--;
return true;
}
@@ -118,10 +213,26 @@ SortedCollection.prototype = new (function () {
}
};
+ /**
+ @name SortedCollection#hasKey
+ @public
+ @function
+ @return {Boolean} Returns true if the item exists, false otherwise
+ @description Checks if a key item exists in the collection
+ @param {String} key The key to look for in the collection
+ */
this.hasKey = function (key) {
return typeof this.items[key] != 'undefined';
};
+ /**
+ @name SortedCollection#hasValue
+ @public
+ @function
+ @return {Boolean} Returns true if a key with the given value exists, false otherwise
+ @description Checks if a key item in the collection has a given val
+ @param {Any} val The value to check for in the collection
+ */
this.hasValue = function (val) {
for (var i = 0; i < this.order.length; i++) {
if (this.items[this.order[i]] == val) {
@@ -131,10 +242,26 @@ SortedCollection.prototype = new (function () {
return false;
};
+ /**
+ @name SortedCollection#allKeys
+ @public
+ @function
+ @return {String} Returns all the keys in a string
+ @description Joins all the keys into a string
+ @param {String} str The string to use between each key
+ */
this.allKeys = function (str) {
return this.order.join(str);
};
+ /**
+ @name SortedCollection#replaceKey
+ @public
+ @function
+ @description Joins all the keys into a string
+ @param {String} oldKey The key item to change
+ @param {String} newKey The key item to change the name to
+ */
this.replaceKey = function (oldKey, newKey) {
// If item for newKey exists, nuke it
if (this.hasKey(newKey)) {
@@ -149,18 +276,46 @@ SortedCollection.prototype = new (function () {
}
};
- this.insertAtIndex = function (pos, key, val) {
- this.order.splice(pos, 0, key);
+ /**
+ @name SortedCollection#insertAtIndex
+ @public
+ @function
+ @return {Boolean} Returns true if the item was set at the given index
+ @description Inserts a key/value at a specific index in the collection
+ @param {Number} ind The index to set the item at
+ @param {String} key The key to use at the item index
+ @param {Any} val The value to set for the item
+ */
+ this.insertAtIndex = function (ind, key, val) {
+ this.order.splice(ind, 0, key);
this.items[key] = val;
this.count++;
return true;
};
+ /**
+ @name SortedCollection#insertAfterKey
+ @public
+ @function
+ @return {Boolean} Returns true if the item was set for the given key
+ @description Inserts a key/value item after the given reference key in the collection
+ @param {String} refKey The key to insert the new item after
+ @param {String} key The key for the new item
+ @param {Any} val The value to set for the item
+ */
this.insertAfterKey = function (refKey, key, val) {
- var pos = this.getPos(refKey);
- this.insertAtPos(pos, key, val);
+ var pos = this.getPosition(refKey);
+ return this.insertAtIndex(pos, key, val);
};
+ /**
+ @name SortedCollection#getPosition
+ @public
+ @function
+ @return {Number} Returns the index for the item of the given key
+ @description Retrieves the index of the key item
+ @param {String} key The key to get the index for
+ */
this.getPosition = function (key) {
var order = this.order;
if (typeof order.indexOf == 'function') {
@@ -173,16 +328,28 @@ SortedCollection.prototype = new (function () {
}
};
- this.each = function (func, o) {
- var opts = o || {}
+ /**
+ @name SortedCollection#each
+ @public
+ @function
+ @return {Boolean}
+ @description Loops through the collection and calls the given function
+ @param {Function} func The function to call for each collection item, the arguments
+ are the key and value for the current item
+ @param {Object} opts The options to use
+ @param {Boolean} [opts.keyOnly] Only give the function the key
+ @param {Boolean} [opts.valueOnly] Only give the function the value
+ */
+ this.each = function (func, opts) {
+ var options = opts || {}
, order = this.order;
for (var i = 0, ii = order.length; i < ii; i++) {
var key = order[i];
var val = this.items[key];
- if (opts.keyOnly) {
+ if (options.keyOnly) {
func(key);
}
- else if (opts.valueOnly) {
+ else if (options.valueOnly) {
func(val);
}
else {
@@ -192,14 +359,39 @@ SortedCollection.prototype = new (function () {
return true;
};
+ /**
+ @name SortedCollection#eachKey
+ @public
+ @function
+ @return {Boolean}
+ @description Loops through the collection and calls the given function
+ @param {Function} func The function to call for each collection item, only giving the
+ key to the function
+ */
this.eachKey = function (func) {
- this.each(func, { keyOnly: true });
+ return this.each(func, { keyOnly: true });
};
+ /**
+ @name SortedCollection#eachValue
+ @public
+ @function
+ @return {Boolean}
+ @description Loops through the collection and calls the given function
+ @param {Function} func The function to call for each collection item, only giving the
+ value to the function
+ */
this.eachValue = function (func) {
- this.each(func, { valueOnly: true });
+ return this.each(func, { valueOnly: true });
};
+ /**
+ @name SortedCollection#clone
+ @public
+ @function
+ @return {Object} Returns a new SortedCollection with the data of the current one
+ @description Creates a cloned version of the current collection and returns it
+ */
this.clone = function () {
var coll = new SortedCollection()
, key
@@ -212,6 +404,13 @@ SortedCollection.prototype = new (function () {
return coll;
};
+ /**
+ @name SortedCollection#concat
+ @public
+ @function
+ @description Join a given collection with the current one
+ @param {Object} hNew A SortedCollection to join from
+ */
this.concat = function (hNew) {
for (var i = 0; i < hNew.order.length; i++) {
var key = hNew.order[i];
@@ -220,11 +419,27 @@ SortedCollection.prototype = new (function () {
}
};
+ /**
+ @name SortedCollection#push
+ @public
+ @function
+ @return {Number} Returns the count of items
+ @description Appends a new item to the collection
+ @param {String} key The key to use for the item
+ @param {Any} val The value to use for the item
+ */
this.push = function (key, val) {
this.insertAtIndex(this.count, key, val);
return this.count;
};
+ /**
+ @name SortedCollection#pop
+ @public
+ @function
+ @return {Any} Returns the value for the last item in the collection
+ @description Pops off the last item in the collection and returns it's value
+ */
this.pop = function () {
var pos = this.count-1;
var ret = this.items[this.order[pos]];
@@ -237,12 +452,28 @@ SortedCollection.prototype = new (function () {
}
};
+ /**
+ @name SortedCollection#unshift
+ @public
+ @function
+ @return {Number} Returns the count of items
+ @description Prepends a new item to the beginning of the collection
+ @param {String} key The key to use for the item
+ @param {Any} val The value to use for the item
+ */
this.unshift = function (key, val) {
this.insertAtIndex(0, key, val);
return this.count;
};
- this.shift = function (key, val) {
+ /**
+ @name SortedCollection#shift
+ @public
+ @function
+ @return {Number} Returns the removed items value
+ @description Removes the first item in the list and returns it's value
+ */
+ this.shift = function () {
var pos = 0;
var ret = this.items[this.order[pos]];
if (typeof ret != 'undefined') {
@@ -254,6 +485,16 @@ SortedCollection.prototype = new (function () {
}
};
+ /**
+ @name SortedCollection#splice
+ @public
+ @function
+ @description Removes items from index to the given max and then adds the given
+ collections items
+ @param {Number} index The index to start at when removing items
+ @param {Number} numToRemove The number of items to remove before adding the new items
+ @param {Object} hash the collection of items to add
+ */
this.splice = function (index, numToRemove, hash) {
var _this = this;
// Removal
@@ -302,6 +543,12 @@ SortedCollection.prototype = new (function () {
this.order.sort(comp);
};
+ /**
+ @name SortedCollection#reverse
+ @public
+ @function
+ @description Reverse the collection item list
+ */
this.reverse = function () {
this.order.reverse();
};
View
76 lib/uri.js
@@ -13,11 +13,16 @@
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
- t
+ *
*/
var uri
, string = require('./string');
+/**
+ @name uri
+ @namespace uri
+*/
+
uri = new (function () {
var _isArray = function (obj) {
return obj &&
@@ -27,6 +32,14 @@ uri = new (function () {
!(obj.propertyIsEnumerable('length'));
};
+ /**
+ @name uri#getFileExtension
+ @public
+ @function
+ @return {String} Returns the file extension for a given path
+ @description Gets the file extension fir a path and returns it
+ @param {String} path The path to get the extension for
+ */
this.getFileExtension = function (path) {
var match;
if (path) {
@@ -36,29 +49,24 @@ uri = new (function () {
};
/**
- * Convert a JS Object to querystring (key=val&key=val).
- * Value in arrays will be added as multiple parameters
- * @param obj -- an Object containing only scalars and arrays
- * @param o -- JS object of options for how to format
- * the return string. Supported options:
- * consolidate: (Boolean) take values from elements that
- * can return multiple values (multi-select, checkbox groups)
- * and collapse into a single, comman-delimited value.
- * Defaults to false.
- * (e.g., thisVar=asdf,qwer,zxcv)
- * includeEmpty: (Boolean) include keys in the string for
- * all elements, even if they have no value set (e.g.,
- * even if elemB has no value: elemA=foo&elemB=&elemC=bar).
- * Defaults to false. Note that some false-y values are always
- * valid even without this option, [0, '']. This option extends
- * coverage to [null, undefined, NaN]
- * snakeize: (Boolean) change param names from
- * camelCase to snake_case. Defaults to false.
- * escapeVals: (Boolean) escape the values for XML entities.
- * Defaults to false.
- * @returns A querystring containing the values in the
- * Object
- */
+ @name uri#paramify
+ @public
+ @function
+ @return {String} Returns a querystring contains the given values
+ @description Convert a JS Object to a querystring (key=val&key=val). Values in arrays
+ will be added as multiple parameters
+ @param {Object} obj An Object containing only scalars and arrays
+ @param {Object} o The options to use for formatting
+ @param {Boolean} [o.consolidate=false] take values from elements that can return
+ multiple values (multi-select, checkbox groups) and collapse into a single,
+ comman-delimited value.
+ @param {Boolean} [o.includeEmpty=false] include keys in the string for all elements, even
+ they have no value set (e.g., even if elemB has no value: elemA=foo&elemB=&elemC=bar).
+ Note that some false-y values are always valid even without this option, [0, ''].
+ This option extends coverage to [null, undefined, NaN]
+ @param {Boolean} [o.snakeize=false] change param names from camelCase to snake_case.
+ @param {Boolean} [o.escapeVals=false] escape the values for XML entities.
+ */
this.paramify = function (obj, o) {
var opts = o || {},
str = '',
@@ -125,16 +133,16 @@ uri = new (function () {
};
/**
- * Convert the values in a query string (key=val&key=val) to
- * an Object
- * @param str -- A querystring
- * @param o -- JS object of options, currently:
- * consolidate: (Boolean) convert mutliple instances of
- * the same key into an array of values instead of
- * overwriting. Defaults to true.
- * @returns JavaScript key/val object with the values from
- * the querystring
- */
+ @name uri#objectify
+ @public
+ @function
+ @return {Object} JavaScript key/val object with the values from the querystring
+ @description Convert the values in a query string (key=val&key=val) to an Object
+ @param {String} str The querystring to convert to an object
+ @param {Object} o The options to use for formatting
+ @param {Boolean} [o.consolidate=true] Convert multiple instances of the same
+ key into an array of values instead of overwriting
+ */
this.objectify = function (str, o) {
var opts = o || {};
var d = {};
View
19 test/array.js
@@ -28,30 +28,37 @@ tests = {
assert.equal(expected, actual);
}
-, 'test humanize with two items for array': function() {
+, 'test humanize with two items for array': function () {
var actual = array.humanize(["array", "array"])
, expected = "array and array";
assert.equal(expected, actual);
}
-, 'test humanize with two items for array': function() {
+, 'test humanize with a single item for array': function () {
var actual = array.humanize(["array"])
, expected = "array";
assert.equal(expected, actual);
}
-, 'test basic include for array': function() {
+, 'test humanize with no items for array': function () {
+ var actual = array.humanize([])
+ , expected = "";
+ assert.equal(expected, actual);
+ }
+
+, 'test basic include for array': function () {
var test = ["array"]
, actual = array.include(test, "array");
assert.equal(true, actual);
}
-, 'test false include for array': function() {
- var actual = array.include(["array"], 'nope');
+, 'test false include for array': function () {
+ var test = ["array"]
+ , actual = array.include(test, 'nope');
assert.equal(false, actual);
}
-, 'test false boolean include for array': function() {
+, 'test false boolean include for array': function () {
var test = ["array", false]
, actual = array.include(test, false);
assert.equal(true, actual);
View
71 test/file.js
@@ -18,6 +18,7 @@
var assert = require('assert')
, fs = require('fs')
+ , path = require('path')
, file = require('../lib/file')
, tests;
@@ -56,6 +57,76 @@ tests = {
fs.rmdirSync('foo');
}
+, 'test readdirR': function () {
+ var res = []
+ , expected = [
+ 'foo'
+ , 'foo/bar'
+ , 'foo/bar/baz'
+ , 'foo/bar/baz/qux'
+ ]
+
+ file.mkdirP('foo/bar/baz/qux', {silent: true});
+ res = file.readdirR('foo');
+
+ for (var i = 0, ii = res.length; i < ii; i++) {
+ assert.equal(expected[i], res[i]);
+ }
+ file.rmRf('foo', {silent: true});
+ }
+
+, 'test isAbsolute with Unix absolute path': function () {
+ var p = '/foo/bar/baz';
+ assert.equal('/', file.isAbsolute(p));
+ }
+
+, 'test isAbsolute with Unix relative path': function () {
+ var p = 'foo/bar/baz';
+ assert.equal(false, file.isAbsolute(p));
+ }
+
+, 'test isAbsolute with Win absolute path': function () {
+ var p = 'C:\\foo\\bar\\baz';
+ assert.equal('C:\\', file.isAbsolute(p));
+ }
+
+, 'test isAbsolute with Win relative path': function () {
+ var p = 'foo\\bar\\baz';
+ assert.equal(false, file.isAbsolute(p));
+ }
+
+, 'test absolutize with Unix absolute path': function () {
+ var expected = '/foo/bar/baz'
+ , actual = file.absolutize('/foo/bar/baz');
+ assert.equal(expected, actual);
+ }
+
+, 'test absolutize with Win absolute path': function () {
+ var expected = 'C:\\foo\\bar\\baz'
+ , actual = file.absolutize('C:\\foo\\bar\\baz');
+ assert.equal(expected, actual);
+ }
+
+, 'test absolutize with relative path': function () {
+ var expected = process.cwd()
+ , actual = '';
+
+ // We can't just create two different tests here
+ // because file.absolutize uses process.cwd()
+ // to get absolute path which is platform
+ // specific
+ if (process.platform === 'win32') {
+ expected += '\\foo\\bar\\baz'
+ actual = file.absolutize('foo\\bar\\baz')
+ }
+ else {
+ expected += '/foo/bar/baz'
+ actual = file.absolutize('foo/bar/baz');
+ }
+
+ assert.equal(expected, actual);
+ }
+
, 'test basedir with Unix absolute path': function () {
var p = '/foo/bar/baz';
assert.equal('/', file.basedir(p));

0 comments on commit 2e5bec8

Please sign in to comment.