pax_global_header00006660000000000000000000000064142370044170014514gustar00rootroot0000000000000052 comment=ba6be1fd1abe7541f5965c0bf831f127e42da815 utilities-1.0.6/000077500000000000000000000000001423700441700135335ustar00rootroot00000000000000utilities-1.0.6/.gitignore000066400000000000000000000002421423700441700155210ustar00rootroot00000000000000v8.log *.swp *.swo auth_info.js dist .idea/ tags nbproject/ spec/browser/autogen_suite.js node_modules tmtags *.DS_Store examples/*/log/* .log npm-debug.log doc/ utilities-1.0.6/.travis.yml000066400000000000000000000002131423700441700156400ustar00rootroot00000000000000language: node_js node_js: - "0.12" - "0.10" before_install: - npm update -g npm script: ./node_modules/jake/bin/cli.js test --trace utilities-1.0.6/Jakefile000066400000000000000000000016341423700441700151740ustar00rootroot00000000000000 testTask('Utilities', function () { this.testFiles.include('test/*.js'); // Can't reliably test ports on travis if(process.env.CI) { this.testFiles.exclude('test/network.js'); } }); namespace('doc', function () { task('generate', ['doc:clobber'], function () { var cmd = '../node-jsdoc-toolkit/app/run.js -n -r=100 ' + '-t=../node-jsdoc-toolkit/templates/codeview -d=./doc/ ./lib'; console.log('Generating docs ...'); jake.exec([cmd], function () { console.log('Done.'); complete(); }); }, {async: true}); task('clobber', function () { var cmd = 'rm -fr ./doc/**'; jake.exec([cmd], function () { console.log('Clobbered old docs.'); complete(); }); }, {async: true}); }); desc('Generate docs for Utilities'); task('doc', ['doc:generate']); publishTask('utilities', [ 'Jakefile' , 'README.md' , 'package.json' , 'lib/**' , 'test/**' ]); utilities-1.0.6/LICENSE000066400000000000000000000261361423700441700145500ustar00rootroot00000000000000 Apache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "[]" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright [yyyy] [name of copyright owner] Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, 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. utilities-1.0.6/Makefile000066400000000000000000000020561423700441700151760ustar00rootroot00000000000000# # Utilities: A classic collection of JavaScript utilities # Copyright 2112 Matthew Eernisse (mde@fleegix.org) # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # 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. # .PHONY: all build install clean uninstall PREFIX=/usr/local DESTDIR= all: build build: @echo 'Utilities built.' install: @mkdir -p $(DESTDIR)$(PREFIX)/lib/node_modules/utilities && \ cp -R ./* $(DESTDIR)$(PREFIX)/lib/node_modules/utilities/ && \ echo 'Utilities installed.' clean: @true uninstall: @rm -rf $(DESTDIR)$(PREFIX)/lib/node_modules/utilities && \ echo 'Utilities uninstalled.' utilities-1.0.6/README.md000066400000000000000000000002611423700441700150110ustar00rootroot00000000000000utilities ========= [![Build Status](https://travis-ci.org/mde/utilities.png?branch=master)](https://travis-ci.org/mde/utilities) A classic collection of JavaScript utilities utilities-1.0.6/lib/000077500000000000000000000000001423700441700143015ustar00rootroot00000000000000utilities-1.0.6/lib/array.js000066400000000000000000000046051423700441700157620ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ /** @name array @namespace array */ var array = new (function () { /** @name array#humanize @public @function @return {String} A string containing the array elements in a readable format @description Creates a string containing the array elements in a readable format @param {Array} array The array to humanize */ this.humanize = function (a) { var array = a.slice(); // If array only has one item then just return it if (array.length <= 1) { return String(array); } var last = array.pop() , items = array.join(', '); return items + ' and ' + last; }; /** @name array#included @public @function @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 */ this.included = function (item, array) { var result = array.indexOf(item); if (result === -1) { return false; } else { return array; } }; /** @name array#include @public @function @return {Boolean} Return true if the item is included in the array @description Checks if an `item` is included in an `array` @param {Array} array The array to check @param {Any} item The item to look for */ this.include = function (array, item) { var res = -1; if (typeof array.indexOf == 'function') { res = array.indexOf(item); } else { for (var i = 0, ii = array.length; i < ii; i++) { if (array[i] == item) { res = i; break; } } } return res > -1; }; })(); module.exports = array; utilities-1.0.6/lib/async.js000066400000000000000000000171631423700441700157640ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var async = {}; /* AsyncChain -- performs a list of asynchronous calls in a desired order. Optional "last" method can be set to run after all the items in the chain have completed. // Example usage var asyncChain = new async.AsyncChain([ { func: app.trainToBangkok, args: [geddy, neil, alex], callback: null, // No callback for this action }, { func: fs.readdir, args: [geddy.config.dirname + '/thailand/express'], callback: function (err, result) { if (err) { // Bail out completely arguments.callee.chain.abort(); } else if (result.theBest) { // Don't run the next item in the chain; go directly // to the 'last' method. arguments.callee.chain.shortCircuit(); } else { // Otherwise do some other stuff and // then go to the next link } } }, { func: child_process.exec, args: ['ls ./'], callback: this.hitTheStops } ]); // Function to exec after all the links in the chain finish asyncChain.last = function () { // Do some final stuff }; // Start the async-chain asyncChain.run(); */ async.execNonBlocking = function (func) { if (typeof process != 'undefined' && typeof process.nextTick == 'function') { process.nextTick(func); } else { setTimeout(func, 0); } }; async.AsyncBase = new (function () { this.init = function (chain) { var item; this.chain = []; this.currentItem = null; this.shortCircuited = false; this.shortCircuitedArgs = undefined; this.aborted = false; for (var i = 0; i < chain.length; i++) { item = chain[i]; this.addItem(item); } }; this.addItem = function(item) { this.chain.push(new async.AsyncCall( item.func, item.args || [], item.callback, item.context)); }; // alias this.push = this.addItem; this.runItem = function (item) { // Reference to the current item in the chain -- used // to look up the callback to execute with execCallback this.currentItem = item; // Scopage var _this = this; // Pass the arguments passed to the current async call // to the callback executor, execute it in the correct scope var executor = function () { _this.execCallback.apply(_this, arguments); }; // Append the callback executor to the end of the arguments // Node helpfully always has the callback func last var args = item.args.concat(executor); var func = item.func; // Run the async call func.apply(item.context, args); }; this.next = function () { if (this.chain.length) { this.runItem(this.chain.shift()); } else { this.last(); } }; this.execCallback = function () { // Look up the callback, if any, specified for this async call var callback = this.currentItem.callback; // If there's a callback, do it if (callback && typeof callback == 'function') { // Allow access to the chain from inside the callback by setting // callback.chain = this, and then using arguments.callee.chain callback.chain = this; callback.apply(this.currentItem.context, arguments); } this.currentItem.finished = true; // If one of the async callbacks called chain.shortCircuit, // skip to the 'last' function for the chain if (this.shortCircuited) { this.last.apply(null, this.shortCircuitedArgs); } // If one of the async callbacks called chain.abort, // bail completely out else if (this.aborted) { return; } // Otherwise run the next item, if any, in the chain // Let's try not to block if we don't have to else { // Scopage var _this = this; async.execNonBlocking(function () { _this.next.call(_this); }); } } // Short-circuit the chain, jump straight to the 'last' function this.shortCircuit = function () { this.shortCircuitedArgs = arguments; this.shortCircuited = true; } // Stop execution of the chain, bail completely out this.abort = function () { this.aborted = true; } // Kick off the chain by grabbing the first item and running it this.run = this.next; // Function to run when the chain is done -- default is a no-op this.last = function () {}; })(); async.AsyncChain = function (chain) { this.init(chain); }; async.AsyncChain.prototype = async.AsyncBase; async.AsyncGroup = function (group) { var item; var callback; var args; this.group = []; this.outstandingCount = 0; for (var i = 0; i < group.length; i++) { item = group[i]; this.group.push(new async.AsyncCall( item.func, item.args, item.callback, item.context)); this.outstandingCount++; } }; /* Simpler way to group async calls -- doesn't ensure completion order, but still has a "last" method called when the entire group of calls have completed. */ async.AsyncGroup.prototype = new function () { this.run = function () { var _this = this , group = this.group , item , createItem = function (item, args) { return function () { item.func.apply(item.context, args); }; } , createCallback = function (item) { return function () { if (item.callback) { item.callback.apply(null, arguments); } _this.finish.call(_this); } }; for (var i = 0; i < group.length; i++) { item = group[i]; callback = createCallback(item); args = item.args.concat(callback); // Run the async call async.execNonBlocking(createItem(item, args)); } }; this.finish = function () { this.outstandingCount--; if (!this.outstandingCount) { this.last(); }; }; this.last = function () {}; }; var _createSimpleAsyncCall = function (func, context) { return { func: func , args: [] , callback: function () {} , context: context }; }; async.SimpleAsyncChain = function (funcs, context) { var chain = []; for (var i = 0, ii = funcs.length; i < ii; i++) { chain.push(_createSimpleAsyncCall(funcs[i], context)); } this.init(chain); }; async.SimpleAsyncChain.prototype = async.AsyncBase; async.AsyncCall = function (func, args, callback, context) { this.func = func; this.args = args; this.callback = callback || null; this.context = context || null; }; async.Initializer = function (steps, callback) { var self = this; this.steps = {}; this.callback = callback; // Create an object-literal of the steps to tick off steps.forEach(function (step) { self.steps[step] = false; }); }; async.Initializer.prototype = new (function () { this.complete = function (step) { var steps = this.steps; // Tick this step off steps[step] = true; // Iterate the steps -- if any are not done, bail out for (var p in steps) { if (!steps[p]) { return false; } } // If all steps are done, run the callback this.callback(); }; })(); module.exports = async; utilities-1.0.6/lib/core.js000066400000000000000000000073001423700441700155670ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var core = new (function () { var ownPropFunc = Object.prototype.hasOwnProperty; var _mix = function (targ, src, merge, includeProto) { for (var p in src) { // Don't copy stuff from the prototype if (ownPropFunc.call(src, p) || includeProto) { if (merge && // Assumes the source property is an Object you can // actually recurse down into (typeof src[p] == 'object') && (src[p] !== null) && !(src[p] instanceof Array)) { // Create the source property if it doesn't exist // Double-equal to undefined includes both null and undefined if (targ[p] == undefined) { targ[p] = {}; } _mix(targ[p], src[p], merge, includeProto); // Recurse } // If it's not a merge-copy, just set and forget else { targ[p] = src[p]; } } } }; /* * Mix in the properties on an object to another object * yam.mixin(target, source, [source,] [source, etc.] [merge-flag]); * 'merge' recurses, to merge object sub-properties together instead * of just overwriting with the source object. */ 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(); } } 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 () { 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); } return targ; }; // Idea to add invalid number & Date from Michael J. Ryan, // http://frugalcoder.us/post/2010/02/15/js-is-empty.aspx this.isEmpty = function (val) { // Empty string, null or undefined (these two are double-equal) if (val === '' || val == undefined) { return true; } // Invalid numerics if (typeof val == 'number' && isNaN(val)) { return true; } // Invalid Dates if (val instanceof Date && isNaN(val.getTime())) { return true; } return false; }; /* binds a function to an object */ this.bind = function () { var args = Array.prototype.slice.call(arguments) , ctxt = args.shift() , fn = args.shift(); if (typeof fn === 'function') { if (typeof Function.bind === 'function') { return fn.bind.apply(ctxt, args); } else { return fn.apply(ctxt, args); } } // in IE, native methods are not functions so they cannot be bound, // and don't need to be else { return fn; } } })(); module.exports = core; utilities-1.0.6/lib/date.js000066400000000000000000000717631423700441700155720ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var string = require('./string') , date , log = require('./log'); /** @name date @namespace date */ date = new (function () { var _this = this , _date = new Date(); var _US_DATE_PAT = /^(\d{1,2})(?:\-|\/|\.)(\d{1,2})(?:\-|\/|\.)(\d{4})/; var _DATETIME_PAT = /^(\d{4})(?:\-|\/|\.)(\d{1,2})(?:\-|\/|\.)(\d{1,2})(?:T| )?(\d{2})?(?::)?(\d{2})?(?::)?(\d{2})?(?:\.)?(\d+)?(?: *)?(Z|[+-]\d{4}|[+-]\d{2}:\d{2}|[+-]\d{2})?/; // TODO Add am/pm parsing instead of dumb, 24-hour clock. var _TIME_PAT = /^(\d{1,2})?(?::)?(\d{2})?(?::)?(\d{2})?(?:\.)?(\d+)?$/; var _dateMethods = [ 'FullYear' , 'Month' , 'Date' , 'Hours' , 'Minutes' , 'Seconds' , 'Milliseconds' ]; var _isArray = function (obj) { return obj && typeof obj === 'object' && typeof obj.length === 'number' && typeof obj.splice === 'function' && !(obj.propertyIsEnumerable('length')); }; this.weekdayLong = ['Sunday', 'Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday']; this.weekdayShort = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat']; this.monthLong = ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December']; this.monthShort = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; this.meridiem = { 'AM': 'AM', 'PM': 'PM' } // compat this.meridian = this.meridiem /** @name date#supportedFormats @public @object @description List of supported strftime formats */ this.supportedFormats = { // abbreviated weekday name according to the current locale 'a': function (dt) { return _this.weekdayShort[dt.getDay()]; }, // full weekday name according to the current locale 'A': function (dt) { return _this.weekdayLong[dt.getDay()]; }, // abbreviated month name according to the current locale 'b': function (dt) { return _this.monthShort[dt.getMonth()]; }, 'h': function (dt) { return _this.strftime(dt, '%b'); }, // full month name according to the current locale 'B': function (dt) { return _this.monthLong[dt.getMonth()]; }, // preferred date and time representation for the current locale 'c': function (dt) { return _this.strftime(dt, '%a %b %d %T %Y'); }, // century number (the year divided by 100 and truncated // to an integer, range 00 to 99) 'C': function (dt) { return _this.calcCentury(dt.getFullYear());; }, // day of the month as a decimal number (range 01 to 31) 'd': function (dt) { return string.lpad(dt.getDate(), '0', 2); }, // same as %m/%d/%y 'D': function (dt) { return _this.strftime(dt, '%m/%d/%y') }, // day of the month as a decimal number, a single digit is // preceded by a space (range ' 1' to '31') 'e': function (dt) { return string.lpad(dt.getDate(), ' ', 2); }, // month as a decimal number, a single digit is // preceded by a space (range ' 1' to '12') 'f': function () { return _this.strftimeNotImplemented('f'); }, // same as %Y-%m-%d 'F': function (dt) { return _this.strftime(dt, '%Y-%m-%d'); }, // like %G, but without the century. 'g': function () { return _this.strftimeNotImplemented('g'); }, // The 4-digit year corresponding to the ISO week number // (see %V). This has the same format and value as %Y, // except that if the ISO week number belongs to the // previous or next year, that year is used instead. 'G': function () { return _this.strftimeNotImplemented('G'); }, // hour as a decimal number using a 24-hour clock (range // 00 to 23) 'H': function (dt) { return string.lpad(dt.getHours(), '0', 2); }, // hour as a decimal number using a 12-hour clock (range // 01 to 12) 'I': function (dt) { return string.lpad( _this.hrMil2Std(dt.getHours()), '0', 2); }, // day of the year as a decimal number (range 001 to 366) 'j': function (dt) { return string.lpad( _this.calcDays(dt), '0', 3); }, // Hour as a decimal number using a 24-hour clock (range // 0 to 23 (space-padded)) 'k': function (dt) { return string.lpad(dt.getHours(), ' ', 2); }, // Hour as a decimal number using a 12-hour clock (range // 1 to 12 (space-padded)) 'l': function (dt) { return string.lpad( _this.hrMil2Std(dt.getHours()), ' ', 2); }, // month as a decimal number (range 01 to 12) 'm': function (dt) { return string.lpad((dt.getMonth()+1), '0', 2); }, // minute as a decimal number 'M': function (dt) { return string.lpad(dt.getMinutes(), '0', 2); }, // Linebreak 'n': function () { return '\n'; }, // either `am' or `pm' according to the given time value, // or the corresponding strings for the current locale 'p': function (dt) { return _this.getMeridian(dt.getHours()); }, // time in a.m. and p.m. notation 'r': function (dt) { return _this.strftime(dt, '%I:%M:%S %p'); }, // time in 24 hour notation 'R': function (dt) { return _this.strftime(dt, '%H:%M'); }, // second as a decimal number 'S': function (dt) { return string.lpad(dt.getSeconds(), '0', 2); }, // Tab char 't': function () { return '\t'; }, // current time, equal to %H:%M:%S 'T': function (dt) { return _this.strftime(dt, '%H:%M:%S'); }, // weekday as a decimal number [1,7], with 1 representing // Monday 'u': function (dt) { return _this.convertOneBase(dt.getDay()); }, // week number of the current year as a decimal number, // starting with the first Sunday as the first day of the // first week 'U': function () { return _this.strftimeNotImplemented('U'); }, // week number of the year (Monday as the first day of the // week) as a decimal number [01,53]. If the week containing // 1 January has four or more days in the new year, then it // is considered week 1. Otherwise, it is the last week of // the previous year, and the next week is week 1. 'V': function () { return _this.strftimeNotImplemented('V'); }, // week number of the current year as a decimal number, // starting with the first Monday as the first day of the // first week 'W': function () { return _this.strftimeNotImplemented('W'); }, // day of the week as a decimal, Sunday being 0 'w': function (dt) { return dt.getDay(); }, // preferred date representation for the current locale // without the time 'x': function (dt) { return _this.strftime(dt, '%D'); }, // preferred time representation for the current locale // without the date 'X': function (dt) { return _this.strftime(dt, '%T'); }, // year as a decimal number without a century (range 00 to // 99) 'y': function (dt) { return _this.getTwoDigitYear(dt.getFullYear()); }, // year as a decimal number including the century 'Y': function (dt) { return string.lpad(dt.getFullYear(), '0', 4); }, // time zone or name or abbreviation 'z': function () { return _this.strftimeNotImplemented('z'); }, 'Z': function () { return _this.strftimeNotImplemented('Z'); }, // Literal percent char '%': function (dt) { return '%'; } }; /** @name date#getSupportedFormats @public @function @description return the list of formats in a string @return {String} The list of supported formats */ this.getSupportedFormats = function () { var str = ''; for (var i in this.supportedFormats) { str += i; } return str; } this.supportedFormatsPat = new RegExp('%[' + this.getSupportedFormats() + ']{1}', 'g'); /** @name date#strftime @public @function @return {String} The `dt` formated with the given `format` @description Formats the given date with the strftime formated @param {Date} dt the date object to format @param {String} format the format to convert the date to */ this.strftime = function (dt, format) { if (!dt) { return '' } var d = dt; var pats = []; var dts = []; var str = format; var key; // Allow either Date obj or UTC stamp d = typeof dt == 'number' ? new Date(dt) : dt; // Grab all instances of expected formats into array while (pats = this.supportedFormatsPat.exec(format)) { dts.push(pats[0]); } // Process any hits for (var i = 0; i < dts.length; i++) { key = dts[i].replace(/%/, ''); str = str.replace('%' + key, this.supportedFormats[key](d)); } return str; }; this.strftimeNotImplemented = function (s) { throw('this.strftime format "' + s + '" not implemented.'); }; /** @name date#calcCentury @public @function @return {String} The century for the given date @description Find the century for the given `year` @param {Number} year The year to find the century for */ this.calcCentury = function (year) { if(!year) { year = _date.getFullYear(); } var ret = parseInt((year / 100) + 1); year = year.toString(); // If year ends in 00 subtract one, because it's still the century before the one // it divides to if (year.substring(year.length - 2) === '00') { ret--; } return ret.toString(); }; /** @name date#calcDays @public @function @return {Number} The number of days so far for the given date @description Calculate the day number in the year a particular date is on @param {Date} dt The date to use */ this.calcDays = function (dt) { var first = new Date(dt.getFullYear(), 0, 1); var diff = 0; var ret = 0; first = first.getTime(); diff = (dt.getTime() - first); ret = parseInt(((((diff/1000)/60)/60)/24))+1; return ret; }; /** * Adjust from 0-6 base week to 1-7 base week * @param d integer for day of week * @return Integer day number for 1-7 base week */ this.convertOneBase = function (d) { return d == 0 ? 7 : d; }; this.getTwoDigitYear = function (yr) { // Add a millenium to take care of years before the year 1000, // (e.g, the year 7) since we're only taking the last two digits // If we overshoot, it doesn't matter var millenYear = yr + 1000; var str = millenYear.toString(); str = str.substr(2); // Get the last two digits return str }; /** @name date#getMeridiem @public @function @return {String} Return 'AM' or 'PM' based on hour in 24-hour format @description Return 'AM' or 'PM' based on hour in 24-hour format @param {Number} h The hour to check */ this.getMeridiem = function (h) { return h > 11 ? this.meridiem.PM : this.meridiem.AM; }; // Compat this.getMeridian = this.getMeridiem; /** @name date#hrMil2Std @public @function @return {String} Return a 12 hour version of the given time @description Convert a 24-hour formatted hour to 12-hour format @param {String} hour The hour to convert */ this.hrMil2Std = function (hour) { var h = typeof hour == 'number' ? hour : parseInt(hour); var str = h > 12 ? h - 12 : h; str = str == 0 ? 12 : str; return str; }; /** @name date#hrStd2Mil @public @function @return {String} Return a 24 hour version of the given time @description Convert a 12-hour formatted hour with meridian flag to 24-hour format @param {String} hour The hour to convert @param {Boolean} pm hour is PM then this should be true */ this.hrStd2Mil = function (hour, pm) { var h = typeof hour == 'number' ? hour : parseInt(hour); var str = ''; // PM if (pm) { str = h < 12 ? (h+12) : h; } // AM else { str = h == 12 ? 0 : h; } return str; }; // Constants for use in this.add var dateParts = { YEAR: 'year' , MONTH: 'month' , DAY: 'day' , HOUR: 'hour' , MINUTE: 'minute' , SECOND: 'second' , MILLISECOND: 'millisecond' , QUARTER: 'quarter' , WEEK: 'week' , WEEKDAY: 'weekday' }; // Create a map for singular/plural lookup, e.g., day/days var datePartsMap = {}; for (var p in dateParts) { datePartsMap[dateParts[p]] = dateParts[p]; datePartsMap[dateParts[p] + 's'] = dateParts[p]; } this.dateParts = dateParts; /** @name date#add @public @function @return {Date} Incremented date @description Add to a Date in intervals of different size, from milliseconds to years @param {Date} dt Date (or timestamp Number), date to increment @param {String} interv a constant representing the interval, e.g. YEAR, MONTH, DAY. See this.dateParts @param {Number} incr how much to add to the date */ this.add = function (dt, interv, incr) { if (typeof dt == 'number') { dt = new Date(dt); } function fixOvershoot() { if (sum.getDate() < dt.getDate()) { sum.setDate(0); } } var key = datePartsMap[interv]; var sum = new Date(dt); switch (key) { case dateParts.YEAR: sum.setFullYear(dt.getFullYear()+incr); // Keep increment/decrement from 2/29 out of March fixOvershoot(); break; case dateParts.QUARTER: // Naive quarter is just three months incr*=3; // fallthrough... case dateParts.MONTH: sum.setMonth(dt.getMonth()+incr); // Reset to last day of month if you overshoot fixOvershoot(); break; case dateParts.WEEK: incr*=7; // fallthrough... case dateParts.DAY: sum.setDate(dt.getDate() + incr); break; case dateParts.WEEKDAY: //FIXME: assumes Saturday/Sunday weekend, but even this is not fixed. // There are CLDR entries to localize this. var dat = dt.getDate(); var weeks = 0; var days = 0; var strt = 0; var trgt = 0; var adj = 0; // Divide the increment time span into weekspans plus leftover days // e.g., 8 days is one 5-day weekspan / and two leftover days // Can't have zero leftover days, so numbers divisible by 5 get // a days value of 5, and the remaining days make up the number of weeks var mod = incr % 5; if (mod == 0) { days = (incr > 0) ? 5 : -5; weeks = (incr > 0) ? ((incr-5)/5) : ((incr+5)/5); } else { days = mod; weeks = parseInt(incr/5); } // Get weekday value for orig date param strt = dt.getDay(); // Orig date is Sat / positive incrementer // Jump over Sun if (strt == 6 && incr > 0) { adj = 1; } // Orig date is Sun / negative incrementer // Jump back over Sat else if (strt == 0 && incr < 0) { adj = -1; } // Get weekday val for the new date trgt = strt + days; // New date is on Sat or Sun if (trgt == 0 || trgt == 6) { adj = (incr > 0) ? 2 : -2; } // Increment by number of weeks plus leftover days plus // weekend adjustments sum.setDate(dat + (7*weeks) + days + adj); break; case dateParts.HOUR: sum.setHours(sum.getHours()+incr); break; case dateParts.MINUTE: sum.setMinutes(sum.getMinutes()+incr); break; case dateParts.SECOND: sum.setSeconds(sum.getSeconds()+incr); break; case dateParts.MILLISECOND: sum.setMilliseconds(sum.getMilliseconds()+incr); break; default: // Do nothing break; } return sum; // Date }; /** @name date#diff @public @function @return {Number} number of (interv) units apart that the two dates are @description Get the difference in a specific unit of time (e.g., number of months, weeks, days, etc.) between two dates. @param {Date} date1 First date to check @param {Date} date2 Date to compate `date1` with @param {String} interv a constant representing the interval, e.g. YEAR, MONTH, DAY. See this.dateParts */ this.diff = function (date1, date2, interv) { // date1 // Date object or Number equivalent // // date2 // Date object or Number equivalent // // interval // A constant representing the interval, e.g. YEAR, MONTH, DAY. See this.dateParts. // Accept timestamp input if (typeof date1 == 'number') { date1 = new Date(date1); } if (typeof date2 == 'number') { date2 = new Date(date2); } var yeaDiff = date2.getFullYear() - date1.getFullYear(); var monDiff = (date2.getMonth() - date1.getMonth()) + (yeaDiff * 12); var msDiff = date2.getTime() - date1.getTime(); // Millisecs var secDiff = msDiff/1000; var minDiff = secDiff/60; var houDiff = minDiff/60; var dayDiff = houDiff/24; var weeDiff = dayDiff/7; var delta = 0; // Integer return value var key = datePartsMap[interv]; switch (key) { case dateParts.YEAR: delta = yeaDiff; break; case dateParts.QUARTER: var m1 = date1.getMonth(); var m2 = date2.getMonth(); // Figure out which quarter the months are in var q1 = Math.floor(m1/3) + 1; var q2 = Math.floor(m2/3) + 1; // Add quarters for any year difference between the dates q2 += (yeaDiff * 4); delta = q2 - q1; break; case dateParts.MONTH: delta = monDiff; break; case dateParts.WEEK: // Truncate instead of rounding // Don't use Math.floor -- value may be negative delta = parseInt(weeDiff); break; case dateParts.DAY: delta = dayDiff; break; case dateParts.WEEKDAY: var days = Math.round(dayDiff); var weeks = parseInt(days/7); var mod = days % 7; // Even number of weeks if (mod == 0) { days = weeks*5; } else { // Weeks plus spare change (< 7 days) var adj = 0; var aDay = date1.getDay(); var bDay = date2.getDay(); weeks = parseInt(days/7); mod = days % 7; // Mark the date advanced by the number of // round weeks (may be zero) var dtMark = new Date(date1); dtMark.setDate(dtMark.getDate()+(weeks*7)); var dayMark = dtMark.getDay(); // Spare change days -- 6 or less if (dayDiff > 0) { switch (true) { // Range starts on Sat case aDay == 6: adj = -1; break; // Range starts on Sun case aDay == 0: adj = 0; break; // Range ends on Sat case bDay == 6: adj = -1; break; // Range ends on Sun case bDay == 0: adj = -2; break; // Range contains weekend case (dayMark + mod) > 5: adj = -2; break; default: // Do nothing break; } } else if (dayDiff < 0) { switch (true) { // Range starts on Sat case aDay == 6: adj = 0; break; // Range starts on Sun case aDay == 0: adj = 1; break; // Range ends on Sat case bDay == 6: adj = 2; break; // Range ends on Sun case bDay == 0: adj = 1; break; // Range contains weekend case (dayMark + mod) < 0: adj = 2; break; default: // Do nothing break; } } days += adj; days -= (weeks*2); } delta = days; break; case dateParts.HOUR: delta = houDiff; break; case dateParts.MINUTE: delta = minDiff; break; case dateParts.SECOND: delta = secDiff; break; case dateParts.MILLISECOND: delta = msDiff; break; default: // Do nothing break; } // Round for fractional values and DST leaps return Math.round(delta); // Number (integer) }; /** @name date#parse @public @function @return {Date} a JavaScript Date object @description Convert various sorts of strings to JavaScript Date objects @param {String} val The string to convert to a Date */ this.parse = function (val, options) { var dt , opts = options || {} , matches , reordered , off , posOff , offHours , offMinutes , offSeconds , curr , stamp , utc; // Yay, we have a date, use it as-is if (val instanceof Date || typeof val.getFullYear == 'function') { dt = val; } // Timestamp? else if (typeof val == 'number') { dt = new Date(val); } // String or Array else { // Value preparsed, looks like [yyyy, mo, dd, hh, mi, ss, ms, (offset?)] if (_isArray(val)) { matches = val; matches.unshift(null); matches[8] = null; } // Oh, crap, it's a string -- parse this bitch else if (typeof val == 'string') { matches = val.match(_DATETIME_PAT); // Stupid US-only format? if (!matches) { matches = val.match(_US_DATE_PAT); if (matches) { reordered = [matches[0], matches[3], matches[1], matches[2]]; // Pad the results to the same length as ISO8601 reordered[8] = null; matches = reordered; } } // Time-stored-in-Date hack? if (!matches) { matches = val.match(_TIME_PAT); if (matches) { reordered = [matches[0], 0, 1, 0, matches[1], matches[2], matches[3], matches[4], null]; matches = reordered; } } } // Sweet, the regex actually parsed it into something useful if (matches) { matches.shift(); // First match is entire match, DO NOT WANT off = matches.pop(); // If there's an offset (or the 'Z' non-offset offset), use UTC // methods to set everything if (off) { if (off == 'Z') { utc = true; offSeconds = 0; } else { utc = false; // Convert from extended to basic if necessary off = off.replace(/:/g, ''); // '+0000' will still be zero if (parseInt(off, 10) === 0) { utc = true; } else { posOff = off.indexOf('+') === 0; // Strip plus or minus off = off.substr(1); offHours = parseInt(off.substr(0, 2), 10); offMinutes = off.substr(2, 2); if (offMinutes) { offMinutes = parseInt(offMinutes, 10); } else { offMinutes = 0; } offSeconds = off.substr(4, 2); if (offSeconds) { offSeconds = parseInt(offSeconds, 10); } else { offSeconds = 0; } offSeconds += (offMinutes * 60) offSeconds += (offHours * 60 * 60); if (!posOff) { offSeconds = 0 - offSeconds; } } } } dt = new Date(0); // Stupid zero-based months matches[1] = parseInt(matches[1], 10) - 1; // Specific offset, iterate the array and set each date property // using UTC setters, then adjust time using offset if (off) { for (var i = matches.length - 1; i > -1; i--) { curr = parseInt(matches[i], 10) || 0; dt['setUTC' + _dateMethods[i]](curr); } // Add any offset dt.setSeconds(dt.getSeconds() - offSeconds); } // Otherwise we know nothing about the offset, just iterate the // array and set each date property using regular setters else { var lastValIndex; for (var i = matches.length - 1; i > -1; i--) { if (matches[i]) { curr = parseInt(matches[i], 10); if (typeof lastValIndex == 'undefined') { lastValIndex = i; } } else { curr = 0; } dt['set' + _dateMethods[i]](curr); } if (opts.setMax) { for (var i = lastValIndex + 1, ii = matches.length; i < ii; i++) { switch (i) { case 3: dt['set' + _dateMethods[i]](23); break; case 4: case 5: dt['set' + _dateMethods[i]](59); break; case 6: dt.setMilliseconds(999); break; } } } } } // Shit, last-ditch effort using Date.parse else { stamp = Date.parse(val); // Failures to parse yield NaN if (!isNaN(stamp)) { dt = new Date(stamp); } } } return dt || null; }; /** @name date#relativeTime @public @function @return {String} A string describing the amount of time ago the passed-in Date is @description Convert a Date to an English sentence representing how long ago the Date was @param {Date} dt The Date to to convert to a relative time string @param {Object} [opts] @param {Boolean} [opts.abbreviated=false] Use short strings (e.g., '<1m') for the relative-time string */ this.relativeTime = function (dt, options) { var opts = options || {} , now = opts.now || new Date() , abbr = opts.abbreviated || false , format = opts.format || '%F %T' // Diff in seconds , diff = (now.getTime() - dt.getTime()) / 1000 , ret , num , hour = 60*60 , day = 24*hour , week = 7*day , month = 30*day; switch (true) { case diff < 60: ret = abbr ? '<1m' : 'less than a minute ago'; break; case diff < 120: ret = abbr ? '1m' : 'about a minute ago'; break; case diff < (45*60): num = parseInt((diff / 60), 10); ret = abbr ? num + 'm' : num + ' minutes ago'; break; case diff < (2*hour): ret = abbr ? '1h' : 'about an hour ago'; break; case diff < (1*day): num = parseInt((diff / hour), 10); ret = abbr ? num + 'h' : 'about ' + num + ' hours ago'; break; case diff < (2*day): ret = abbr ? '1d' : 'one day ago'; break; case diff < (7*day): num = parseInt((diff / day), 10); ret = abbr ? num + 'd' : 'about ' + num + ' days ago'; break; case diff < (11*day): ret = abbr ? '1w': 'one week ago'; break; case diff < (1*month): num = Math.round(diff / week); ret = abbr ? num + 'w' : 'about ' + num + ' weeks ago'; break; default: ret = date.strftime(dt, format); break; } return ret; }; /** @name date#toISO8601 @public @function @return {String} A string describing the amount of time ago @description Convert a Date to an ISO8601-formatted string @param {Date} dt The Date to to convert to an ISO8601 string */ var _pad = function (n) { return n < 10 ? '0' + n : n; }; this.toISO8601 = function (dt, options) { var opts = options || {} , off = dt.getTimezoneOffset() , offHours , offMinutes , str = this.strftime(dt, '%F') + 'T' + this.strftime(dt, '%T') + '.' + string.lpad(dt.getMilliseconds(), '0', 3); if (opts.tz) { // Pos and neg numbers are both truthy; only // zero is falsy if (off && !opts.utc) { str += off > 0 ? '-' : '+'; offHours = parseInt(off / 60, 10); str += string.lpad(offHours, '0', 2); offMinutes = off % 60; if (offMinutes) { str += string.lpad(offMinutes, '0', 2); } } else { str += 'Z'; } } return str; }; // Alias this.toIso8601 = this.toISO8601; this.toUTC = function (dt) { return new Date( dt.getUTCFullYear() , dt.getUTCMonth() , dt.getUTCDate() , dt.getUTCHours() , dt.getUTCMinutes() , dt.getUTCSeconds() , dt.getUTCMilliseconds()); }; })(); module.exports = date; utilities-1.0.6/lib/event_buffer.js000066400000000000000000000061011423700441700173070ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ /* 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(). Example: var source = new Stream() , dest = new EventEmitter() , buff = new EventBuffer(source) , data = ''; dest.on('data', function (d) { data += d; }); source.writeable = true; source.readable = true; source.emit('data', 'abcdef'); source.emit('data', '123456'); buff.sync(dest); */ /** @name EventBuffer @namespace EventBuffer @constructor */ var EventBuffer = function (src, events) { // By default, we service the default stream events var self = this , streamEvents = ['data', 'end', 'error', 'close', 'fd', 'drain', 'pipe']; this.events = events || streamEvents; this.emitter = src; this.eventBuffer = []; this.outlet = null; this.events.forEach(function (name) { self.emitter.addListener(name, function () { self.proxyEmit(name, arguments); }); }); }; 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); } else { this.eventBuffer.push({name: name, args: args}); } }; /** @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); }; /** @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 to */ this.sync = function (outlet) { var buffer = this.eventBuffer , bufferItem; this.outlet = outlet; while ((bufferItem = buffer.shift())) { this.emit(bufferItem.name, bufferItem.args); } }; })(); EventBuffer.prototype.constructor = EventBuffer; module.exports.EventBuffer = EventBuffer; utilities-1.0.6/lib/file.js000066400000000000000000000352131423700441700155620ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var fs = require('fs') , path = require('path') , DEFAULT_INCLUDE_PAT = /\.(js|coffee|css|less|scss)$/ , DEFAULT_EXCLUDE_PAT = /\.git|node_modules/ , logger; var logger = new (function () { var out; try { out = require('./log'); } catch (e) { out = console; } this.log = function (o) { out.log(o); }; })(); /** @name file @namespace file */ var fileUtils = new (function () { 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 , toStat , destExists , destDoesNotExistErr , content , filename , dirContents , targetDir; fromStat = fs.statSync(from); try { //console.dir(to + ' destExists'); toStat = fs.statSync(to); destExists = true; } catch(e) { //console.dir(to + ' does not exist'); destDoesNotExistErr = e; destExists = false; } // 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, fromStat.mode & 07777); } catch(e) { if (e.code !== 'EEXIST') { throw e; } } for (var i = 0, ii = dirContents.length; i < ii; i++) { _copyFile(path.join(from, dirContents[i]), targetDir, {preserveMode: options.preserveMode}); } } // Copying a file else { content = fs.readFileSync(from); var mode = fromStat.mode & 07777; var targetFile = to; if (toStat.isDirectory()) { targetFile = path.join(to, filename); } var fileExists = fs.existsSync(targetFile); fs.writeFileSync(targetFile, content); // If the file didn't already exist, use the original file mode. // Otherwise, only update the mode if preserverMode is true. if(!fileExists || options.preserveMode) { fs.chmodSync(targetFile, mode); } } } // Dest doesn't exist, can't create it else { throw destDoesNotExistErr; } }; // Return the contents of a given directory _readDir = function (dirPath) { var dir = path.normalize(dirPath) , paths = [] , ret = [dir] , msg; try { paths = fs.readdirSync(dir); } catch (e) { msg = 'Could not read path ' + dir + '\n'; if (e.stack) { msg += e.stack; } throw new Error(msg); } 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); } }); return ret; }; // Remove the given directory _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.lstatSync(curr); if (stat.isDirectory()) { _rmDir(curr); } else { try { fs.unlinkSync(curr); } catch(e) { if (e.code === 'EPERM') { fs.chmodSync(curr, parseInt(666, 8)); fs.unlinkSync(curr); } else { throw e; } } } }); fs.rmdirSync(dir); }; // Recursively watch files with a callback _watch = function () { var args = Array.prototype.slice.call(arguments) , filePath , opts , callback , inclPat , exclPat , createWatcher; filePath = args.shift(); callback = args.pop(); opts = args.pop() || {}; inclPat = opts.includePattern || DEFAULT_INCLUDE_PAT; exclPat = opts.excludePattern || DEFAULT_EXCLUDE_PAT; opts.level = opts.level || 1; createWatcher = function (watchPath) { if (!exclPat.test(watchPath)) { fs.watch(watchPath, function (ev, p) { if (inclPat.test(p) && !exclPat.test(p)) { callback(path.join(watchPath, p)); } }); } }; fs.stat(filePath, function (err, stats) { if (err) { return false; } // Watch files at the top level if (stats.isFile() && opts.level == 1) { createWatcher(filePath); opts.level++; } else if (stats.isDirectory()) { createWatcher(filePath); opts.level++; fs.readdir(filePath, function (err, files) { if (err) { return log.fatal(err); } for (var f in files) { _watch(path.join(filePath, files[f]), opts, callback); } }); } }); }; /** @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 @param {Boolean} [opts.preserveMode] If target file already exists, this determines whether the original file's mode is copied over. The default of false mimics the behavior of the `cp` command line tool. (Default: false) */ this.cpR = function (fromPath, toPath, options) { var from = path.normalize(fromPath) , to = path.normalize(toPath) , toStat , doesNotExistErr , filename , opts = options || {}; if (!opts.silent) { logger.log('cp -r ' + fromPath + ' ' + toPath); } if (from == to) { throw new Error('Cannot copy ' + from + ' to itself.'); } // Handle rename-via-copy try { toStat = fs.statSync(to); } catch(e) { doesNotExistErr = e; // Get abs path so it's possible to check parent dir if (!this.isAbsolute(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) {} 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); } else { throw doesNotExistErr; } } _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(/\/|\\/) , currPath = '' , next; 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())) { if (next == '..') { currPath = path.join(currPath, next); continue; } currPath = path.join(currPath, next); try { //console.log('making ' + currPath); fs.mkdirSync(currPath, mode || parseInt(755, 8)); } catch(e) { if (e.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); return format == 'string' ? ret.join('\n') : ret; }; /** @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, options) { var stat , opts = options || {}; if (!opts.silent) { logger.log('rm -rf ' + p); } try { stat = fs.lstatSync(p); if (stat.isDirectory()) { _rmDir(p); } else { fs.unlinkSync(p); } } catch (e) {} }; /** @name file#isAbsolute @public @function @return {Boolean/String} If it's absolute the first character 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; } else { return path.join(process.cwd(), p); } }; /** Given a patern, return the base directory of it (ie. the folder that will contain all the files matching the path). eg. file.basedir('/test/**') => '/test/' Path ending by '/' are considerd as folder while other are considerd as files, eg.: file.basedir('/test/a/') => '/test/a' file.basedir('/test/a') => '/test' The returned path always end with a '/' so we have: file.basedir(file.basedir(x)) == file.basedir(x) */ this.basedir = function (pathParam) { var basedir = '' , parts , part , pos = 0 , p = pathParam || ''; // If the path has a leading asterisk, basedir is the current dir if (p.indexOf('*') == 0 || p.indexOf('**') == 0) { return '.'; } // always consider .. at the end as a folder and not a filename if (/(?:^|\/|\\)\.\.$/.test(p.slice(-3))) { p += '/'; } parts = p.split(/\\|\//); for (var i = 0, l = parts.length - 1; i < l; i++) { part = parts[i]; if (part.indexOf('*') > -1 || part.indexOf('**') > -1) { break; } pos += part.length + 1; basedir += part + p[pos - 1]; } if (!basedir) { basedir = '.'; } // Strip trailing slashes if (!(basedir == '\\' || basedir == '/')) { basedir = basedir.replace(/\\$|\/$/, ''); } return basedir; }; /** @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 (location, beginPath, callback) { if (typeof beginPath === 'function' && !callback) { callback = beginPath; beginPath = process.cwd(); } var cwd = beginPath || process.cwd(); if (!location) { // Return if no path is given return; } var relPath = '' , i = 5 // Only search up to 5 directories , pathLoc , pathExists; while (--i >= 0) { pathLoc = path.join(cwd, relPath, location); pathExists = this.existsSync(pathLoc); if (pathExists) { callback && callback(undefined, pathLoc); break; } else { // Dir could not be found if (i === 0) { callback && callback(new Error("Path \"" + pathLoc + "\" not found"), undefined); break; } // Add a relative parent directory relPath += '../'; // Switch to relative parent directory process.chdir(path.join(cwd, relPath)); } } }; /** @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); }; // Compatibility for fs.exists(0.8) and path.exists(0.6) this.exists = (typeof fs.exists === 'function') ? fs.exists : path.exists; // Compatibility for fs.existsSync(0.8) and path.existsSync(0.6) this.existsSync = (typeof fs.existsSync === 'function') ? fs.existsSync : path.existsSync; /** @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) { var dep; // Try to require in the application directory try { dep = require(path.join(process.cwd(), 'node_modules', module)); } catch(err) { if (message) { throw new Error(message); } throw new Error('Module "' + module + '" could not be found as a ' + 'local module. Please install it by doing "npm install ' + module + '"'); } return dep; }; })(); module.exports = fileUtils; utilities-1.0.6/lib/i18n.js000066400000000000000000000037001423700441700154160ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var core = require('./core') , i18n; var DEFAULT_LOCALE = 'en-us'; i18n = new (function () { var _defaultLocale = DEFAULT_LOCALE , _strings = {}; this.getText = function (key, opts, locale) { var currentLocale = locale || _defaultLocale , currentLocaleStrings = _strings[currentLocale] || {} , defaultLocaleStrings = _strings[_defaultLocale] || {} , str = currentLocaleStrings[key] || defaultLocaleStrings[key] || "[[" + key + "]]"; for (var p in opts) { str = str.replace(new RegExp('\\{' + p + '\\}', 'g'), opts[p]); } return str; }; this.getDefaultLocale = function () { return _defaultLocale; }; this.setDefaultLocale = function (locale) { _defaultLocale = locale; }; this.loadLocale = function (locale, strings) { _strings[locale] = _strings[locale] || {}; core.mixin(_strings[locale], strings); }; })(); i18n.I18n = function (locale) { var _locale = locale || i18n.getDefaultLocale(); this.getLocale = function (locale) { return _locale; }; this.setLocale = function (locale) { _locale = locale; }; this.getText = function (key, opts, locale) { return i18n.getText(key, opts || {}, locale || _locale); }; this.t = this.getText; }; module.exports = i18n; utilities-1.0.6/lib/index.js000066400000000000000000000033551423700441700157540ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var utils = {} // Core methods , core = require('./core') // Namespaces with methods , string = require('./string') , file = require('./file') , async = require('./async') , i18n = require('./i18n') , uri = require('./uri') , array = require('./array') , object = require('./object') , date = require('./date') , request = require('./request') , log = require('./log') , network = require('./network') // Third-party -- remove this if possible , inflection = require('./inflection') // Constructors , EventBuffer = require('./event_buffer').EventBuffer , XML = require('./xml').XML , SortedCollection = require('./sorted_collection').SortedCollection; core.mixin(utils, core); utils.string = string; utils.file = file; utils.async = async; utils.i18n = i18n; utils.uri = uri; utils.array = array; utils.object = object; utils.date = date; utils.request = request; utils.log = log; utils.network = network; utils.inflection = inflection; utils.SortedCollection = SortedCollection; utils.EventBuffer = EventBuffer; utils.XML = XML; module.exports = utils; utilities-1.0.6/lib/inflection.js000066400000000000000000000177521423700441700170050ustar00rootroot00000000000000/* * Copyright (c) 2010 George Moschovitis, http://www.gmosx.com * * Permission is hereby granted, free of charge, to any person * obtaining a copy of this software and associated documentation * files (the "Software"), to deal in the Software without * restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be * included in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF * CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE * SOFTWARE. * * A port of the Rails/ActiveSupport Inflector class * http://api.rubyonrails.org/classes/ActiveSupport/Inflector.html */ /** @name inflection @namespace inflection */ var inflection = new (function () { /** @name inflection#inflections @public @object @description A list of rules and replacements for different inflection types */ this.inflections = { plurals: [] , singulars: [] , uncountables: [] }; var self = this , setInflection , setPlural , setSingular , setUncountable , setIrregular; // Add a new inflection rule/replacement to the beginning of the array for the // inflection type setInflection = function (type, rule, replacement) { self.inflections[type].unshift([rule, replacement]); }; // Add a new plural inflection rule setPlural = function (rule, replacement) { setInflection('plurals', rule, replacement); }; // Add a new singular inflection rule setSingular = function (rule, replacement) { setInflection('singulars', rule, replacement); }; // Add a new irregular word to the inflection list, by a given singular and plural inflection setIrregular = function (singular, plural) { if (singular.substr(0, 1).toUpperCase() == plural.substr(0, 1).toUpperCase()) { setPlural(new RegExp("(" + singular.substr(0, 1) + ")" + singular.substr(1) + "$", "i"), '$1' + plural.substr(1)); setPlural(new RegExp("(" + plural.substr(0, 1) + ")" + plural.substr(1) + "$", "i"), '$1' + plural.substr(1)); setSingular(new RegExp("(" + plural.substr(0, 1) + ")" + plural.substr(1) + "$", "i"), '$1' + singular.substr(1)); } else { setPlural(new RegExp(singular.substr(0, 1).toUpperCase() + singular.substr(1) + "$"), plural.substr(0, 1).toUpperCase() + plural.substr(1)); setPlural(new RegExp(singular.substr(0, 1).toLowerCase() + singular.substr(1) + "$"), plural.substr(0, 1).toLowerCase() + plural.substr(1)); setPlural(new RegExp(plural.substr(0, 1).toUpperCase() + plural.substr(1) + "$"), plural.substr(0, 1).toUpperCase() + plural.substr(1)); setPlural(new RegExp(plural.substr(0, 1).toLowerCase() + plural.substr(1) + "$"), plural.substr(0, 1).toLowerCase() + plural.substr(1)); setSingular(new RegExp(plural.substr(0, 1).toUpperCase() + plural.substr(1) + "$"), singular.substr(0, 1).toUpperCase() + singular.substr(1)); setSingular(new RegExp(plural.substr(0, 1).toLowerCase() + plural.substr(1) + "$"), singular.substr(0, 1).toLowerCase() + singular.substr(1)); } }; // Add a new word to the uncountable inflection list setUncountable = function (word) { self.inflections.uncountables[word] = true; }; // Create inflections (function () { setPlural(/$/, "s"); setPlural(/s$/i, "s"); setPlural(/(ax|test)is$/i, "$1es"); setPlural(/(octop|vir)us$/i, "$1i"); setPlural(/(octop|vir)i$/i, "$1i"); setPlural(/(alias|status)$/i, "$1es"); setPlural(/(bu)s$/i, "$1ses"); setPlural(/(buffal|tomat)o$/i, "$1oes"); setPlural(/([ti])a$/i, "$1a"); setPlural(/([ti])um$/i, "$1a"); setPlural(/sis$/i, "ses"); setPlural(/ses$/i, "ses"); setPlural(/(?:([^f])fe|([lr])f)$/i, "$1$2ves"); setPlural(/(hive)$/i, "$1s"); setPlural(/([^aeiouy]|qu)y$/i, "$1ies"); setPlural(/(x|ch|ss|sh)$/i, "$1es"); setPlural(/(matr|vert|ind)(?:ix|ex)$/i, "$1ices"); setPlural(/([m|l])ouse$/i, "$1ice"); setPlural(/([m|l])ice$/i, "$1ice"); setPlural(/^(ox)$/i, "$1en"); setPlural(/^(ox)en$/i, "$1en"); setPlural(/(quiz)$/i, "$1zes"); setSingular(/s$/i, "") setSingular(/ss$/i, "ss") setSingular(/(n)ews$/i, "$1ews") setSingular(/([ti])um$/i, "$1um") setSingular(/([ti])a$/i, "$1um") setSingular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)ses$/i, "$1$2sis") setSingular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)sis$/i, "$1$2sis") setSingular(/(^analy)ses$/i, "$1sis") setSingular(/(^analy)sis$/i, "$1sis") setSingular(/([^f])ves$/i, "$1fe") setSingular(/(hive)s$/i, "$1") setSingular(/(tive)s$/i, "$1") setSingular(/([lr])ves$/i, "$1f") setSingular(/([^aeiouy]|qu)ies$/i, "$1y") setSingular(/(s)eries$/i, "$1eries") setSingular(/(m)ovies$/i, "$1ovie") setSingular(/(x|ch|ss|sh)es$/i, "$1") setSingular(/([m|l])ice$/i, "$1ouse") setSingular(/([m|l])ouse$/i, "$1ouse") setSingular(/(bus)es$/i, "$1") setSingular(/(bus)$/i, "$1") setSingular(/(o)es$/i, "$1") setSingular(/(shoe)s$/i, "$1") setSingular(/(cris|ax|test)es$/i, "$1is") setSingular(/(cris|ax|test)is$/i, "$1is") setSingular(/(octop|vir)i$/i, "$1us") setSingular(/(octop|vir)us$/i, "$1us") setSingular(/(alias|status)es$/i, "$1") setSingular(/(alias|status)$/i, "$1") setSingular(/^(ox)en/i, "$1") setSingular(/(vert|ind)ices$/i, "$1ex") setSingular(/(matr)ices$/i, "$1ix") setSingular(/(quiz)zes$/i, "$1") setSingular(/(database)s$/i, "$1") setIrregular("person", "people"); setIrregular("man", "men"); setIrregular("child", "children"); setIrregular("sex", "sexes"); setIrregular("move", "moves"); setIrregular("cow", "kine"); setUncountable("equipment"); setUncountable("information"); setUncountable("rice"); setUncountable("money"); setUncountable("species"); setUncountable("series"); setUncountable("fish"); setUncountable("sheep"); setUncountable("jeans"); })(); /** @name inflection#parse @public @function @return {String} The inflection of the word from the type given @description Parse a word from the given inflection type @param {String} type A type of the inflection to use @param {String} word the word to parse */ this.parse = function (type, word) { var lowWord = word.toLowerCase() , inflections = this.inflections[type]; if (this.inflections.uncountables[lowWord]) { return word; } var i = -1; while (++i < inflections.length) { var rule = inflections[i][0] , replacement = inflections[i][1]; if (rule.test(word)) { return word.replace(rule, replacement) } } return word; }; /** @name inflection#pluralize @public @function @return {String} The plural inflection for the given word @description Create a plural inflection for a word @param {String} word the word to create a plural version for */ this.pluralize = function (word) { return self.parse('plurals', word); }; /** @name inflection#singularize @public @function @return {String} The singular inflection for the given word @description Create a singular inflection for a word @param {String} word the word to create a singular version for */ this.singularize = function (word) { return self.parse('singulars', word); }; })(); module.exports = inflection; utilities-1.0.6/lib/log.js000066400000000000000000000020611423700441700154170ustar00rootroot00000000000000var util = require('util') , log , _logger , _levels , _serialize , _output; _levels = { 'debug': 'log' , 'log' : 'log' , 'info': 'info' , 'notice': 'info' , 'warning': 'warn' , 'warn': 'warn' , 'error': 'error' , 'critical': 'error' , 'alert': 'error' , 'emergency': 'error' }; _serialize = function (obj) { var out; if (typeof obj == 'string') { out = obj; } else { out = util.inspect(obj); } return out; }; _output = function (obj, level) { var out = _serialize(obj); if (_logger) { _logger[level](out); } else { console[_levels[level]](out); } }; log = function (obj) { _output(obj, 'info'); }; log.registerLogger = function (logger) { // Malkovitch, Malkovitch if (logger === log) { return; } _logger = logger; }; (function () { var level; for (var p in _levels) { (function (p) { level = _levels[p]; log[p] = function (obj) { _output(obj, p); }; })(p); } // Also handle 'access', not an actual level log.access = log.info; })(); module.exports = log; utilities-1.0.6/lib/network.js000066400000000000000000000034021423700441700163270ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var network , net = require('net'); /** @name network @namespace network */ network = new (function () { /** @name network#isPortOpen @public @function @description Checks if the given port in the given host is open @param {Number} port number @param {String} host @param {Function} callback Callback function -- should be in the format of function(err, result) {} */ this.isPortOpen = function (port, host, callback) { if (typeof host === 'function' && !callback) { callback = host; host = 'localhost'; } var isOpen = false , connection , error; connection = net.createConnection(port, host, function () { isOpen = true; connection.end(); }); connection.on('error', function (err) { // We ignore 'ECONNREFUSED' as it simply indicates the port isn't open. // Anything else is reported if(err.code !== 'ECONNREFUSED') { error = err; } }); connection.setTimeout(400, function () { connection.end(); }); connection.on('close', function () { callback && callback(error, isOpen); }); }; })(); module.exports = network;utilities-1.0.6/lib/object.js000066400000000000000000000065751423700441700161220ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var hasOwnProperty = Object.prototype.hasOwnProperty; var hasOwn = function (obj, key) { return hasOwnProperty.apply(obj, [key]); }; /** @name object @namespace object */ var object = new (function () { /** @name object#merge @public @function @return {Object} Returns the merged object @description Merge merges `otherObject` into `object` and takes care of deep merging of objects @param {Object} object Object to merge into @param {Object} otherObject Object to read from */ this.merge = function (object, otherObject) { var obj = object || {} , otherObj = otherObject || {} , key, value; for (key in otherObj) { if (!hasOwn(otherObj, key)) { continue; } if (key === '__proto__' || key === 'constructor') { continue; } value = otherObj[key]; // Check if a value is an Object, if so recursively add it's key/values if (typeof value === 'object' && !(value instanceof Array)) { // Update value of object to the one from otherObj obj[key] = this.merge(obj[key], value); } // Value is anything other than an Object, so just add it else { obj[key] = value; } } return obj; }; /** @name object#reverseMerge @public @function @return {Object} Returns the merged object @description ReverseMerge merges `object` into `defaultObject` @param {Object} object Object to read from @param {Object} defaultObject Object to merge into */ this.reverseMerge = function (object, defaultObject) { // Same as `merge` except `defaultObject` is the object being changed // - this is useful if we want to easily deal with default object values return this.merge(defaultObject, object); }; /** @name object#isEmpty @public @function @return {Boolean} Returns true if empty false otherwise @description isEmpty checks if an Object is empty @param {Object} object Object to check if empty */ this.isEmpty = function (object) { // Returns true if a object is empty false if not for (var i in object) { return false; } return true; }; /** @name object#toArray @public @function @return {Array} Returns an array of objects each including the original key and value @description Converts an object to an array of objects each including the original key/value @param {Object} object Object to convert */ this.toArray = function (object) { // Converts an object into an array of objects with the original key, values array = []; for (var i in object) { array.push({ key: i, value: object[i] }); } return array; }; })(); module.exports = object; utilities-1.0.6/lib/request.js000066400000000000000000000111171423700441700163300ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var http = require('http') , https = require('https') , url = require('url') , uri = require('./uri') , log = require('./log') , core = require('./core'); /** @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 @param {Function} callback the function to call after, args are `error, data` */ var request = function (opts, callback) { var client , options = opts || {} , parsed = url.parse(options.url) , path , requester = parsed.protocol == 'http:' ? http : https , method = (options.method && options.method.toUpperCase()) || 'GET' , headers = core.mixin({}, options.headers || {}) , data = options.data , contentLength , port , clientOpts; if (parsed.port) { port = parsed.port; } else { port = parsed.protocol == 'http:' ? '80' : '443'; } path = parsed.pathname; if (method == 'POST' || method == 'PUT') { // Handle the payload and content-length if (data) { // JSON data if (options.dataType == 'json') { if (typeof data == 'object') { data = JSON.stringify(data); } headers['Content-Type'] = headers['Content-Type'] || headers['content-type'] || 'application/json'; } // Form data else { if (typeof data == 'object') { data = uri.paramify(data); } // FIXME: What is the prefix for form-urlencoded? headers['Content-Type'] = headers['Content-Type'] || headers['content-type'] || 'form-urlencoded'; } contentLength = Buffer.byteLength(data); } else { contentLength = 0 } headers['Content-Length'] = contentLength; if (parsed.search) { path += parsed.search; } } else { if (data) { // Data is an object, parse into querystring if (typeof data == 'object') { data = uri.paramify(data); } // Create querystring or append to existing if (parsed.search) { path += parsed.search; // search includes question mark path += '&' + data; } else { path += '?' + data; } } } clientOpts = { host: parsed.hostname , port: port , method: method , agent: false , path: path , headers: headers }; client = requester.request(clientOpts); client.addListener('response', function (resp) { var data = ''; resp.addListener('data', function (chunk) { data += chunk.toString(); }); resp.addListener('end', function () { var stat = resp.statusCode , contentType , err; // Successful response if ((stat > 199 && stat < 300) || stat == 304) { if (data) { contentType = resp.headers['Content-Type']; if (contentType == 'application/json' || contentType == 'text/json' || uri.getFileExtension(parsed.pathname) == 'json') { try { data = JSON.parse(data); } catch (e) { return callback(e, null); } } callback(null, data); } else { callback(null, null); } } // Something failed else { err = new Error(data); err.statusCode = resp.statusCode; callback(err, null); } }); }); client.addListener('error', function (e) { callback(e, null); }); if ((method == 'POST' || method == 'PUT') && data) { client.write(data); } client.end(); }; module.exports = request; utilities-1.0.6/lib/sorted_collection.js000066400000000000000000000361201423700441700203540ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ /** @name SortedCollection @namespace SortedCollection @constructor */ var SortedCollection = function (d) { this.count = 0; this.items = {}; // Hash keys and their values this.order = []; // Array for sort order if (d) { this.defaultValue = d; }; }; SortedCollection.prototype = new (function () { /** @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); } else if (typeof p == 'number') { return this.getByIndex(p); } }; /** @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') { return this.setByKey(p, val); } else if (typeof p == 'number') { 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') { return this.removeByKey(p); } else if (typeof p == 'number') { 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') { v = this.defaultValue; } else { v = val; } if (typeof this.items[key] == 'undefined') { this.order[this.count] = key; this.count++; } this.items[key] = v; 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; delete this.items[key]; // Remove the value // Find the key in the order list for (var i = 0; i < this.order.length; i++) { if (this.order[i] == key) { pos = i; } } 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]]; }; /** @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[ind]] this.order.splice(ind, 1); this.count--; return true; } else { return false; } }; /** @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) { return true; } } 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)) { this.removeItem(newKey); } this.items[newKey] = this.items[oldKey]; delete this.items[oldKey]; for (var i = 0; i < this.order.length; i++) { if (this.order[i] == oldKey) { this.order[i] = newKey; } } }; /** @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.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') { return order.indexOf(key); } else { for (var i = 0; i < order.length; i++) { if (order[i] == key) { return i;} } } }; /** @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 (options.keyOnly) { func(key); } else if (options.valueOnly) { func(val); } else { func(val, key); } } 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) { 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) { 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 , val; for (var i = 0; i < this.order.length; i++) { key = this.order[i]; val = this.items[key]; coll.setItem(key, val); } 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]; var val = hNew.items[key]; this.setItem(key, val); } }; /** @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]]; if (typeof ret != 'undefined') { this.removeByIndex(pos); return ret; } else { return; } }; /** @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; }; /** @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') { this.removeByIndex(pos); return ret; } else { return; } }; /** @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 if (numToRemove > 0) { // Items var limit = index + numToRemove; for (var i = index; i < limit; i++) { delete this.items[this.order[i]]; } // Order this.order.splice(index, numToRemove); } // Adding if (hash) { // Items for (var i in hash.items) { this.items[i] = hash.items[i]; } // Order var args = hash.order; args.unshift(0); args.unshift(index); this.order.splice.apply(this.order, args); } this.count = this.order.length; }; this.sort = function (c) { var arr = []; // Assumes vals are comparable scalars var comp = function (a, b) { return c(a.val, b.val); } for (var i = 0; i < this.order.length; i++) { var key = this.order[i]; arr[i] = { key: key, val: this.items[key] }; } arr.sort(comp); this.order = []; for (var i = 0; i < arr.length; i++) { this.order.push(arr[i].key); } }; this.sortByKey = function (comp) { this.order.sort(comp); }; /** @name SortedCollection#reverse @public @function @description Reverse the collection item list */ this.reverse = function () { this.order.reverse(); }; })(); module.exports.SortedCollection = SortedCollection; utilities-1.0.6/lib/string.js000066400000000000000000000577211423700441700161610ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var core = require('./core') , inflection = require('./inflection') , string; /** @name string @namespace string */ string = new (function () { // Regexes for trimming, and character maps for escaping var _LTR = /^\s+/ , _RTR = /\s+$/ , _TR = /^\s+|\s+$/g , _NL = /\n|\r|\r\n/g , _CHARS = { '&': '&' , '<': '<' , '>': '>' , '"': '"' , '\'': ''' } , _UUID_CHARS = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'.split('') , _buildEscape , _buildEscapeTest; // Builds the escape/unescape methods using a // map of characters _buildEscape = function (direction) { return function (str) { var string = str; // If string is NaN, null or undefined then provide an empty default if((typeof string === 'undefined') || string === null || (!string && isNaN(string))) { string = ''; } string = string.toString(); var from, to, p; for (p in _CHARS) { from = direction == 'to' ? p : _CHARS[p]; to = direction == 'to' ? _CHARS[p] : p; string = string.replace(new RegExp(from, 'gm'), to); } return string; } }; // Builds a method that tests for any escapable // characters, useful for avoiding double-scaping if // you're not sure if a string has already been escaped _buildEscapeTest = function (direction) { return function (string) { var pat = '' , p; for (p in _CHARS) { pat += direction == 'to' ? p : _CHARS[p]; pat += '|'; } pat = pat.substr(0, pat.length - 1); pat = new RegExp(pat, "gm"); return pat.test(string) } }; // Escape special XMl chars this.escapeXML = _buildEscape('to'); // Unescape XML chars to literal representation this.unescapeXML = _buildEscape('from'); // Test if a string includes special chars // that need escaping this.needsEscape = _buildEscapeTest('to'); // Test if a string includes escaped chars // that need unescaping this.needsUnescape = _buildEscapeTest('from'); /** @name string#escapeRegExpChars @public @function @return {String} A string of escaped characters @description Escapes regex control-characters in strings used to build regexes dynamically @param {String} string The string of chars to escape */ this.escapeRegExpChars = (function () { var specials = [ '^', '$', '/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\' ]; var sRE = new RegExp('(\\' + specials.join('|\\') + ')', 'g'); return function (string) { var str = string || ''; str = String(str); return str.replace(sRE, '\\$1'); }; }).call(this); /** @name string#toArray @public @function @return {Array} Returns an array of characters @description Converts a string to an array @param {String} string The string to convert */ this.toArray = function (string) { var str = string || '' , arr = [] , i = -1; str = String(str); while (++i < str.length) { arr.push(str.substr(i, 1)); } return arr; }; /** @name string#reverse @public @function @return {String} Returns the `string` reversed @description Reverses a string @param {String} string The string to reverse */ this.reverse = function (string) { var str = string || ''; str = String(str); return this.toArray(str).reverse().join(''); }; /** @name string#ltrim @public @function @return {String} Returns the trimmed string @description Ltrim trims `char` from the left of a `string` and returns it if no `char` is given it will trim spaces @param {String} string The string to trim @param {String} character The character to trim */ this.ltrim = function (string, character) { var str = string || '' , pat = character ? new RegExp('^' + character + '+') : _LTR; str = String(str); return str.replace(pat, ''); }; /** @name string#rtrim @public @function @return {String} Returns the trimmed string @description Rtrim trims `char` from the right of a `string` and returns it if no `char` is given it will trim spaces @param {String} string The string to trim @param {String} character The character to trim */ this.rtrim = function (string, character) { var str = string || '' , pat = character ? new RegExp(character + '+$') : _RTR; str = String(str); return str.replace(pat, ''); }; // Alias this.chomp = this.rtrim; /** @name string#trim @public @function @return {String} Returns the trimmed string @description Trim trims `char` from the left and right of a `string` and returns it if no `char` is given it will trim spaces @param {String} string The string to trim @param {String} character The character to trim */ this.trim = function (string, character) { var str = string || '' , pat = character ? new RegExp('^' + character + '+|' + character + '+$', 'g') : _TR; str = String(str); return str.replace(pat, ''); }; /** @name string#chop @public @function @description Returns a new String with the last character removed. If the string ends with \r\n, both characters are removed. Applying chop to an empty string returns an empty string. @param {String} string to return with the last character removed. */ this.chop = function (string) { var index , str = string || ''; str = String(str); if (str.length) { // Special-case for \r\n index = str.indexOf('\r\n'); if (index == str.length - 2) { return str.substring(0, index); } return str.substring(0, str.length - 1); } else { return ''; } }; /** @name string#lpad @public @function @return {String} Returns the padded string @description Lpad adds `char` to the left of `string` until the length of `string` is more than `width` @param {String} string The string to pad @param {String} character The character to pad with @param {Number} width the width to pad to */ this.lpad = function (string, character, width) { var str = string || '' , width; str = String(str); // Should width be string.length + 1? or the same to be safe width = parseInt(width, 10) || str.length; character = character || ' '; while (str.length < width) { str = character + str; } return str; }; /** @name string#rpad @public @function @return {String} Returns the padded string @description Rpad adds `char` to the right of `string` until the length of `string` is more than `width` @param {String} string The string to pad @param {String} character The character to pad with @param {Number} width the width to pad to */ this.rpad = function (string, character, width) { var str = string || '' , width; str = String(str); // Should width be string.length + 1? or the same to be safe width = parseInt(width, 10) || str.length; character = character || ' '; while (str.length < width) { str += character; } return str; }; /** @name string#pad @public @function @return {String} Returns the padded string @description Pad adds `char` to the left and right of `string` until the length of `string` is more than `width` @param {String} string The string to pad @param {String} character The character to pad with @param {Number} width the width to pad to */ this.pad = function (string, character, width) { var str = string || '' , width; str = String(str); // Should width be string.length + 1? or the same to be safe width = parseInt(width, 10) || str.length; character = character || ' '; while (str.length < width) { str = character + str + character; } return str; }; /** @name string#truncate @public @function @return {String} Returns the truncated string @description Truncates a given `string` after a specified `length` if `string` is longer than `length`. The last characters will be replaced with an `omission` for a total length not exceeding `length`. If `callback` is given it will fire if `string` is truncated. @param {String} string The string to truncate @param {Integer/Object} options Options for truncation, If options is an Integer it will be length @param {Integer} [options.length=string.length] Length the output string will be @param {Integer} [options.len] Alias for `length` @param {String} [options.omission='...'] Replace last characters with an omission @param {String} [options.ellipsis='...'] Alias for `omission` @param {String/RegExp} [options.seperator] Break the truncated test at the nearest `seperator` @param {Function} callback Callback is called only if a truncation is done */ this.truncate = function (string, options, callback) { var str = string || '' , stringLen , opts , stringLenWithOmission , last , ignoreCase , multiLine , stringToWorkWith , lastIndexOf , nextStop , result , returnString; str = String(str); stringLen = str.length // If `options` is a number, assume it's the length and // create a options object with length if (typeof options === 'number') { opts = { length: options }; } else { opts = options || {}; } // Set `opts` defaults opts.length = opts.length || stringLen; opts.omission = opts.omission || opts.ellipsis || '...'; stringLenWithOmission = opts.length - opts.omission.length; // Set the index to stop at for `string` if (opts.seperator) { if (opts.seperator instanceof RegExp) { // If `seperator` is a regex if (opts.seperator.global) { opts.seperator = opts.seperator; } else { ignoreCase = opts.seperator.ignoreCase ? 'i' : '' multiLine = opts.seperator.multiLine ? 'm' : ''; opts.seperator = new RegExp(opts.seperator.source, 'g' + ignoreCase + multiLine); } stringToWorkWith = str.substring(0, stringLenWithOmission + 1) lastIndexOf = -1 nextStop = 0 while ((result = opts.seperator.exec(stringToWorkWith))) { lastIndexOf = result.index; opts.seperator.lastIndex = ++nextStop; } last = lastIndexOf; } else { // Seperator is a String last = str.lastIndexOf(opts.seperator, stringLenWithOmission); } // If the above couldn't be found, they'll default to -1 so, // we need to just set it as `stringLenWithOmission` if (last === -1) { last = stringLenWithOmission; } } else { last = stringLenWithOmission; } if (stringLen < opts.length) { return str; } else { returnString = str.substring(0, last) + opts.omission; returnString += callback && typeof callback === 'function' ? callback() : ''; return returnString; } }; /** @name string#truncateHTML @public @function @return {String} Returns the HTML safe truncated string @description Truncates a given `string` inside HTML tags after a specified `length` if string` is longer than `length`. The last characters will be replaced with an `omission` for a total length not exceeding `length`. If `callback` is given it will fire if `string` is truncated. If `once` is true only the first string in the first HTML tags will be truncated leaving the others as they were @param {String} string The string to truncate @param {Integer/Object} options Options for truncation, If options is an Integer it will be length all Object options are the same as `truncate` @param {Boolean} [options.once=false] If true, it will only be truncated once, otherwise the truncation will loop through all text inside HTML tags @param {Function} callback Callback is called only if a truncation is done */ this.truncateHTML = function (string, options, callback) { var str = string || '' , returnString = '' , opts = options; str = String(str); // If `options` is a number assume it's the length and create a options object with length if (typeof opts === 'number') { var num = opts; opts = {}; opts.length = num; } else opts = opts || {}; // Set `default` options for HTML specifics opts.once = opts.once || false; var pat = /(<[^>]*>)/ // Patter for matching HTML tags , arr = [] // Holds the HTML tags and content seperately , truncated = false , result = pat.exec(str) , item , firstPos , lastPos , i; // Gather the HTML tags and content into the array while (result) { firstPos = result.index; lastPos = pat.lastIndex; if (firstPos !== 0) { // Should be content not HTML tags arr.push(str.substring(0, firstPos)); // Slice content from string str = str.slice(firstPos); } arr.push(result[0]); // Push HTML tags str = str.slice(result[0].length); // Re-run the pattern on the new string result = pat.exec(str); } if (str !== '') { arr.push(str); } // Loop through array items appending the tags to the string, // - and truncating the text then appending it to content i = -1; while (++i < arr.length) { item = arr[i]; switch (true) { // Closing tag case item.indexOf(''); }; /** @name string#snakeize @public @function @return {String} The string in a snake_case version @description Snakeize converts camelCase and CamelCase strings to snake_case strings @param {String} string The string to convert to snake_case @param {String} separ='_' The seperator to use */ this.snakeize = (function () { // Only create regexes once on initial load var repl = /([A-Z]+)/g , lead = /^_/g; return function (string, separ) { var str = string || '' , sep = separ || '_' , leading = separ ? new RegExp('^' + sep, 'g') : lead; str = String(str); return str.replace(repl, sep + '$1').toLowerCase(). replace(leading, ''); }; }).call(this); // Aliases /** @name string#underscorize @public @function @return {String} The string in a underscorized version @description Underscorize returns the given `string` converting camelCase and snakeCase to underscores @param {String} string The string to underscorize */ this.underscorize = this.snakeize; this.underscoreize = this.snakeize; this.decamelize = this.snakeize; /** @name string#camelize @public @function @return {String} The string in a camelCase version @description Camelize takes a string and optional options and returns a camelCase version of the given `string` @param {String} string The string to convert to camelCase @param {Object} options @param {Boolean} [options.initialCap] If initialCap is true the returned string will have a capitalized first letter @param {Boolean} [options.leadingUnderscore] If leadingUnderscore os true then if an underscore exists at the beggining of the string, it will stay there. Otherwise it'll be removed. */ this.camelize = (function () { // Only create regex once on initial load var repl = /[-_](\w)/g; return function (string, options) { var str = string || '' , ret , config = { initialCap: false , leadingUnderscore: false } , opts = options || {}; str = String(str); // Backward-compat if (typeof opts == 'boolean') { config = { initialCap: true }; } else { core.mixin(config, opts); } ret = str.replace(repl, function (m, m1) { return m1.toUpperCase(); }); if (config.leadingUnderscore & str.indexOf('_') === 0) { ret = '_' + this.decapitalize(ret); } // If initialCap is true capitalize it ret = config.initialCap ? this.capitalize(ret) : this.decapitalize(ret); return ret; }; }).call(this); /** @name string#decapitalize @public @function @return {String} The string with the first letter decapitalized @description Decapitalize returns the given string with the first letter uncapitalized. @param {String} string The string to decapitalize */ this.decapitalize = function (string) { var str = string || ''; str = String(str); return str.substr(0, 1).toLowerCase() + str.substr(1); }; /** @name string#capitalize @public @function @return {String} The string with the first letter capitalized @description capitalize returns the given string with the first letter capitalized. @param {String} string The string to capitalize */ this.capitalize = function (string) { var str = string || ''; str = String(str); return str.substr(0, 1).toUpperCase() + str.substr(1); }; /** @name string#dasherize @public @function @return {String} The string in a dashed version @description Dasherize returns the given `string` converting camelCase and snakeCase to dashes or replace them with the `replace` character. @param {String} string The string to dasherize @param {String} replace='-' The character to replace with */ this.dasherize = function (string, replace) { var repl = replace || '-' return this.snakeize(string, repl); }; /** @name string#include @public @function @return {Boolean} Returns true if the string is found in the string to search @description Searches for a particular string in another string @param {String} searchIn The string to search for the other string in @param {String} searchFor The string to search for */ this.include = function (searchIn, searchFor) { var str = searchFor; if (!str && typeof string != 'string') { return false; } str = String(str); return (searchIn.indexOf(str) > -1); }; /* * getInflections(name, initialCap) * * Inflection returns an object that contains different inflections * created from the given `name` */ /** @name string#getInflections @public @function @return {Object} A Object containing multiple different inflects for the given `name` @description Inflection returns an object that contains different inflections created from the given `name` @param {String} name The string to create inflections from */ this.getInflections = function (name) { if (!name) { return; } var self = this // Use plural version to fix possible mistakes(e,g,. thingie instead of thingy) , normalizedName = this.snakeize(inflection.pluralize(name)) , nameSingular = inflection.singularize(normalizedName) , namePlural = inflection.pluralize(normalizedName) , nameNormal = this.snakeize(name); return { // For filepaths or URLs filename: { normal: nameNormal // neil_peart , singular: nameSingular // neil_pearts , plural: namePlural } // Constructor names , constructor: { normal: self.camelize(nameNormal, {initialCap: true}) // NeilPeart , singular: self.camelize(nameSingular, {initialCap: true}) // NeilPearts , plural: self.camelize(namePlural, {initialCap: true}) } , property: { normal: self.camelize(nameNormal) // neilPeart , singular: self.camelize(nameSingular) // neilPearts , plural: self.camelize(namePlural) } }; }; /** @name string#getInflection @public @function @return {Object} A Object containing multiple different inflects for the given `name` @description Inflection returns an object that contains different inflections created from the given `name` @param {String} name The string to create inflections from */ this.getInflection = function (name, key, pluralization) { var infl = this.getInflections(name); return infl[key][pluralization]; }; // From Math.uuid.js, https://github.com/broofa/node-uuid // Robert Kieffer (robert@broofa.com), MIT license this.uuid = function (length, radix) { var chars = _UUID_CHARS , uuid = [] , r , i; radix = radix || chars.length; if (length) { // Compact form i = -1; while (++i < length) { uuid[i] = chars[0 | Math.random()*radix]; } } else { // rfc4122, version 4 form // rfc4122 requires these characters uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-'; uuid[14] = '4'; // Fill in random data. At i==19 set the high bits of clock sequence as // per rfc4122, sec. 4.1.5 i = -1; while (++i < 36) { if (!uuid[i]) { r = 0 | Math.random()*16; uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r]; } } } return uuid.join(''); }; /** @name string#stripTags @public @function @return {String} A String with HTML tags removed. @description Strips HTML tags from a string. @param {String} The string to strip HTML tags from @param {String|Array} A String or Array containing allowed tags. e.g. "

" */ this.stripTags = function(string, allowed) { // taken from http://phpjs.org/functions/strip_tags/ var allowed = (((allowed || "") + "").toLowerCase().match(/<[a-z][a-z0-9]*>/g) || []).join(''); // making sure the allowed arg is a string containing only tags in lowercase () var tags = /<\/?([a-z][a-z0-9]*)\b[^>]*>/gi, comments = //gi; return string.replace(comments, '').replace(tags, function ($0, $1) { return allowed.indexOf('<' + $1.toLowerCase() + '>') > -1 ? $0 : ''; }); } })(); module.exports = string; utilities-1.0.6/lib/uri.js000066400000000000000000000200171423700441700154360ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var uri , string = require('./string') , mixin = require('./core').mixin; /** @name uri @namespace uri */ uri = new (function () { var _isArray = function (obj) { return obj && typeof obj === 'object' && typeof obj.length === 'number' && typeof obj.splice === 'function' && !(obj.propertyIsEnumerable('length')); }; /** @name uri#getFileExtension @public @function @return {String} Returns the file extension for a given path @description Gets the file extension for a path and returns it @param {String} path The path to get the extension for */ this.getFileExtension = function (path) { var match; if (path) { match = /.+\.(\w{2,4}$)/.exec(path); } return (match && match[1]) || ''; }; /** @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. @param {Boolean} [o.index=false] use numeric indices for arrays */ this.paramify = function (obj, o) { var opts = o || {}, _opts, str = '', key, val, isValid, itemArray, arr = [], arrVal, prefix = opts.prefix || '', self = this; function getParamName(key) { if (opts.prefix) { return prefix + '[' + key + ']'; } else { return key; } } for (var p in obj) { if (Object.prototype.hasOwnProperty.call(obj, p)) { val = obj[p]; // This keeps valid falsy values like false and 0 // It's duplicated in the array block below. Could // put it in a function but don't want the overhead isValid = !( val === null || val === undefined || (typeof val === 'number' && isNaN(val)) ); key = opts.snakeize ? string.snakeize(p) : p; if (isValid) { // Multiple vals -- array if (_isArray(val) && val.length) { itemArray = []; for (var i = 0, ii = val.length; i < ii; i++) { arrVal = val[i]; // This keeps valid falsy values like false and 0 isValid = !( arrVal === null || arrVal === undefined || (typeof arrVal === 'number' && isNaN(arrVal)) ); // for index mode, which works recursive // objects and array must not be encoded if (opts.index && typeof arrVal === 'object') { itemArray[i] = arrVal; } else { itemArray[i] = isValid ? encodeURIComponent(arrVal) : ''; if (opts.escapeVals) { itemArray[i] = string.escapeXML(itemArray[i]); } } } // Consolidation mode -- single value joined on comma if (opts.consolidate) { arr.push(getParamName(key) + '=' + itemArray.join(',')); } // Indexed mode -- multiple, same-named params with numeric indices else if (opts.index) { // {foo: [1, 2, 3]} => 'foo[0]=1&foo[1]=2&foo[2]=3' itemArray.forEach(function(item, i) { // recursion of arrays if (_isArray(item) && item.length) { _opts = mixin(opts, {}); item.forEach(function(_item, ii) { if (typeof _item === 'object') { _opts.prefix = getParamName(key) + '[' + i + '][' + ii + ']'; arr.push(self.paramify(_item, _opts)); } else { arr.push(getParamName(key) + '[' + i + '][' + ii + ']=' + _item); } }); } // recursion of object in array else if (typeof item === 'object') { _opts = mixin(opts, {}); _opts.prefix = getParamName(key) + '[' + i + ']'; arr.push(self.paramify(item, _opts)); } // primitive else { arr.push(getParamName(key) + '[' + i + ']=' + item); } }); } // Normal mode -- multiple, same-named params with each val else { // {foo: [1, 2, 3]} => 'foo=1&foo=2&foo=3' // Add into results array, as this just ends up getting // joined on ampersand at the end anyhow arr.push(getParamName(key) + '=' + itemArray.join('&' + getParamName(key) + '=')); } } // Object -- recursion else if (typeof val === 'object') { _opts = mixin(opts, {}); _opts.prefix = getParamName(key); arr.push(this.paramify(val, _opts)); } // Single val -- string else { if (opts.escapeVals) { val = string.escapeXML(val); } arr.push(getParamName(key) + '=' + encodeURIComponent(val)); } str += '&'; } else { if (opts.includeEmpty) { arr.push(getParamName(key) + '='); } } } } return arr.join('&'); }; /** @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 = {}; var consolidate = typeof opts.consolidate == 'undefined' ? true : opts.consolidate; if (str) { var arr = str.split('&'); for (var i = 0; i < arr.length; i++) { var pair = arr[i].split('='); var name = pair[0]; var val = decodeURIComponent(pair[1] || ''); // "We've already got one!" -- arrayize if the flag // is set if (typeof d[name] != 'undefined' && consolidate) { if (typeof d[name] == 'string') { d[name] = [d[name]]; } d[name].push(val); } // Otherwise just set the value else { d[name] = val; } } } return d; }; })(); module.exports = uri; utilities-1.0.6/lib/xml.js000066400000000000000000000175531423700441700154520ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var core = require('./core') , inflection = require('./inflection') /** @name xml @namespace xml */ exports.XML = new (function () { // Default indention level var indentLevel = 4 , tagFromType , obj2xml; tagFromType = function (item, prev) { var ret , type , types; if (item instanceof Array) { ret = 'array'; } else { types = ['string', 'number', 'boolean', 'object']; for (var i = 0, ii = types.length; i < ii; i++) { type = types[i]; if (typeof item == type) { ret = type; } } } if (prev && ret != prev) { return 'record' } else { return ret; } }; obj2xml = function (o, opts) { var name = opts.name , level = opts.level , arrayRoot = opts.arrayRoot , pack , item , n , currentIndent = (new Array(level * indentLevel)).join(' ') , nextIndent = (new Array((level + 1) * indentLevel)).join(' ') , xml = ''; switch (typeof o) { case 'string': case 'number': case 'boolean': xml = o.toString(); break; case 'object': // Arrays if (o instanceof Array) { // Pack the processed version of each item into an array that // can be turned into a tag-list with a `join` method below // As the list gets iterated, if all items are the same type, // that's the tag-name for the individual tags. If the items are // a mixed, the tag-name is 'record' pack = []; for (var i = 0, ii = o.length; i < ii; i++) { item = o[i]; if (!name) { // Pass any previous tag-name, so it's possible to know if // all items are the same type, or it's mixed types n = tagFromType(item, n); } pack.push(obj2xml(item, { name: name , level: level + 1 , arrayRoot: arrayRoot })); } // If this thing is attached to a named property on an object, // use the name for the containing tag-name if (name) { n = name; } // If this is a top-level item, wrap in a top-level containing tag if (level == 0) { xml += currentIndent + '<' + inflection.pluralize(n) + ' type="array">\n' } xml += nextIndent + '<' + n + '>' + pack.join('\n' + nextIndent + '<' + n + '>') + '\n'; // If this is a top-level item, close the top-level containing tag if (level == 0) { xml += currentIndent + ''; } } // Generic objects else { n = name || 'object'; // If this is a top-level item, wrap in a top-level containing tag if (level == 0) { xml += currentIndent + '<' + n; // Lookahead hack to allow tags to have attributes for (var p in o) { if (p.indexOf('attr:') == 0) { xml += ' ' + p.replace(/^attr:/, '') + '="' + o[p] + '"' } } xml += '>\n'; } for (var p in o) { item = o[p]; // Data properties only if (typeof item == 'function') { continue; } // No attr hack properties if (p.indexOf('attr:') == 0) { continue; } xml += nextIndent; if (p == '#cdata') { xml += '\n'; } else { // Complex values, going to have items with multiple tags // inside if (typeof item == 'object') { if (item instanceof Array) { if (arrayRoot) { xml += '<' + p + ' type="array">\n' } } else { xml += '<' + p; // Lookahead hack to allow tags to have attributes for (var q in item) { if (q.indexOf('attr:') == 0) { xml += ' ' + q.replace(/^attr:/, '') + '="' + item[q] + '"' } } xml += '>\n'; } } // Scalars, just a value and closing tag else { xml += '<' + p + '>' } xml += obj2xml(item, { name: p , level: level + 1 , arrayRoot: arrayRoot }); // Objects and Arrays, need indentation before closing tag if (typeof item == 'object') { if (item instanceof Array) { if (arrayRoot) { xml += nextIndent; xml += '\n'; } } else { xml += nextIndent; xml += '\n'; } } // Scalars, just close else { xml += '\n'; } } } // If this is a top-level item, close the top-level containing tag if (level == 0) { xml += currentIndent + '\n'; } } break; default: // No default } return xml; } /* * XML configuration * */ this.config = { whitespace: true , name: null , fragment: false , level: 0 , arrayRoot: true }; /** @name xml#setIndentLevel @public @function @return {Number} Return the given `level` @description SetIndentLevel changes the indent level for XML.stringify and returns it @param {Number} level The indent level to use */ this.setIndentLevel = function (level) { if(!level) { return; } return indentLevel = level; }; /** @name xml#stringify @public @function @return {String} Return the XML entities of the given `obj` @description Stringify returns an XML representation of the given `obj` @param {Object} obj The object containing the XML entities to use @param {Object} opts @param {Boolean} [opts.whitespace=true] Don't insert indents and newlines after xml entities @param {String} [opts.name=typeof obj] Use custom name as global namespace @param {Boolean} [opts.fragment=false] If true no header fragment is added to the top @param {Number} [opts.level=0] Remove this many levels from the output @param {Boolean} [opts.arrayRoot=true] */ this.stringify = function (obj, opts) { var config = core.mixin({}, this.config) , xml = ''; core.mixin(config, (opts || {})); if (!config.whitespace) { indentLevel = 0; } if (!config.fragment) { xml += '\n'; } xml += obj2xml(obj, { name: config.name , level: config.level , arrayRoot: config.arrayRoot }); if (!config.whitespace) { xml = xml.replace(/>\n/g, '>'); } return xml; }; })(); utilities-1.0.6/package.json000066400000000000000000000007721423700441700160270ustar00rootroot00000000000000{ "name": "utilities", "description": "A classic collection of JavaScript utilities", "keywords": [ "utilities", "utils", "jake", "geddy" ], "version": "1.0.6", "author": "Matthew Eernisse (http://fleegix.org)", "main": "./lib/index.js", "scripts": { "test": "jake test" }, "repository": { "type": "git", "url": "git://github.com/mde/utilities.git" }, "devDependencies": { "jake": "latest" }, "engines": { "node": "*" } } utilities-1.0.6/test/000077500000000000000000000000001423700441700145125ustar00rootroot00000000000000utilities-1.0.6/test/array.js000066400000000000000000000037241423700441700161740ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var assert = require('assert') , array = require('../lib/array') , tests; tests = { 'test basic humanize for array': function () { var actual = array.humanize(["array", "array", "array"]) , expected = "array, array and array"; assert.equal(expected, actual); } , '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 a single item for array': function () { var actual = array.humanize(["array"]) , expected = "array"; assert.equal(expected, actual); } , '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 test = ["array"] , actual = array.include(test, 'nope'); assert.equal(false, actual); } , 'test false boolean include for array': function () { var test = ["array", false] , actual = array.include(test, false); assert.equal(true, actual); } }; module.exports = tests; utilities-1.0.6/test/core.js000066400000000000000000000051611423700441700160030ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var assert = require('assert') , core = require('../lib/core') , tests; tests = { 'simple mixin for core': function () { var expected = {secret: 'asdf', geddy: 'geddyKey'} , result = core.mixin({secret: 'asdf'}, {geddy: 'geddyKey'}); assert.deepEqual(expected, result); } , 'mixin with overiding key for core': function () { var expected = {secret: 'geddySecret', geddy: 'geddyKey'} , result = core.mixin({secret: 'asdf'}, {geddy: 'geddyKey', secret: 'geddySecret'}); assert.deepEqual(expected, result); } , 'simple enhance for core': function () { var expected = {secret: 'asdf', geddy: 'geddyKey'} , result = core.enhance({secret: 'asdf'}, {geddy: 'geddyKey'}); assert.deepEqual(expected, result); } , 'enhance with overiding key for core': function () { var expected = {secret: 'geddySecret', geddy: 'geddyKey'} , result = core.enhance({secret: 'asdf'}, {geddy: 'geddyKey', secret: 'geddySecret'}); assert.deepEqual(expected, result); } , 'isEmpty, empty string (true)': function () { assert.ok(core.isEmpty('')); } , 'isEmpty, null (true)': function () { assert.ok(core.isEmpty(null)); } , 'isEmpty, undefined (true)': function () { assert.ok(core.isEmpty(null)); } , 'isEmpty, NaN (true)': function () { assert.ok(core.isEmpty(NaN)); } , 'isEmpty, invalid Date (true)': function () { assert.ok(core.isEmpty(new Date(NaN))); } , 'isEmpty, zero (false)': function () { assert.ok(!core.isEmpty(0)); } , 'bind': function () { function bar() {} function foo() { assert.equal(this.name, 'bar'); } var fooBoundToBar = core.bind(bar, foo); fooBoundToBar(); } , 'bind, arguments': function () { function bar() {} function foo(arg) { assert.equal(this.name, 'bar'); assert.equal(arg, 'cats'); } var fooBoundToBarWithCats = core.bind(bar, foo, 'cats'); fooBoundToBarWithCats(); } }; module.exports = tests; utilities-1.0.6/test/date.js000066400000000000000000000046421423700441700157730ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var date = require('../lib/date') , assert = require('assert') , tests = {} , _date = new Date(); tests = { 'test strftime for date': function () { var data = date.strftime(_date, "%w") , actual = _date.getDay(); assert.equal(actual, data); } , 'test calcCentury using current year for date': function () { var data = date.calcCentury() , actual = '21'; assert.equal(actual, data); } , 'test calcCentury using 20th century year for date': function () { var data = date.calcCentury(2000) , actual = '20'; assert.equal(actual, data); } , 'test calcCentury using 1st century year for date': function () { var data = date.calcCentury(10) , actual = '1'; assert.equal(actual, data); } , 'test getMeridiem for date': function () { var data = date.getMeridiem(_date.getHours()) , actual = (_date.getHours() > 11) ? 'PM' : 'AM'; assert.equal(actual, data); } , 'test parse UTC': function () { var dt = date.parse('1970-01-01T00:00:00Z'); assert.equal(0, dt.getTime()); } , 'test parse with offset basic': function () { var dt; dt = date.parse('1970-01-01T00:00:00-0100'); assert.equal(3600000, dt.getTime()); dt = date.parse('1970-01-01T00:00:00+0100'); assert.equal(-3600000, dt.getTime()); } , 'test parse with offset extended': function () { var dt; dt = date.parse('1970-01-01T00:00:00-01:00'); assert.equal(3600000, dt.getTime()); dt = date.parse('1970-01-01T00:00:00+01:00'); assert.equal(-3600000, dt.getTime()); } , 'test parse floating (i.e., local offset)': function () { var dt; dt = date.parse('1970-01-01T00:00:00'); assert.equal(dt.getTime() / 1000 / 60, dt.getTimezoneOffset()); } }; module.exports = tests; utilities-1.0.6/test/event_buffer.js000066400000000000000000000026071423700441700175270ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var Stream = require('stream').Stream , EventEmitter = require('events').EventEmitter , EventBuffer = require('../lib/event_buffer.js').EventBuffer , assert = require('assert') , tests; tests = { 'test basic event buffer functionality': function () { var source = new Stream() , dest = new EventEmitter() , buff = new EventBuffer(source) , data = ''; dest.on('data', function (d) { data += d; }); source.writeable = true; source.readable = true; source.emit('data', 'abcdef'); source.emit('data', '123456'); buff.sync(dest); assert.equal('abcdef123456', data); source.emit('data', '---'); assert.equal('abcdef123456---', data); } }; module.exports = tests; utilities-1.0.6/test/file.js000066400000000000000000000245661423700441700160040ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var assert = require('assert') , fs = require('fs') , path = require('path') , file = require('../lib/file') , existsSync = fs.existsSync || path.existsSync , tests; tests = { 'before': function () { process.chdir('./test'); } , 'after': function () { process.chdir('../'); } , 'test mkdirP': function () { var expected = [ ['foo'] , ['foo', 'bar'] , ['foo', 'bar', 'baz'] , ['foo', 'bar', 'baz', 'qux'] ] , res; file.mkdirP('foo/bar/baz/qux'); res = file.readdirR('foo'); for (var i = 0, ii = res.length; i < ii; i++) { assert.equal(path.join.apply(path, expected[i]), res[i]); } file.rmRf('foo', {silent: true}); } , 'test rmRf': function () { file.mkdirP('foo/bar/baz/qux', {silent: true}); file.rmRf('foo/bar', {silent: true}); res = file.readdirR('foo'); assert.equal(1, res.length); assert.equal('foo', res[0]); fs.rmdirSync('foo'); } , 'test rmRf with symlink subdir': function () { file.mkdirP('foo'); file.mkdirP('bar'); fs.writeFileSync('foo/hello.txt', 'hello, it\'s me'); fs.symlinkSync('../foo', 'bar/foo'); file.rmRf('bar', {silent: true}); // Make sure the bar directory was successfully deleted var barDeleted = false; try { var stat = fs.statSync('bar'); } catch(err) { if(err.code == 'ENOENT') { barDeleted = true; } } assert.equal(true, barDeleted); // Make sure that the file inside the linked folder wasn't deleted res = fs.readdirSync('foo'); assert.equal(1, res.length); assert.equal('hello.txt', res[0]); // Cleanup fs.unlinkSync('foo/hello.txt'); fs.rmdirSync('foo'); } , 'test rmRf with symlinked dir': function () { file.mkdirP('foo'); fs.writeFileSync('foo/hello.txt', 'hello!'); fs.symlinkSync('foo', 'bar'); file.rmRf('bar', {silent: true}); // Make sure the bar directory was successfully deleted var barDeleted = false; try { var stat = fs.statSync('bar'); } catch(err) { if(err.code == 'ENOENT') { barDeleted = true; } } assert.equal(true, barDeleted); // Make sure that the file inside the linked folder wasn't deleted res = fs.readdirSync('foo'); assert.equal(1, res.length); assert.equal('hello.txt', res[0]); // Cleanup fs.unlinkSync('foo/hello.txt'); fs.rmdirSync('foo'); } , 'test cpR with same name and different directory': function () { file.mkdirP('foo', {silent: true}); fs.writeFileSync('foo/bar.txt', 'w00t'); file.cpR('foo', 'bar', {silent: true}); assert.ok(existsSync('bar/bar.txt')); file.rmRf('foo', {silent: true}); file.rmRf('bar', {silent: true}); } , 'test cpR with same to and from will throw': function () { assert.throws(function () { file.cpR('foo.txt', 'foo.txt', {silent: true}); }); } , 'test cpR rename via copy in directory': function () { file.mkdirP('foo', {silent: true}); fs.writeFileSync('foo/bar.txt', 'w00t'); file.cpR('foo/bar.txt', 'foo/baz.txt', {silent: true}); assert.ok(existsSync('foo/baz.txt')); file.rmRf('foo', {silent: true}); } , 'test cpR rename via copy in base': function () { fs.writeFileSync('bar.txt', 'w00t'); file.cpR('bar.txt', 'baz.txt', {silent: true}); assert.ok(existsSync('baz.txt')); file.rmRf('bar.txt', {silent: true}); file.rmRf('baz.txt', {silent: true}); } , 'test cpR keeps file mode': function () { fs.writeFileSync('bar.txt', 'w00t', {mode: 0750}); fs.writeFileSync('bar1.txt', 'w00t!', {mode: 0744}); file.cpR('bar.txt', 'baz.txt', {silent: true}); file.cpR('bar1.txt', 'baz1.txt', {silent: true}); assert.ok(existsSync('baz.txt')); assert.ok(existsSync('baz1.txt')); var bazStat = fs.statSync('baz.txt'); var bazStat1 = fs.statSync('baz1.txt'); assert.equal(0750, bazStat.mode & 07777); assert.equal(0744, bazStat1.mode & 07777); file.rmRf('bar.txt', {silent: true}); file.rmRf('baz.txt', {silent: true}); file.rmRf('bar1.txt', {silent: true}); file.rmRf('baz1.txt', {silent: true}); } , 'test cpR keeps file mode when overwriting with preserveMode': function () { fs.writeFileSync('bar.txt', 'w00t', {mode: 0755}); fs.writeFileSync('baz.txt', 'w00t!', {mode: 0744}); file.cpR('bar.txt', 'baz.txt', {silent: true, preserveMode: true}); assert.ok(existsSync('baz.txt')); var bazStat = fs.statSync('baz.txt'); assert.equal(0755, bazStat.mode & 07777); file.rmRf('bar.txt', {silent: true}); file.rmRf('baz.txt', {silent: true}); } , 'test cpR does not keep file mode when overwriting': function () { fs.writeFileSync('bar.txt', 'w00t', {mode: 0766}); fs.writeFileSync('baz.txt', 'w00t!', {mode: 0744}); file.cpR('bar.txt', 'baz.txt', {silent: true}); assert.ok(existsSync('baz.txt')); var bazStat = fs.statSync('baz.txt'); assert.equal(0744, bazStat.mode & 07777); file.rmRf('bar.txt', {silent: true}); file.rmRf('baz.txt', {silent: true}); } , 'test cpR copies file mode recursively': function () { fs.mkdirSync('foo'); fs.writeFileSync('foo/bar.txt', 'w00t', {mode: 0740}); file.cpR('foo', 'baz', {silent: true}); assert.ok(existsSync('baz')); var barStat = fs.statSync('baz/bar.txt'); assert.equal(0740, barStat.mode & 07777); file.rmRf('foo'); file.rmRf('baz'); } , 'test cpR keeps file mode recursively': function () { fs.mkdirSync('foo'); fs.writeFileSync('foo/bar.txt', 'w00t', {mode: 0740}); fs.mkdirSync('baz'); fs.mkdirSync('baz/foo'); fs.writeFileSync('baz/foo/bar.txt', 'w00t!', {mode: 0755}); file.cpR('foo', 'baz', {silent: true, preserveMode: true}); assert.ok(existsSync('baz')); var barStat = fs.statSync('baz/foo/bar.txt'); assert.equal(0740, barStat.mode & 07777); file.rmRf('foo'); file.rmRf('baz'); } , 'test cpR copies directory mode recursively': function () { fs.mkdirSync('foo', 0755); fs.mkdirSync('foo/bar', 0700); file.cpR('foo', 'bar'); assert.ok(existsSync('foo')); var fooBarStat = fs.statSync('bar/bar'); assert.equal(0700, fooBarStat.mode & 07777); file.rmRf('foo'); file.rmRf('bar'); } , 'test readdirR': function () { var expected = [ ['foo'] , ['foo', 'bar'] , ['foo', 'bar', 'baz'] , ['foo', 'bar', 'baz', 'qux'] ] , res; file.mkdirP('foo/bar/baz/qux', {silent: true}); res = file.readdirR('foo'); for (var i = 0, ii = res.length; i < ii; i++) { assert.equal(path.join.apply(path, 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('/foo/bar', file.basedir(p)); } , 'test basedir with Win absolute path': function () { var p = 'C:\\foo\\bar\\baz'; assert.equal('C:\\foo\\bar', file.basedir(p)); } , 'test basedir with Unix root path': function () { var p = '/'; assert.equal('/', file.basedir(p)); } , 'test basedir with Unix absolute path and double-asterisk': function () { var p = '/**/foo/bar/baz'; assert.equal('/', file.basedir(p)); } , 'test basedir with leading double-asterisk': function () { var p = '**/foo'; assert.equal('.', file.basedir(p)); } , 'test basedir with leading asterisk': function () { var p = '*.js'; assert.equal('.', file.basedir(p)); } , 'test basedir with leading dot-slash and double-asterisk': function () { var p = './**/foo'; assert.equal('.', file.basedir(p)); } , 'test basedir with leading dirname and double-asterisk': function () { var p = 'a/**/*.js'; assert.equal('a', file.basedir(p)); } , 'test basedir with leading dot-dot-slash and double-asterisk': function () { var p = '../../test/**/*.js'; assert.equal('../../test', file.basedir(p)); } , 'test basedir with single-asterisk in dirname': function () { var p = 'a/test*/file'; assert.equal('a', file.basedir(p)); } , 'test basedir with single filename': function () { var p = 'filename'; assert.equal('.', file.basedir(p)); } , 'test basedir with empty path': function () { var p = ''; assert.equal('.', file.basedir(p)); assert.equal('.', file.basedir()); } }; module.exports = tests; utilities-1.0.6/test/i18n.js000066400000000000000000000033071423700441700156320ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var i18n = require('../lib/i18n') , assert = require('assert') , tests , inst = {}; tests = { 'before': function () { i18n.loadLocale('en-us', {foo: 'FOO', bar: 'BAR', baz: 'BAZ'}); i18n.loadLocale('ja-jp', {foo: 'フー', bar: 'バー'}); inst.en = new i18n.I18n('en-us'); inst.jp = new i18n.I18n('ja-jp'); inst.de = new i18n.I18n('de-de'); } , 'test default-locale fallback, defined strings': function () { var expected = 'BAZ' , actual = inst.jp.t('baz'); assert.equal(expected, actual); } , 'test default-locale fallback, no defined strings': function () { var expected = 'BAZ' , actual = inst.de.t('baz'); assert.equal(expected, actual); } , 'test key lookup, default-locale': function () { var expected = 'FOO' , actual = inst.en.t('foo'); assert.equal(expected, actual); } , 'test key lookup, non-default-locale': function () { var expected = 'フー' , actual = inst.jp.t('foo'); assert.equal(expected, actual); } }; module.exports = tests; utilities-1.0.6/test/inflection.js000066400000000000000000000333601423700441700172070ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var inflection = require('../lib/inflection') , assert = require('assert') , esInflections , sInflections , iesInflections , vesInflections , icesInflections , renInflections , oesInflections , iInflections , genInflections , irregularInflections , noInflections , tests; /** * Most test inflections are from Ruby on Rails: * https://github.com/rails/rails/blob/master/activesupport/test/inflector_test_cases.rb * * Ruby on Rails is MIT licensed: http://www.opensource.org/licenses/MIT */ esInflections = [ ["search", "searches"] , ["switch", "switches"] , ["fix", "fixes"] , ["box", "boxes"] , ["process", "processes"] , ["address", "addresses"] , ["wish", "wishes"] , ["status", "statuses"] , ["alias", "aliases"] , ["basis", "bases"] , ["diagnosis", "diagnoses"] , ["bus", "buses"] ]; sInflections = [ ["stack", "stacks"] , ["shoe", "shoes"] , ["status_code", "status_codes"] , ["case", "cases"] , ["edge", "edges"] , ["archive", "archives"] , ["experience", "experiences"] , ["day", "days"] , ["comment", "comments"] , ["foobar", "foobars"] , ["newsletter", "newsletters"] , ["old_news", "old_news"] , ["perspective", "perspectives"] , ["diagnosis_a", "diagnosis_as"] , ["horse", "horses"] , ["prize", "prizes"] ]; iesInflections = [ ["category", "categories"] , ["query", "queries"] , ["ability", "abilities"] , ["agency", "agencies"] ]; vesInflections = [ ["wife", "wives"] , ["safe", "saves"] , ["half", "halves"] , ["elf", "elves"] , ["dwarf", "dwarves"] ]; icesInflections = [ ["index", "indices"] , ["vertex", "vertices"] , ["matrix", "matrices"] ]; renInflections = [ ["node_child", "node_children"] , ["child", "children"] ]; oesInflections = [ ["buffalo", "buffaloes"] , ["tomato", "tomatoes"] ]; iInflections = [ ["octopus", "octopi"] , ["virus", "viri"] ]; genInflections = [ ["salesperson", "salespeople"] , ["person", "people"] , ["spokesman", "spokesmen"] , ["man", "men"] , ["woman", "women"] ]; irregularInflections = [ ["datum", "data"] , ["medium", "media"] , ["ox", "oxen"] , ["cow", "kine"] , ["mouse", "mice"] , ["louse", "lice"] , ["axis", "axes"] , ["testis", "testes"] , ["crisis", "crises"] , ["analysis", "analyses"] , ["quiz", "quizzes"] ]; noInflections = [ ["fish", "fish"] , ["news", "news"] , ["series", "series"] , ["species", "species"] , ["rice", "rice"] , ["information", "information"] , ["equipment", "equipment"] ]; tests = { 'test es plural words for inflection': function () { var i = esInflections.length , value; while (--i >= 0) { value = esInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test es singular words for inflection': function () { var i = esInflections.length , value; while (--i >= 0) { value = esInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test es plural words for inflection consistency': function() { var i = esInflections.length , value; while (--i >= 0) { value = esInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test es singular words for inflection consistency': function() { var i = esInflections.length , value; while (--i >= 0) { value = esInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test s plural words for inflection': function () { var i = sInflections.length , value; while (--i >= 0) { value = sInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test s singular words for inflection': function () { var i = sInflections.length , value; while (--i >= 0) { value = sInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test s plural words for inflection consistency': function () { var i = sInflections.length , value; while (--i >= 0) { value = sInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test s singular words for inflection consistency': function () { var i = sInflections.length , value; while (--i >= 0) { value = sInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test ies plural words for inflection': function () { var i = iesInflections.length , value; while (--i >= 0) { value = iesInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test ies singular words for inflection': function () { var i = iesInflections.length , value; while (--i >= 0) { value = iesInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test ies plural words for inflection consistency': function () { var i = iesInflections.length , value; while (--i >= 0) { value = iesInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test ies singular words for inflection consistency': function () { var i = iesInflections.length , value; while (--i >= 0) { value = iesInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test ves plural words for inflection': function () { var i = vesInflections.length , value; while (--i >= 0) { value = vesInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test ves singular words for inflection': function () { var i = vesInflections.length , value; while (--i >= 0) { value = vesInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test ves plural words for inflection consistency': function () { var i = vesInflections.length , value; while (--i >= 0) { value = vesInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test ves singular words for inflection consistency': function () { var i = vesInflections.length , value; while (--i >= 0) { value = vesInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test ices plural words for inflection': function () { var i = icesInflections.length , value; while (--i >= 0) { value = icesInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test ices singular words for inflection': function () { var i = icesInflections.length , value; while (--i >= 0) { value = icesInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test ices plural words for inflection consistency': function () { var i = icesInflections.length , value; while (--i >= 0) { value = icesInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test ices singular words for inflection consistency': function () { var i = icesInflections.length , value; while (--i >= 0) { value = icesInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test ren plural words for inflection': function () { var i = renInflections.length , value; while (--i >= 0) { value = renInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test ren singular words for inflection': function () { var i = renInflections.length , value; while (--i >= 0) { value = renInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test ren plural words for inflection consistency': function () { var i = renInflections.length , value; while (--i >= 0) { value = renInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test ren singular words for inflection consistency': function () { var i = renInflections.length , value; while (--i >= 0) { value = renInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test oes plural words for inflection': function () { var i = oesInflections.length , value; while (--i >= 0) { value = oesInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test oes singular words for inflection': function () { var i = oesInflections.length , value; while (--i >= 0) { value = oesInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test oes plural words for inflection consistency': function () { var i = oesInflections.length , value; while (--i >= 0) { value = oesInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test oes singular words for inflection consistency': function () { var i = oesInflections.length , value; while (--i >= 0) { value = oesInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test i plural words for inflection': function () { var i = iInflections.length , value; while (--i >= 0) { value = iInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test i singular words for inflection': function () { var i = iInflections.length , value; while (--i >= 0) { value = iInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test i plural words for inflection consistency': function () { var i = iInflections.length , value; while (--i >= 0) { value = iInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test i singular words for inflection consistency': function () { var i = iInflections.length , value; while (--i >= 0) { value = iInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test gender and people plural words for inflection': function () { var i = genInflections.length , value; while (--i >= 0) { value = genInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test gender and people singular words for inflection': function () { var i = genInflections.length , value; while (--i >= 0) { value = genInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test gender and people plural words for inflection consistency': function () { var i = genInflections.length , value; while (--i >= 0) { value = genInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test gender and people singular words for inflection consistency': function () { var i = genInflections.length , value; while (--i >= 0) { value = genInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test irregular plural words for inflection': function () { var i = irregularInflections.length , value; while (--i >= 0) { value = irregularInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test irregular singular words for inflection': function () { var i = irregularInflections.length , value; while (--i >= 0) { value = irregularInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test irregular plural words for inflection consistency': function () { var i = irregularInflections.length , value; while (--i >= 0) { value = irregularInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test irregular singular words for inflection consistency': function () { var i = irregularInflections.length , value; while (--i >= 0) { value = irregularInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } , 'test no change plural words for inflection': function () { var i = noInflections.length , value; while (--i >= 0) { value = noInflections[i]; assert.equal(value[1], inflection.pluralize(value[0])) } } , 'test no change singular words for inflection': function () { var i = noInflections.length , value; while (--i >= 0) { value = noInflections[i]; assert.equal(value[0], inflection.singularize(value[1])) } } , 'test no change plural words for inflection consistency': function () { var i = noInflections.length , value; while (--i >= 0) { value = noInflections[i]; assert.equal(value[1], inflection.pluralize(value[1])) } } , 'test no change singular words for inflection consistency': function () { var i = noInflections.length , value; while (--i >= 0) { value = noInflections[i]; assert.equal(value[0], inflection.singularize(value[0])) } } }; module.exports = tests; utilities-1.0.6/test/logging.js000066400000000000000000000034771423700441700165110ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var assert = require('assert') , logger = require('../lib/log') , tests; tests = { 'test basic logging': function () { var oldLog = console.log; console.log = function (str) { assert.equal(str, "basic log"); }; logger.log("basic log"); console.log = oldLog; } , 'test info logging': function () { var oldinfoLog = console.info; console.info = function (str) { assert.equal(str, "info log"); }; logger.info("info log"); console.info = oldinfoLog; } , 'test warning logging': function () { var oldwarnLog = console.warn; console.warn = function (str) { assert.equal(str, "warn log"); }; logger.warn("warn log"); console.warn = oldwarnLog; } , 'test error logging': function () { var oldErrorLog = console.error; console.error = function (str) { assert.equal(str, "error log"); }; logger.error("error log"); console.error = oldErrorLog; } } module.exports = tests;utilities-1.0.6/test/object.js000066400000000000000000000051611423700441700163210ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var object = require('../lib/object') , array = require('../lib/array') , assert = require('assert') , tests = {} , checkObjects; tests = { 'test merge in object': function () { var expected = {user: 'geddy', key: 'key'} , actual = object.merge({user: 'geddy'}, {key: 'key'}); assert.deepEqual(actual, expected); } , 'test merge with overwriting keys in object': function () { var expected = {user: 'geddy', key: 'key'} , actual = object.merge({user: 'geddy', key: 'geddyKey'}, {key: 'key'}); assert.deepEqual(actual, expected); } , 'test merge with objects as keys': function () { var expected = {user: {name: 'geddy', password: 'random', key: 'key'}, key: 'key'} , actual = object.merge({key: 'key'}, {user: {name: 'geddy', password: 'random', key: 'key'}}); assert.deepEqual(actual, expected); } , 'test reverseMerge in object': function () { var expected = {user: 'geddy', key: 'key'} , actual = object.reverseMerge({user: 'geddy'}, {key: 'key'}); assert.deepEqual(actual, expected); } , 'test reverseMerge with keys overwriting default in object': function () { var expected = {user: 'geddy', key: 'geddyKey'} , actual = object.reverseMerge({user: 'geddy', key: 'geddyKey'}, {key: 'key'}); assert.deepEqual(actual, expected); } , 'test reverseMerge with objects as keys': function () { var expected = {user: {name: 'geddy', password: 'random', key: 'key'}, key: 'key'} , actual = object.merge({user: {name: 'geddy', password: 'random', key: 'key'}}, {key: 'key'}); assert.deepEqual(actual, expected); } , 'test isEmpty with non empty object in object': function () { var expected = false , actual = object.isEmpty({user: 'geddy'}); assert.equal(actual, expected); } , 'test isEmpty with empty object in object': function () { var expected = true , actual = object.isEmpty({}); assert.equal(actual, expected); } }; module.exports = tests; utilities-1.0.6/test/sorted_collection.js000066400000000000000000000063061423700441700205700ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var SortedCollection = require('../lib/sorted_collection').SortedCollection , assert = require('assert') , tests; tests = { 'test no default value': function () { // Set up a collection, no default value for new items var c = new SortedCollection(); // Add some items c.addItem('testA', 'AAAA'); c.addItem('testB', 'BBBB'); c.addItem('testC', 'CCCC'); // Test count assert.equal(3, c.count); // Test getItem by string key var item = c.getItem('testC'); assert.equal('CCCC', item); // Test getItem by index number var item = c.getItem(1); assert.equal('BBBB', item); // Test setItem by string key c.setItem('testA', 'aaaa'); var item = c.getItem('testA'); assert.equal('aaaa', item); // Test setItem by index number c.setItem(2, 'cccc'); var item = c.getItem(2); assert.equal('cccc', item); } , 'test default value': function () { // Set up a collection, default value for new items is 'foo' var c = new SortedCollection('foo'); // Add an item with no value -- should get // default value c.addItem('testA'); // Add some items with empty/falsey values -- // should be set to desired values c.addItem('testB', null); c.addItem('testC', false); // Test getItem for default value var item = c.getItem('testA'); assert.equal('foo', item); var item = c.getItem('testB'); assert.equal(null, item); var item = c.getItem('testC'); assert.equal(false, item); } , 'test each': function () { var c = new SortedCollection() , str = ''; // Add an item with no value -- should get // default value c.addItem('a', 'A'); c.addItem('b', 'B'); c.addItem('c', 'C'); c.addItem('d', 'D'); c.each(function (val, key) { str += val + key; }); assert.equal('AaBbCcDd', str); } , 'test removing an item': function () { var c = new SortedCollection() , str = ''; // Add an item with no value -- should get // default value c.addItem('a', 'A'); c.addItem('b', 'B'); c.addItem('c', 'C'); c.addItem('d', 'D'); assert.equal(4, c.count); omg = c.removeItem('c'); assert.equal(3, c.count); c.each(function (val, key) { str += val + key; }); assert.equal('AaBbDd', str); } , 'test clone': function () { var c = new SortedCollection() , copy; c.addItem('a', 'A'); c.addItem('b', 'B'); copy = c.clone(); assert.equal(2, copy.count); assert.equal('A', copy.getItem('a')); } }; module.exports = tests; utilities-1.0.6/test/string.js000066400000000000000000000303051423700441700163570ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var assert = require('assert') , string = require('../lib/string') , tests; tests = { 'test basic escapeXML for string': function () { var expected = '<html></html>' , actual = string.escapeXML(''); assert.equal(expected, actual); } , 'test all escape characters for escapeXML': function () { var expected = '<>&"'' , actual = string.escapeXML('<>&"\''); assert.equal(expected, actual); } , 'test no escape characters with string for escapeXML': function () { var expected = 'Geddy' , actual = string.escapeXML('Geddy'); assert.equal(expected, actual); } , 'test no escape characters with numbers for escapeXML': function () { var expected = 05 , actual = string.escapeXML(05); assert.equal(expected, actual); } , 'test basic unescapeXML for string': function () { var expected = '' , actual = string.unescapeXML('<html></html>'); assert.equal(expected, actual); } , 'test all escape characters for unescapeXML': function () { var expected = '<>&"\'' , actual = string.unescapeXML('<>&"''); assert.equal(expected, actual); } , 'test no escape characters with string for unescapeXML': function () { var expected = 'Geddy' , actual = string.unescapeXML('Geddy'); assert.equal(expected, actual); } , 'test no escape characters with numbers for unescapeXML': function () { var expected = 05 , actual = string.unescapeXML(05); assert.equal(expected, actual); } , 'test basic needsEscape for string': function () { var expected = true , actual = string.needsEscape('Geddy>'); assert.equal(expected, actual); } , 'test basic needsEscape thats false for string': function () { var expected = false , actual = string.needsEscape('Geddy'); assert.equal(expected, actual); } , 'test basic needsUnescape for string': function () { var expected = true , actual = string.needsEscape('"Geddy"'); assert.equal(expected, actual); } , 'test basic needsUnescape thats false for string': function () { var expected = false , actual = string.needsEscape('Geddy'); assert.equal(expected, actual); } , 'test escapeRegExpCharacters': function () { var expected = '\\^\\/\\.\\*\\+\\?\\|\\(\\)\\[\\]\\{\\}\\\\' actual = string.escapeRegExpChars('^/.*+?|()[]{}\\'); assert.equal(expected, actual); } , 'test toArray for string': function () { var data = string.toArray('geddy') , expected = ['g', 'e', 'd', 'd', 'y']; // Loop through each item and check // if not, then the arrays aren't _really_ the same var i = expected.length; while (--i >= 0) { assert.equal(expected[i], data[i]); } } , 'test reverse for string': function () { var data = string.reverse('yddeg') , expected = 'geddy'; assert.equal(expected, data); } , 'test basic ltrim for string': function () { var data = string.ltrim(' geddy') , expected = 'geddy'; assert.equal(expected, data); } , 'test custom char ltrim for string': function () { var data = string.ltrim('&&geddy', '&') , expected = 'geddy'; assert.equal(expected, data); } , 'test basic rtrim for string': function () { var data = string.rtrim('geddy ') , expected = 'geddy'; assert.equal(expected, data); } , 'test custom char rtrim for string': function () { var data = string.rtrim('geddy&&', '&') , expected = 'geddy'; assert.equal(expected, data); } , 'test basic trim for string': function () { var data = string.trim(' geddy ') , expected = 'geddy'; assert.equal(expected, data); } , 'test custom char trim for string': function () { var data = string.trim('&geddy&&', '&') , expected = 'geddy'; assert.equal(expected, data); } , 'test chop special-case line-ending': function () { var expected = 'geddy' , actual = string.chop('geddy\r\n'); assert.equal(expected, actual); } , 'test chop not actual special-case line-ending': function () { var expected = 'geddy\n' , actual = string.chop('geddy\n\r'); assert.equal(expected, actual); } , 'test chop normal line-ending': function () { var expected = 'geddy' , actual = string.chop('geddy\n'); assert.equal(expected, actual); } , 'test chop whatever character': function () { var expected = 'gedd' , actual = string.chop('geddy'); assert.equal(expected, actual); } , 'test chop empty string': function () { var expected = '' , actual = string.chop(''); assert.equal(expected, actual); } , 'test basic lpad for string': function () { var data = string.lpad('geddy', '&', 7) , expected = '&&geddy'; assert.equal(expected, data); } , 'test lpad without width for string': function () { var data = string.lpad('geddy', '&') , expected = 'geddy'; assert.equal(expected, data); } , 'test lpad without width of char for string': function () { var data = string.lpad('geddy') , expected = 'geddy'; assert.equal(expected, data); } , 'test basic rpad for string': function () { var data = string.rpad('geddy', '&', 7) , expected = 'geddy&&'; assert.equal(expected, data); } , 'test rpad without width for string': function () { var data = string.rpad('geddy', '&') , expected = 'geddy'; assert.equal(expected, data); } , 'test rpad without width of char for string': function () { var data = string.rpad('geddy') , expected = 'geddy'; assert.equal(expected, data); } , 'test basic pad for string': function () { var data = string.pad('geddy', '&', 7) , expected = '&geddy&'; assert.equal(expected, data); } , 'test pad without width for string': function () { var data = string.pad('geddy', '&') , expected = 'geddy'; assert.equal(expected, data); } , 'test pad without width of char for string': function () { var data = string.pad('geddy') , expected = 'geddy'; assert.equal(expected, data); } , 'test single tags in truncateHTML': function () { var str = string.truncateHTML('

Once upon a time in a world

', { length: 10 }); assert.equal(str, '

Once up...

'); } , 'test multiple tags in truncateHTML': function () { var str = string.truncateHTML('

Once upon a time in a world

', { length: 10 }); assert.equal(str, '

Once up...in a wo...

'); } , 'test multiple tags but only truncate once in truncateHTML': function () { var str = string.truncateHTML('

Once upon a time in a world

', { length: 10, once: true }); assert.equal(str, '

Once up...in a world

'); } , 'test standard truncate': function () { var str = string.truncate('Once upon a time in a world', { length: 10 }); assert.equal(str, 'Once up...'); } , 'test custom omission in truncate': function () { var str = string.truncate('Once upon a time in a world', { length: 10, omission: '///' }); assert.equal(str, 'Once up///'); } , 'test regex seperator in truncate': function () { var str = string.truncate('Once upon a time in a world', { length: 15, seperator: /\s/ }); assert.equal(str, 'Once upon a...'); } , 'test string seperator in truncate': function () { var str = string.truncate('Once upon a time in a world', { length: 15, seperator: ' ' }); assert.equal(str, 'Once upon a...'); } , 'test unsafe html in truncate': function () { var str = string.truncate('

Once upon a time in a world

', { length: 20 }); assert.equal(str, '

Once upon a ti...'); } , 'test nl2br for string': function () { var data = string.nl2br("geddy\n") , expected = 'geddy
'; assert.equal(expected, data); } , 'test snakeize for string': function () { var data = string.snakeize("geddyJs") , expected = 'geddy_js'; assert.equal(expected, data); } , 'test snakeize with beginning caps for string': function () { var data = string.snakeize("GeddyJs") , expected = 'geddy_js'; assert.equal(expected, data); } , 'test camelize for string': function () { var data = string.camelize("geddy_js") , expected = 'geddyJs'; assert.equal(expected, data); } , 'test camelize with initialCap for string': function () { var data = string.camelize("geddy_js", {initialCap: true}) , expected = 'GeddyJs'; assert.equal(expected, data); } , 'test camelize with leadingUnderscore with no underscore for string': function () { var data = string.camelize("geddy_js", {leadingUnderscore: true}) , expected = 'geddyJs'; assert.equal(expected, data); } , 'test camelize with leadingUnderscore with underscore for string': function () { var data = string.camelize("_geddy_js", {leadingUnderscore: true}) , expected = '_geddyJs'; assert.equal(expected, data); } , 'test decapitalize for string': function () { var data = string.decapitalize("Geddy") , expected = 'geddy'; assert.equal(expected, data); } , 'test capitalize for string': function () { var data = string.capitalize("geddy") , expected = 'Geddy'; assert.equal(expected, data); } , 'test dasherize for string': function () { var data = string.dasherize("geddyJs") , expected = 'geddy-js'; assert.equal(expected, data); } , 'test dasherize with custom replace char for string': function () { var data = string.dasherize("geddyJs", "_") , expected = 'geddy_js'; assert.equal(expected, data); } , 'test underscorize for string': function () { var data = string.underscorize("geddyJs") , expected = 'geddy_js'; assert.equal(expected, data); } , 'test include for string with included string': function () { assert.ok(string.include('foobarbaz', 'foo')); } , 'test include for string with not included string': function () { assert.ok(!string.include('foobarbaz', 'qux')); } , 'test getInflections for string': function () { var actual = string.getInflections("string") , expected = { filename: { normal: "string" , singular: "string" , plural: "strings" }, constructor: { normal: "String" , singular: "String" , plural: "Strings" }, property: { normal: "string" , singular: "string" , plural: "strings" }, }; assert.deepEqual(expected, actual); } , 'test inflection with odd name for string': function () { var actual = string.getInflections("snow_dog") , expected = { filename: { normal: "snow_dog" , singular: "snow_dog" , plural: "snow_dogs" }, constructor: { normal: "SnowDog" , singular: "SnowDog" , plural: "SnowDogs" }, property: { normal: "snowDog" , singular: "snowDog" , plural: "snowDogs" }, }; assert.deepEqual(expected, actual); } , 'test uuid length for string': function () { var data = string.uuid(5).length , expected = 5; assert.equal(expected, data); } , 'test stripTags': function () { var html = '

foo

bar
wooby

' , expected = 'foobarwooby'; assert.equal(string.stripTags(html), expected); } , 'test stripTags with allowed
': function () { var html = '
foo

bar
wooby

' , expected = 'foobar
wooby'; assert.equal(string.stripTags(html, '
'), expected); } }; module.exports = tests; utilities-1.0.6/test/uri.js000066400000000000000000000103771423700441700156570ustar00rootroot00000000000000/* * Utilities: A classic collection of JavaScript utilities * Copyright 2112 Matthew Eernisse (mde@fleegix.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * 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. * */ var uri = require('../lib/uri') , array = require('../lib/array') , assert = require('assert') , tests = {}; tests = { 'test getFileExtension for uri': function () { var data = uri.getFileExtension('users.json') , actual = 'json'; assert.equal(actual, data); } , 'test paramify for uri': function () { var data = uri.paramify({username: 'user', token: 'token', secret: 'secret'}) , actual = 'username=user&token=token&secret=secret'; assert.equal(actual, data); } , 'test paramify with conslidate option for uri': function () { var data = uri.paramify({username: 'user', auth: ['token', 'secret']}, {conslidate: true}) , actual = 'username=user&auth=token&auth=secret'; assert.equal(actual, data); } , 'test paramify with includeEmpty option for uri': function () { var data = uri.paramify({username: 'user', token: ''}, {includeEmpty: true}) , actual = 'username=user&token='; assert.equal(actual, data); } , 'test paramify with includeEmpty as 0 option for uri': function () { var data = uri.paramify({username: 'user', token: 0}, {includeEmpty: true}) , actual = 'username=user&token=0'; assert.equal(actual, data); } , 'test paramify with includeEmpty as null option for uri': function () { var data = uri.paramify({username: 'user', token: null}, {includeEmpty: true}) , actual = 'username=user&token='; assert.equal(actual, data); } , 'test paramify with includeEmpty as undefined option for uri': function () { var data = uri.paramify({username: 'user', token: undefined}, {includeEmpty: true}) , actual = 'username=user&token='; assert.equal(actual, data); } , 'test paramify with snakeize option for uri': function () { var data = uri.paramify({username: 'user', authToken: 'token'}, {snakeize: true}) , actual = 'username=user&auth_token=token'; assert.equal(actual, data); } , 'test paramify with escapeVals option for uri': function () { var data = uri.paramify({username: 'user', token: '