diff --git a/dist/underscore-contrib.js b/dist/underscore-contrib.js index 036e06a..759212e 100644 --- a/dist/underscore-contrib.js +++ b/dist/underscore-contrib.js @@ -9,20 +9,21 @@ // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- // Create quick reference variables for speed access to core prototypes. - var slice = Array.prototype.slice, - concat = Array.prototype.concat; + var slice = Array.prototype.slice; var existy = function(x) { return x != null; }; @@ -35,14 +36,7 @@ // array. If given an `arguments` object, `cat` will treat it like an array // and concatenate it likewise. cat: function() { - return _.reduce(arguments, function(acc, elem) { - if (_.isArguments(elem)) { - return concat.call(acc, slice.call(elem)); - } - else { - return concat.call(acc, elem); - } - }, []); + return _.flatten(arguments, true); }, // 'Constructs' an array by putting an element at its front @@ -90,7 +84,7 @@ // Maps a function over an array and concatenates all of the results. mapcat: function(array, fun) { - return _.cat.apply(null, _.map(array, fun)); + return _.flatten(_.map(array, fun), true); }, // Returns an array with some item between each element @@ -193,27 +187,41 @@ // built-in `Array.prototype.reverse` method, this does not mutate the // original object. Note: attempting to use this method on a string will // result in a `TypeError`, as it cannot properly reverse unicode strings. - reverseOrder: function(obj) { if (typeof obj == 'string') throw new TypeError('Strings cannot be reversed by _.reverseOrder'); return slice.call(obj).reverse(); + }, + + // Creates an array with all possible combinations of elements from + // the given arrays + combinations: function(){ + return _.reduce(slice.call(arguments, 1),function(ret,newarr){ + return _.reduce(ret,function(memo,oldi){ + return memo.concat(_.map(newarr,function(newi){ + return oldi.concat([newi]); + })); + },[]); + },_.map(arguments[0],function(i){return [i];})); } + }); -})(this); +}).call(this); // Underscore-contrib (underscore.array.selectors.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -251,6 +259,29 @@ if ((index != null) && !guard) return array[index]; }, + // A function to get values via indices into an array + nths: nths = function(array, indices) { + if (array == null) return void 0; + + if (isSeq(indices)) + return _(indices).map(function(i){return array[i];}); + else + return nths(array, slice.call(arguments, 1)); + }, + valuesAt: nths, + + // A function to get at "truthily" indexed values + // bin refers to "binary" nature of true/false values in binIndices + // but can also be thought of as putting array values into either "take" or "don't" bins + binPick: function binPick(array, binIndices) { + if (array == null) return void 0; + + if (isSeq(binIndices)) + return _.nths(array, _.range(binIndices.length).filter(function(i){return binIndices[i];})); + else + return binPick(array, slice.call(arguments, 1)); + }, + // Takes all items in an array while a given predicate returns truthy. takeWhile: function(array, pred) { if (!isSeq(array)) throw new TypeError; @@ -319,19 +350,21 @@ } }); -})(this); +}).call(this); // Underscore-contrib (underscore.collections.walk.js 0.3.0) // (c) 2013 Patrick Dubroy // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -516,19 +549,21 @@ // Use `_.walk` as a namespace to hold versions of the walk functions which // use the default traversal strategy. _.extend(_.walk, _.walk()); -})(this); +}).call(this); // Underscore-contrib (underscore.function.arity.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -591,6 +626,30 @@ }; }()); + // Right curry variants + // --------------------- + var curryRight = function (func) { + return curry.call(this, func, true); + }; + + var curryRight2 = function (fun) { + return enforcesUnary(function (last) { + return enforcesUnary(function (first) { + return fun.call(this, first, last); + }); + }); + }; + + var curryRight3 = function (fun) { + return enforcesUnary(function (last) { + return enforcesUnary(function (second) { + return enforcesUnary(function (first) { + return fun.call(this, first, second, last); + }); + }); + }); + }; + // Mixing in the arity functions // ----------------------------- @@ -650,9 +709,8 @@ curry: curry, // Flexible right to left curry with strict arity. - rCurry: function (func) { - return curry.call(this, func, true); - }, + curryRight: curryRight, + rCurry: curryRight, // alias for backwards compatibility curry2: function (fun) { @@ -673,24 +731,13 @@ }); }, - // reverse currying for functions taking two arguments. - rcurry2: function (fun) { - return enforcesUnary(function (last) { - return enforcesUnary(function (first) { - return fun.call(this, first, last); - }); - }); - }, + // reverse currying for functions taking two arguments. + curryRight2: curryRight2, + rcurry2: curryRight2, // alias for backwards compatibility + + curryRight3: curryRight3, + rcurry3: curryRight3, // alias for backwards compatibility - rcurry3: function (fun) { - return enforcesUnary(function (last) { - return enforcesUnary(function (second) { - return enforcesUnary(function (first) { - return fun.call(this, first, second, last); - }); - }); - }); - }, // Dynamic decorator to enforce function arity and defeat varargs. enforce: enforce }); @@ -717,19 +764,21 @@ }; })(); -})(this); +}).call(this); // Underscore-contrib (underscore.function.combinators.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -750,7 +799,22 @@ }; }; + var createPredicateApplicator = function (funcToInvoke /*, preds */) { + var preds = _(arguments).tail(); + + return function (objToCheck) { + var array = _(objToCheck).cat(); + + return _[funcToInvoke](array, function (e) { + return _[funcToInvoke](preds, function (p) { + return p(e); + }); + }); + }; + }; + // n.b. depends on underscore.function.arity.js + // n.b. depends on underscore.array.builders.js // Takes a target function and a mapping function. Returns a function // that applies the mapper to its arguments before evaluating the body. @@ -783,32 +847,12 @@ // Composes a bunch of predicates into a single predicate that // checks all elements of an array for conformance to all of the // original predicates. - conjoin: function(/* preds */) { - var preds = arguments; - - return function(array) { - return _.every(array, function(e) { - return _.every(preds, function(p) { - return p(e); - }); - }); - }; - }, + conjoin: _.partial(createPredicateApplicator, ('every')), // Composes a bunch of predicates into a single predicate that // checks all elements of an array for conformance to any of the // original predicates. - disjoin: function(/* preds */) { - var preds = arguments; - - return function(array) { - return _.some(array, function(e) { - return _.some(preds, function(p) { - return p(e); - }); - }); - }; - }, + disjoin: _.partial(createPredicateApplicator, 'some'), // Takes a predicate-like and returns a comparator (-1,0,1). comparator: function(fun) { @@ -984,19 +1028,21 @@ return _.bind(fn, obj); }; -})(this); +}).call(this); // Underscore-contrib (underscore.function.dispatch.js 0.3.0) // (c) 2013 Justin Ridgewell // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -1018,19 +1064,21 @@ } }); -})(this); +}).call(this); // Underscore-contrib (underscore.function.iterators.js 0.3.0) // (c) 2013 Michael Fogus and DocumentCloud Inc. // Underscore-contrib may be freely distributed under the MIT license. -(function(root, undefined) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -1238,6 +1286,14 @@ }; } + function cycle(array) { + var index = 0, + length = array.length; + return function() { + return array[index++ % length]; + }; + } + function Tree (array) { var index, myself, state; index = 0; @@ -1350,135 +1406,133 @@ constant: K, K: K, numbers: numbers, - range: range + range: range, + cycle: cycle }; -})(this, void 0); +}).call(this, void 0); // Underscore-contrib (underscore.function.predicates.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); - - // Helpers - // ------- - - - // Mixing in the predicate functions - // --------------------------------- - - _.mixin({ - // A wrapper around instanceof - isInstanceOf: function(x, t) { return (x instanceof t); }, - - // An associative object is one where its elements are - // accessed via a key or index. (i.e. array and object) - isAssociative: function(x) { return _.isArray(x) || _.isObject(x) || _.isArguments(x); }, - - // An indexed object is anything that allows numerical index for - // accessing its elements (e.g. arrays and strings). NOTE: Underscore - // does not support cross-browser consistent use of strings as array-like - // objects, so be wary in IE 8 when using String objects and IE<8. - // on string literals & objects. - isIndexed: function(x) { return _.isArray(x) || _.isString(x) || _.isArguments(x); }, - - // A seq is something considered a sequential composite type (i.e. arrays and `arguments`). - isSequential: function(x) { return (_.isArray(x)) || (_.isArguments(x)); }, - - // Check if an object is an object literal, since _.isObject(function() {}) === _.isObject([]) === true - isPlainObject: function(x) { return _.isObject(x) && x.constructor === root.Object; }, - - // These do what you think that they do - isZero: function(x) { return 0 === x; }, - isEven: function(x) { return _.isFinite(x) && (x & 1) === 0; }, - isOdd: function(x) { return _.isFinite(x) && !_.isEven(x); }, - isPositive: function(x) { return x > 0; }, - isNegative: function(x) { return x < 0; }, - isValidDate: function(x) { return _.isDate(x) && !_.isNaN(x.getTime()); }, - - // A numeric is a variable that contains a numeric value, regardless its type - // It can be a String containing a numeric value, exponential notation, or a Number object - // See here for more discussion: http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844 - isNumeric: function(n) { - return !isNaN(parseFloat(n)) && isFinite(n); - }, - - // An integer contains an optional minus sign to begin and only the digits 0-9 - // Objects that can be parsed that way are also considered ints, e.g. "123" - // Floats that are mathematically equal to integers are considered integers, e.g. 1.0 - // See here for more discussion: http://stackoverflow.com/questions/1019515/javascript-test-for-an-integer - isInteger: function(i) { - return _.isNumeric(i) && i % 1 === 0; - }, - - // A float is a numbr that is not an integer. - isFloat: function(n) { - return _.isNumeric(n) && !_.isInteger(n); - }, - - // checks if a string is a valid JSON - isJSON: function(str) { - try { - JSON.parse(str); - } catch (e) { +// Establish the root object, `window` in the browser, or `require` it on the server. +if (typeof exports === 'object') { + _ = module.exports = require('underscore'); +} + +// Helpers +// ------- + + +// Mixing in the predicate functions +// --------------------------------- + +_.mixin({ + // A wrapper around instanceof + isInstanceOf: function(x, t) { return (x instanceof t); }, + + // An associative object is one where its elements are + // accessed via a key or index. (i.e. array and object) + isAssociative: function(x) { return _.isArray(x) || _.isObject(x) || _.isArguments(x); }, + + // An indexed object is anything that allows numerical index for + // accessing its elements (e.g. arrays and strings). NOTE: Underscore + // does not support cross-browser consistent use of strings as array-like + // objects, so be wary in IE 8 when using String objects and IE<8. + // on string literals & objects. + isIndexed: function(x) { return _.isArray(x) || _.isString(x) || _.isArguments(x); }, + + // A seq is something considered a sequential composite type (i.e. arrays and `arguments`). + isSequential: function(x) { return (_.isArray(x)) || (_.isArguments(x)); }, + + // Check if an object is an object literal, since _.isObject(function() {}) === _.isObject([]) === true + isPlainObject: function(x) { return _.isObject(x) && x.constructor === Object; }, + + // These do what you think that they do + isZero: function(x) { return 0 === x; }, + isEven: function(x) { return _.isFinite(x) && (x & 1) === 0; }, + isOdd: function(x) { return _.isFinite(x) && !_.isEven(x); }, + isPositive: function(x) { return x > 0; }, + isNegative: function(x) { return x < 0; }, + isValidDate: function(x) { return _.isDate(x) && !_.isNaN(x.getTime()); }, + + // A numeric is a variable that contains a numeric value, regardless its type + // It can be a String containing a numeric value, exponential notation, or a Number object + // See here for more discussion: http://stackoverflow.com/questions/18082/validate-numbers-in-javascript-isnumeric/1830844#1830844 + isNumeric: function(n) { + return !isNaN(parseFloat(n)) && isFinite(n); + }, + + // An integer contains an optional minus sign to begin and only the digits 0-9 + // Objects that can be parsed that way are also considered ints, e.g. "123" + // Floats that are mathematically equal to integers are considered integers, e.g. 1.0 + // See here for more discussion: http://stackoverflow.com/questions/1019515/javascript-test-for-an-integer + isInteger: function(i) { + return _.isNumeric(i) && i % 1 === 0; + }, + + // A float is a numbr that is not an integer. + isFloat: function(n) { + return _.isNumeric(n) && !_.isInteger(n); + }, + + // checks if a string is a valid JSON + isJSON: function(str) { + try { + JSON.parse(str); + } catch (e) { + return false; + } + return true; + }, + + // Returns true if its arguments are monotonically + // increaing values; false otherwise. + isIncreasing: function() { + var count = _.size(arguments); + if (count === 1) return true; + if (count === 2) return arguments[0] < arguments[1]; + + for (var i = 1; i < count; i++) { + if (arguments[i-1] >= arguments[i]) { return false; } - return true; - }, - - // Returns true if its arguments are monotonically - // increaing values; false otherwise. - isIncreasing: function() { - var count = _.size(arguments); - if (count === 1) return true; - if (count === 2) return arguments[0] < arguments[1]; - - for (var i = 1; i < count; i++) { - if (arguments[i-1] >= arguments[i]) { - return false; - } - } + } - return true; - }, + return true; + }, - // Returns true if its arguments are monotonically - // decreaing values; false otherwise. - isDecreasing: function() { - var count = _.size(arguments); - if (count === 1) return true; - if (count === 2) return arguments[0] > arguments[1]; + // Returns true if its arguments are monotonically + // decreaing values; false otherwise. + isDecreasing: function() { + var count = _.size(arguments); + if (count === 1) return true; + if (count === 2) return arguments[0] > arguments[1]; - for (var i = 1; i < count; i++) { - if (arguments[i-1] <= arguments[i]) { - return false; - } + for (var i = 1; i < count; i++) { + if (arguments[i-1] <= arguments[i]) { + return false; } - - return true; } - }); -})(this); + return true; + } +}); // Underscore-contrib (underscore.object.builders.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -1587,19 +1641,21 @@ frequencies: curry2(_.countBy)(_.identity) }); -})(this); +}).call(this); // Underscore-contrib (underscore.object.selectors.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -1609,6 +1665,25 @@ var ArrayProto = Array.prototype; var slice = ArrayProto.slice; + // Will take a path like 'element[0][1].subElement["Hey!.What?"]["[hey]"]' + // and return ["element", "0", "1", "subElement", "Hey!.What?", "[hey]"] + function keysFromPath(path) { + // from http://codereview.stackexchange.com/a/63010/8176 + /** + * Repeatedly capture either: + * - a bracketed expression, discarding optional matching quotes inside, or + * - an unbracketed expression, delimited by a dot or a bracket. + */ + var re = /\[("|')(.+)\1\]|([^.\[\]]+)/g; + + var elements = []; + var result; + while ((result = re.exec(path)) !== null) { + elements.push(result[2] || result[3]); + } + return elements; + } + // Mixing in the object selectors // ------------------------------ @@ -1647,39 +1722,38 @@ // path described by the keys given. Keys may be given as an array // or as a dot-separated string. getPath: function getPath (obj, ks) { - if (typeof ks == "string") ks = ks.split("."); - - // If we have reached an undefined property - // then stop executing and return undefined - if (obj === undefined) return void 0; + ks = typeof ks == "string" ? keysFromPath(ks) : ks; - // If the path array has no more elements, we've reached - // the intended property and return its value - if (ks.length === 0) return obj; + var i = -1, length = ks.length; - // If we still have elements in the path array and the current - // value is null, stop executing and return undefined - if (obj === null) return void 0; - - return getPath(obj[_.first(ks)], _.rest(ks)); + // If the obj is null or undefined we have to break as + // a TypeError will result trying to access any property + // Otherwise keep incrementally access the next property in + // ks until complete + while (++i < length && obj != null) { + obj = obj[ks[i]]; + } + return i === length ? obj : void 0; }, // Returns a boolean indicating whether there is a property // at the path described by the keys given hasPath: function hasPath (obj, ks) { - if (typeof ks == "string") ks = ks.split("."); - - var numKeys = ks.length; - - if (obj == null && numKeys > 0) return false; - - if (!(ks[0] in obj)) return false; + ks = typeof ks == "string" ? keysFromPath(ks) : ks; - if (numKeys === 1) return true; - - return hasPath(obj[_.first(ks)], _.rest(ks)); + var i = -1, length = ks.length; + while (++i < length && _.isObject(obj)) { + if (ks[i] in obj) { + obj = obj[ks[i]]; + } else { + return false; + } + } + return i === length; }, + keysFromPath: keysFromPath, + pickWhen: function(obj, pred) { var copy = {}; @@ -1696,75 +1770,82 @@ }); -})(this); +}).call(this); // Underscore-contrib (underscore.util.existential.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); - - // Helpers - // ------- - +// Establish the root object, `window` in the browser, or `require` it on the server. +if (typeof exports === 'object') { + _ = module.exports = require('underscore'); +} - // Mixing in the truthiness - // ------------------------ - - _.mixin({ - exists: function(x) { return x != null; }, - truthy: function(x) { return (x !== false) && _.exists(x); }, - falsey: function(x) { return !_.truthy(x); }, - not: function(b) { return !b; }, - firstExisting: function() { - for (var i = 0; i < arguments.length; i++) { - if (arguments[i] != null) return arguments[i]; - } +// Mixing in the truthiness +// ------------------------ + +_.mixin({ + exists: function(x) { return x != null; }, + truthy: function(x) { return (x !== false) && _.exists(x); }, + falsey: function(x) { return !_.truthy(x); }, + not: function(b) { return !b; }, + firstExisting: function() { + for (var i = 0; i < arguments.length; i++) { + if (arguments[i] != null) return arguments[i]; } - }); - -})(this); + } +}); // Underscore-contrib (underscore.function.arity.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Setup for variadic operators // ---------------------------- // Turn a binary math operator into a variadic operator function variadicMath(operator) { - return function() { - return _.reduce(arguments, operator); - }; + return variaderize(function(numbersToOperateOn) { + return _.reduce(numbersToOperateOn, operator); + }); } // Turn a binary comparator into a variadic comparator function variadicComparator(comparator) { - return function() { + return variaderize(function(itemsToCompare) { var result; - for (var i = 0; i < arguments.length - 1; i++) { - result = comparator(arguments[i], arguments[i + 1]); + + for (var i = 0; i < itemsToCompare.length - 1; i++) { + result = comparator(itemsToCompare[i], itemsToCompare[i + 1]); if (result === false) return result; } - return result; + + return result; + }); + } + + // Converts a unary function that operates on an array into one that also works with a variable number of arguments + function variaderize(func) { + return function (args) { + var allArgs = isArrayLike(args) ? args : arguments; + return func(allArgs); }; } + function isArrayLike(obj) { + return obj != null && typeof obj.length === "number"; + } + // Turn a boolean-returning function into one with the opposite meaning function invert(fn) { return function() { @@ -1894,19 +1975,21 @@ bitwiseRight: variadicMath(bitwiseRight), bitwiseZ: variadicMath(bitwiseZ) }); -})(this); +}).call(this); // Underscore-contrib (underscore.util.strings.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { +(function() { // Baseline setup // -------------- - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); + // Establish the root object, `window` in the browser, or `require` it on the server. + if (typeof exports === 'object') { + _ = module.exports = require('underscore'); + } // Helpers // ------- @@ -2001,15 +2084,21 @@ }, // Converts a string to camel case - camelCase : function( string ){ - return string.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); + camelCase : function( string, separator ){ + separator = separator || '-'; + if (typeof separator != 'string') throw new TypeError('Separator must be a string.'); + if (separator.length != 1) throw new Error('Separator must be one character.'); + return string.replace(new RegExp(separator+'([a-z])', 'g'), function (g) { return g[1].toUpperCase(); }); }, // Converts camel case to dashed (opposite of _.camelCase) - toDash : function( string ){ - string = string.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();}); + toDash : function( string, separator ){ + separator = separator || '-'; + if (typeof separator != 'string') throw new TypeError('Separator must be a string.'); + if (separator.length != 1) throw new Error('Separator must be one character.'); + string = string.replace(/([A-Z])/g, function($1){return separator+$1.toLowerCase();}); // remove first dash - return ( string.charAt( 0 ) == '-' ) ? string.substr(1) : string; + return ( string.charAt( 0 ) == separator ) ? string.substr(1) : string; }, // Creates a query string from a hash @@ -2024,44 +2113,35 @@ } }); -})(this); +}).call(this); // Underscore-contrib (underscore.util.trampolines.js 0.3.0) // (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // Underscore-contrib may be freely distributed under the MIT license. -(function(root) { - - // Baseline setup - // -------------- - - // Establish the root object, `window` in the browser, or `global` on the server. - var _ = root._ || require('underscore'); - - // Helpers - // ------- - - - // Mixing in the truthiness - // ------------------------ +// Establish the root object, `window` in the browser, or `require` it on the server. +if (typeof exports === 'object') { + _ = module.exports = require('underscore'); +} - _.mixin({ - done: function(value) { - var ret = _(value); - ret.stopTrampoline = true; - return ret; - }, +// Mixing in the truthiness +// ------------------------ - trampoline: function(fun /*, args */) { - var result = fun.apply(fun, _.rest(arguments)); +_.mixin({ + done: function(value) { + var ret = _(value); + ret.stopTrampoline = true; + return ret; + }, - while (_.isFunction(result)) { - result = result(); - if ((result instanceof _) && (result.stopTrampoline)) break; - } + trampoline: function(fun /*, args */) { + var result = fun.apply(fun, _.rest(arguments)); - return result.value(); + while (_.isFunction(result)) { + result = result(); + if ((result instanceof _) && (result.stopTrampoline)) break; } - }); -})(this); + return result.value(); + } +}); diff --git a/dist/underscore-contrib.min.js b/dist/underscore-contrib.min.js index e8be493..d91c79a 100644 --- a/dist/underscore-contrib.min.js +++ b/dist/underscore-contrib.min.js @@ -5,4 +5,4 @@ // > (c) 2013 Michael Fogus, DocumentCloud and Investigative Reporters & Editors // > underscore-contrib may be freely distributed under the MIT license. -(function(n){var r=n._||require("underscore"),t=Array.prototype.slice,e=Array.prototype.concat,u=function(n){return null!=n};r.mixin({cat:function(){return r.reduce(arguments,function(n,u){return r.isArguments(u)?e.call(n,t.call(u)):e.call(n,u)},[])},cons:function(n,t){return r.cat([n],t)},chunk:function(n,t,e){var u=function(n){if(null==n)return[];var i=r.take(n,t);return t===r.size(i)?r.cons(i,u(r.drop(n,t))):e?[r.take(r.cat(i,e),t)]:[]};return u(n)},chunkAll:function(n,t,e){e=null!=e?e:t;var u=function(n,t,e){return r.isEmpty(n)?[]:r.cons(r.take(n,t),u(r.drop(n,e),t,e))};return u(n,t,e)},mapcat:function(n,t){return r.cat.apply(null,r.map(n,t))},interpose:function(n,e){if(!r.isArray(n))throw new TypeError;var u=r.size(n);return 0===u?n:1===u?n:t.call(r.mapcat(n,function(n){return r.cons(n,[e])}),0,-1)},weave:function(){return r.some(arguments)?1==arguments.length?arguments[0]:r.filter(r.flatten(r.zip.apply(null,arguments),!0),function(n){return null!=n}):[]},interleave:r.weave,repeat:function(n,t){return r.times(n,function(){return t})},cycle:function(n,t){return r.flatten(r.times(n,function(){return t}),!0)},splitAt:function(n,t){return[r.take(n,t),r.drop(n,t)]},iterateUntil:function(n,r,t){for(var e=[],u=n(t);r(u);)e.push(u),u=n(u);return e},takeSkipping:function(n,t){var e=[],u=r.size(n);if(0>=t)return[];if(1===t)return n;for(var i=0;u>i;i+=t)e.push(n[i]);return e},reductions:function(n,t,e){var u=[],i=e;return r.each(n,function(r,e){i=t(i,n[e]),u.push(i)}),u},keepIndexed:function(n,t){return r.filter(r.map(r.range(r.size(n)),function(r){return t(r,n[r])}),u)},reverseOrder:function(n){if("string"==typeof n)throw new TypeError("Strings cannot be reversed by _.reverseOrder");return t.call(n).reverse()}})})(this),function(n){var r=n._||require("underscore"),t=Array.prototype.slice,e=Array.prototype.concat,u=function(n){return null!=n},i=function(n){return n!==!1&&u(n)},o=function(n){return r.isArray(n)||r.isArguments(n)};r.mixin({second:function(n,r,e){return null==n?void 0:null==r||e?n[1]:t.call(n,1,r)},third:function(n,r,e){return null==n?void 0:null==r||e?n[2]:t.call(n,2,r)},nth:function(n,r,t){return null==r||t?void 0:n[r]},takeWhile:function(n,t){if(!o(n))throw new TypeError;for(var e=r.size(n),u=0;e>u&&i(t(n[u]));u++);return r.take(n,u)},dropWhile:function(n,t){if(!o(n))throw new TypeError;for(var e=r.size(n),u=0;e>u&&i(t(n[u]));u++);return r.drop(n,u)},splitWith:function(n,t){return[r.takeWhile(n,t),r.dropWhile(n,t)]},partitionBy:function(n,t){if(r.isEmpty(n)||!u(n))return[];var i=r.first(n),o=t(i),c=e.call([i],r.takeWhile(r.rest(n),function(n){return r.isEqual(o,t(n))}));return e.call([c],r.partitionBy(r.drop(n,r.size(c)),t))},best:function(n,t){return r.reduce(n,function(n,r){return t(n,r)?n:r})},keep:function(n,t){if(!o(n))throw new TypeError("expected an array as the first argument");return r.filter(r.map(n,function(n){return t(n)}),u)}})}(this),function(n){function r(n){return u.isElement(n)?n.children:n}function t(n,r,t,e,a,f){var l=[];return function s(n,p,m){if(u.isObject(n)){if(l.indexOf(n)>=0)throw new TypeError(c);l.push(n)}if(t){var v=t.call(a,n,p,m);if(v===o)return o;if(v===i)return}var h,g=r(n);if(u.isObject(g)&&!u.isEmpty(g)){f&&(h=u.isArray(n)?[]:{});var y=u.any(g,function(r,t){var e=s(r,t,n);return e===o?!0:(h&&(h[t]=e),void 0)});if(y)return o}return e?e.call(a,n,p,m,h):void 0}(n)}function e(n,r,t){var e=[];return this.preorder(n,function(n,o){return t||o!=r?(u.has(n,r)&&(e[e.length]=n[r]),void 0):i}),e}var u=n._||require("underscore"),i={},o={},c="Not a tree: same object found in two different branches",a={find:function(n,r,t){var e;return this.preorder(n,function(n,u,i){return r.call(t,n,u,i)?(e=n,o):void 0},t),e},filter:function(n,r,t,e){var u=[];return null==n?u:(r(n,function(n,r,i){t.call(e,n,r,i)&&u.push(n)},null,this._traversalStrategy),u)},reject:function(n,r,t,e){return this.filter(n,r,function(n,r,u){return!t.call(e,n,r,u)})},map:function(n,r,t,e){var u=[];return r(n,function(n,r,i){u[u.length]=t.call(e,n,r,i)},null,this._traversalStrategy),u},pluck:function(n,r){return e.call(this,n,r,!1)},pluckRec:function(n,r){return e.call(this,n,r,!0)},postorder:function(n,r,e,u){u=u||this._traversalStrategy,t(n,u,null,r,e)},preorder:function(n,r,e,u){u=u||this._traversalStrategy,t(n,u,r,null,e)},reduce:function(n,r,e,u){var i=function(n,t,u,i){return r(i||e,n,t,u)};return t(n,this._traversalStrategy,null,i,u,!0)}};a.collect=a.map,a.detect=a.find,a.select=a.filter,u.walk=function(n){var t=u.clone(a);return u.bindAll.apply(null,[t].concat(u.keys(t))),t._traversalStrategy=n||r,t},u.extend(u.walk,u.walk())}(this),function(n){function r(n){return function(){if(1===arguments.length)return n.apply(this,arguments);throw new RangeError("Only a single argument may be accepted.")}}var t=n._||require("underscore"),e=function(){function n(t,e,u,i,o,c){return c===!0?i.unshift(o):i.push(o),i.length==u?t.apply(e,i):r(function(){return n(t,e,u,i.slice(0),arguments[0],c)})}return function(t,e){var u=this;return r(function(){return n(t,u,t.length,[],arguments[0],e)})}}(),u=function(){var n=[];return function(r){if("function"!=typeof r)throw Error("Argument 1 must be a function.");var t=r.length;return void 0===n[t]&&(n[t]=function(n){return function(){if(arguments.length!==t)throw new RangeError(t+" arguments must be applied.");return n.apply(this,arguments)}}),n[t](r)}}();t.mixin({fix:function(n){var r=t.rest(arguments),e=function(){for(var e=r.slice(),u=0,i=0;(e.length||arguments.length>u)>i;i++)e[i]===t&&(e[i]=arguments[u++]);return n.apply(null,e)};return e._original=n,e},unary:function(n){return function(r){return n.call(this,r)}},binary:function(n){return function(r,t){return n.call(this,r,t)}},ternary:function(n){return function(r,t,e){return n.call(this,r,t,e)}},quaternary:function(n){return function(r,t,e,u){return n.call(this,r,t,e,u)}},curry:e,rCurry:function(n){return e.call(this,n,!0)},curry2:function(n){return r(function(t){return r(function(r){return n.call(this,t,r)})})},curry3:function(n){return r(function(t){return r(function(e){return r(function(r){return n.call(this,t,e,r)})})})},rcurry2:function(n){return r(function(t){return r(function(r){return n.call(this,r,t)})})},rcurry3:function(n){return r(function(t){return r(function(e){return r(function(r){return n.call(this,r,e,t)})})})},enforce:u}),t.arity=function(){var n={};return function r(t,e){if(null==n[t]){for(var u=Array(t),i=0;t>i;++i)u[i]="__"+i;var o=u.join(),c="return function ("+o+") { return fun.apply(this, arguments); };";n[t]=Function(["fun"],c)}return null==e?function(n){return r(t,n)}:n[t](e)}}()}(this),function(n){function r(n,r){return t.arity(n.length,function(){return n.apply(this,c.call(arguments,r))})}var t=n._||require("underscore"),e=function(n){return null!=n},u=function(n){return n!==!1&&e(n)},i=[].reverse,o=[].slice,c=[].map,a=function(n){return function(r,t){return 1===arguments.length?function(t){return n(r,t)}:n(r,t)}};t.mixin({always:t.constant,pipeline:function(){var n=t.isArray(arguments[0])?arguments[0]:arguments;return function(r){return t.reduce(n,function(n,r){return r(n)},r)}},conjoin:function(){var n=arguments;return function(r){return t.every(r,function(r){return t.every(n,function(n){return n(r)})})}},disjoin:function(){var n=arguments;return function(r){return t.some(r,function(r){return t.some(n,function(n){return n(r)})})}},comparator:function(n){return function(r,t){return u(n(r,t))?-1:u(n(t,r))?1:0}},complement:function(n){return function(){return!n.apply(this,arguments)}},splat:function(n){return function(r){return n.apply(this,r)}},unsplat:function(n){var r=n.length;return 1>r?n:1===r?function(){return n.call(this,o.call(arguments,0))}:function(){var t=arguments.length,e=o.call(arguments,0,r-1),u=Math.max(r-t-1,0),i=Array(u),c=o.call(arguments,n.length-1);return n.apply(this,e.concat(i).concat([c]))}},unsplatl:function(n){var r=n.length;return 1>r?n:1===r?function(){return n.call(this,o.call(arguments,0))}:function(){var t=arguments.length,e=o.call(arguments,Math.max(t-r+1,0)),u=o.call(arguments,0,Math.max(t-r+1,0));return n.apply(this,[u].concat(e))}},mapArgs:a(r),juxt:function(){var n=arguments;return function(){var r=arguments;return t.map(n,function(n){return n.apply(this,r)},this)}},fnull:function(n){var r=t.rest(arguments);return function(){for(var u=t.toArray(arguments),i=t.size(r),o=0;i>o;o++)e(u[o])||(u[o]=r[o]);return n.apply(this,u)}},flip2:function(n){return function(){var r=o.call(arguments);return r[0]=arguments[1],r[1]=arguments[0],n.apply(this,r)}},flip:function(n){return function(){var r=i.call(arguments);return n.apply(this,r)}},functionalize:function(n){return function(r){return n.apply(r,t.rest(arguments))}},methodize:function(n){return function(){return n.apply(null,t.cons(this,arguments))}},k:t.always,t:t.pipeline}),t.unsplatr=t.unsplat,t.mapArgsWith=a(t.flip(r)),t.bound=function(n,r){var e=n[r];if(!t.isFunction(e))throw new TypeError("Expected property to be a function");return t.bind(e,n)}}(this),function(n){var r=n._||require("underscore"),t=Array.prototype.slice;r.mixin({attempt:function(n,e){if(null==n)return void 0;var u=n[e],i=t.call(arguments,2);return r.isFunction(u)?u.apply(n,i):void 0}})}(this),function(n){function r(n){return function(r){return n.call(this,r)}}function t(n,r,t){var e,u;for(e=t!==void 0?t:n(),u=n();null!=u;)e=r.call(u,e,u),u=n();return e}function e(n,r){var t=x;return function(){return t===x?t=n:null!=t&&(t=r.call(t,t)),t}}function u(n,r){var t,e,u=n;return function(){return null!=u?(t=r.call(u,u),e=t[1],u=null!=e?t[0]:void 0,e):void 0}}function i(n,r,t){var e=t;return function(){var t=n();return null==t?t:e=e===void 0?t:r.call(t,e,t)}}function o(n,r,t){var e,u,i=t;return function(){return u=n(),null==u?u:i===void 0?i=u:(e=r.call(u,i,u),i=e[0],e[1])}}function c(n,r){return function(){var t;return t=n(),null!=t?r.call(t,t):void 0}}function a(n,r){var t=null;return function(){var e,u;if(null==t){if(u=n(),null==u)return t=null,void 0;t=r.call(u,u)}for(;null==e;)if(e=t(),null==e){if(u=n(),null==u)return t=null,void 0;t=r.call(u,u)}return e}}function f(n,r){return function(){var t;for(t=n();null!=t;){if(r.call(t,t))return t;t=n()}return void 0}}function l(n,r){return f(n,function(n){return!r(n)})}function s(n,r){return f(n,r)()}function p(n,r,t){for(var e=0;r-->0;)n();return null!=t?function(){return t>=++e?n():void 0}:n}function m(n,r){return p(n,null==r?1:r)}function v(n,r){return p(n,0,null==r?1:r)}function h(n){var r=0;return function(){return n[r++]}}function g(n){var r,t,e;return r=0,e=[],t=function(){var u,i;return u=n[r++],u instanceof Array?(e.push({array:n,index:r}),n=u,r=0,t()):u===void 0?e.length>0?(i=e.pop(),n=i.array,r=i.index,t()):void 0:u}}function y(n){return function(){return n}}function d(n,r,t){return function(){var e;return n>r?void 0:(e=n,n+=t,e)}}function w(n,r,t){return function(){var e;return r>n?void 0:(e=n,n-=t,e)}}function A(n,r,t){return null==n?d(1,1/0,1):null==r?d(n,1/0,1):null==t?r>=n?d(n,r,1):w(n,r,1):t>0?d(n,r,t):0>t?w(n,r,Math.abs(t)):k(n)}var b=n._||require("underscore"),x={},_=r(A);b.iterators={accumulate:i,accumulateWithReturn:o,foldl:t,reduce:t,unfold:e,unfoldWithReturn:u,map:c,mapcat:a,select:f,reject:l,filter:f,find:s,slice:p,drop:m,take:v,List:h,Tree:g,constant:y,K:y,numbers:_,range:A}}(this,void 0),function(n){var r=n._||require("underscore");r.mixin({isInstanceOf:function(n,r){return n instanceof r},isAssociative:function(n){return r.isArray(n)||r.isObject(n)||r.isArguments(n)},isIndexed:function(n){return r.isArray(n)||r.isString(n)||r.isArguments(n)},isSequential:function(n){return r.isArray(n)||r.isArguments(n)},isPlainObject:function(t){return r.isObject(t)&&t.constructor===n.Object},isZero:function(n){return 0===n},isEven:function(n){return r.isFinite(n)&&0===(1&n)},isOdd:function(n){return r.isFinite(n)&&!r.isEven(n)},isPositive:function(n){return n>0},isNegative:function(n){return 0>n},isValidDate:function(n){return r.isDate(n)&&!r.isNaN(n.getTime())},isNumeric:function(n){return!isNaN(parseFloat(n))&&isFinite(n)},isInteger:function(n){return r.isNumeric(n)&&0===n%1},isFloat:function(n){return r.isNumeric(n)&&!r.isInteger(n)},isJSON:function(n){try{JSON.parse(n)}catch(r){return!1}return!0},isIncreasing:function(){var n=r.size(arguments);if(1===n)return!0;if(2===n)return arguments[0]t;t++)if(arguments[t-1]>=arguments[t])return!1;return!0},isDecreasing:function(){var n=r.size(arguments);if(1===n)return!0;if(2===n)return arguments[0]>arguments[1];for(var t=1;n>t;t++)if(arguments[t-1]<=arguments[t])return!1;return!0}})}(this),function(n){var r=n._||require("underscore"),t=(Array.prototype.slice,Array.prototype.concat),e=function(n){return null!=n},u=function(n){return n!==!1&&e(n)},i=function(n){return r.isArray(n)||r.isObject(n)},o=function(n){return function(r){return function(t){return n(t,r)}}};r.mixin({merge:function(){var n=r.some(arguments)?{}:null;return u(n)&&r.extend.apply(null,t.call([n],r.toArray(arguments))),n},renameKeys:function(n,u){return r.reduce(u,function(r,t,u){return e(n[u])?(r[t]=n[u],r):r},r.omit.apply(null,t.call([n],r.keys(u))))},snapshot:function(n){if(null==n||"object"!=typeof n)return n;var t=new n.constructor;for(var e in n)n.hasOwnProperty(e)&&(t[e]=r.snapshot(n[e]));return t},updatePath:function(n,t,u,o){if(!i(n))throw new TypeError("Attempted to update a non-associative object.");if(!e(u))return t(n);var c=r.isArray(u),a=c?u:[u],f=c?r.snapshot(n):r.clone(n),l=r.last(a),s=f;return r.each(r.initial(a),function(n){o&&!r.has(s,n)&&(s[n]=r.clone(o)),s=s[n]}),s[l]=t(s[l]),f},setPath:function(n,t,u,i){if(!e(u))throw new TypeError("Attempted to set a property at a null path.");return r.updatePath(n,function(){return t},u,i)},frequencies:o(r.countBy)(r.identity)})}(this),function(n){var r=n._||require("underscore"),t=Array.prototype.concat,e=Array.prototype;e.slice,r.mixin({accessor:function(n){return function(r){return r&&r[n]}},dictionary:function(n){return function(r){return n&&r&&n[r]}},selectKeys:function(n,e){return r.pick.apply(null,t.call([n],e))},kv:function(n,t){return r.has(n,t)?[t,n[t]]:void 0},getPath:function u(n,t){return"string"==typeof t&&(t=t.split(".")),void 0===n?void 0:0===t.length?n:null===n?void 0:u(n[r.first(t)],r.rest(t))},hasPath:function i(n,t){"string"==typeof t&&(t=t.split("."));var e=t.length;return null==n&&e>0?!1:t[0]in n?1===e?!0:i(n[r.first(t)],r.rest(t)):!1},pickWhen:function(n,t){var e={};return r.each(n,function(r,u){t(n[u])&&(e[u]=n[u])}),e},omitWhen:function(n,t){return r.pickWhen(n,function(n){return!t(n)})}})}(this),function(n){var r=n._||require("underscore");r.mixin({exists:function(n){return null!=n},truthy:function(n){return n!==!1&&r.exists(n)},falsey:function(n){return!r.truthy(n)},not:function(n){return!n},firstExisting:function(){for(var n=0;arguments.length>n;n++)if(null!=arguments[n])return arguments[n]}})}(this),function(n){function r(n){return function(){return E.reduce(arguments,n)}}function t(n){return function(){for(var r,t=0;arguments.length-1>t;t++)if(r=n(arguments[t],arguments[t+1]),r===!1)return r;return r}}function e(n){return function(){return!n.apply(this,arguments)}}function u(n,r){return n+r}function i(n,r){return n-r}function o(n,r){return n*r}function c(n,r){return n/r}function a(n,r){return n%r}function f(n){return++n}function l(n){return--n}function s(n){return-n}function p(n,r){return n&r}function m(n,r){return n|r}function v(n,r){return n^r}function h(n,r){return n<>r}function y(n,r){return n>>>r}function d(n){return~n}function w(n,r){return n==r}function A(n,r){return n===r}function b(n){return!n}function x(n,r){return n>r}function k(n,r){return r>n}function _(n,r){return n>=r}function q(n,r){return r>=n}var E=n._||require("underscore");E.mixin({add:r(u),sub:r(i),mul:r(o),div:r(c),mod:a,inc:f,dec:l,neg:s,eq:t(w),seq:t(A),neq:e(t(w)),sneq:e(t(A)),not:b,gt:t(x),lt:t(k),gte:t(_),lte:t(q),bitwiseAnd:r(p),bitwiseOr:r(m),bitwiseXor:r(v),bitwiseNot:d,bitwiseLeft:r(h),bitwiseRight:r(g),bitwiseZ:r(y)})}(this),function(n){var r=n._||require("underscore"),t=/\+/g,e=/\%20/g,u=/(?:([^\[]+))|(?:\[(.*?)\])/g,i=function(n){return decodeURIComponent(n.replace(t,"%20"))},o=function(n){return encodeURIComponent(n).replace(e,"+")},c=function(n,t,e){return r.isUndefined(e)&&(e=!0),r.isArray(t)?r.map(t,function(r,t){return c(e?t:n+"[]",r,!1)}).join("&"):r.isObject(t)?r.map(t,function(r,t){return c(e?t:n+"["+t+"]",r,!1)}).join("&"):o(n)+"="+o(t)};r.mixin({explode:function(n){return n.split("")},fromQuery:function(n){var t,e,o,c,a,f=n.split("&"),l={};return r.each(f,function(n){for(n=n.split("="),t=i(n[0]),o=t,a=l,u.lastIndex=0;null!==(e=u.exec(t));)r.isUndefined(e[1])?(c=e[2],a[o]=a[o]||(c?{}:[]),a=a[o]):c=e[1],o=c||r.size(a);a[o]=i(n[1])}),l},implode:function(n){return n.join("")},camelCase:function(n){return n.replace(/-([a-z])/g,function(n){return n[1].toUpperCase()})},toDash:function(n){return n=n.replace(/([A-Z])/g,function(n){return"-"+n.toLowerCase()}),"-"==n.charAt(0)?n.substr(1):n},toQuery:function(n){return c("",n)},strContains:function(n,r){if("string"!=typeof n)throw new TypeError;return-1!=n.indexOf(r)}})}(this),function(n){var r=n._||require("underscore");r.mixin({done:function(n){var t=r(n);return t.stopTrampoline=!0,t},trampoline:function(n){for(var t=n.apply(n,r.rest(arguments));r.isFunction(t)&&(t=t(),!(t instanceof r&&t.stopTrampoline)););return t.value()}})}(this); \ No newline at end of file +(function(){"object"==typeof exports&&(_=module.exports=require("underscore"));var n=Array.prototype.slice,r=function(n){return null!=n};_.mixin({cat:function(){return _.flatten(arguments,!0)},cons:function(n,r){return _.cat([n],r)},chunk:function(n,r,t){var e=function(n){if(null==n)return[];var u=_.take(n,r);return r===_.size(u)?_.cons(u,e(_.drop(n,r))):t?[_.take(_.cat(u,t),r)]:[]};return e(n)},chunkAll:function(n,r,t){t=null!=t?t:r;var e=function(n,r,t){return _.isEmpty(n)?[]:_.cons(_.take(n,r),e(_.drop(n,t),r,t))};return e(n,r,t)},mapcat:function(n,r){return _.flatten(_.map(n,r),!0)},interpose:function(r,t){if(!_.isArray(r))throw new TypeError;var e=_.size(r);return 0===e?r:1===e?r:n.call(_.mapcat(r,function(n){return _.cons(n,[t])}),0,-1)},weave:function(){return _.some(arguments)?1==arguments.length?arguments[0]:_.filter(_.flatten(_.zip.apply(null,arguments),!0),function(n){return null!=n}):[]},interleave:_.weave,repeat:function(n,r){return _.times(n,function(){return r})},cycle:function(n,r){return _.flatten(_.times(n,function(){return r}),!0)},splitAt:function(n,r){return[_.take(n,r),_.drop(n,r)]},iterateUntil:function(n,r,t){for(var e=[],u=n(t);r(u);)e.push(u),u=n(u);return e},takeSkipping:function(n,r){var t=[],e=_.size(n);if(0>=r)return[];if(1===r)return n;for(var u=0;e>u;u+=r)t.push(n[u]);return t},reductions:function(n,r,t){var e=[],u=t;return _.each(n,function(t,i){u=r(u,n[i]),e.push(u)}),e},keepIndexed:function(n,t){return _.filter(_.map(_.range(_.size(n)),function(r){return t(r,n[r])}),r)},reverseOrder:function(r){if("string"==typeof r)throw new TypeError("Strings cannot be reversed by _.reverseOrder");return n.call(r).reverse()},combinations:function(){return _.reduce(n.call(arguments,1),function(n,r){return _.reduce(n,function(n,t){return n.concat(_.map(r,function(n){return t.concat([n])}))},[])},_.map(arguments[0],function(n){return[n]}))}})}).call(this),function(){"object"==typeof exports&&(_=module.exports=require("underscore"));var n=Array.prototype.slice,r=Array.prototype.concat,t=function(n){return null!=n},e=function(n){return n!==!1&&t(n)},u=function(n){return _.isArray(n)||_.isArguments(n)};_.mixin({second:function(r,t,e){return null==r?void 0:null==t||e?r[1]:n.call(r,1,t)},third:function(r,t,e){return null==r?void 0:null==t||e?r[2]:n.call(r,2,t)},nth:function(n,r,t){return null==r||t?void 0:n[r]},nths:nths=function(r,t){return null==r?void 0:u(t)?_(t).map(function(n){return r[n]}):nths(r,n.call(arguments,1))},valuesAt:nths,binPick:function i(r,t){return null==r?void 0:u(t)?_.nths(r,_.range(t.length).filter(function(n){return t[n]})):i(r,n.call(arguments,1))},takeWhile:function(n,r){if(!u(n))throw new TypeError;for(var t=_.size(n),i=0;t>i&&e(r(n[i]));i++);return _.take(n,i)},dropWhile:function(n,r){if(!u(n))throw new TypeError;for(var t=_.size(n),i=0;t>i&&e(r(n[i]));i++);return _.drop(n,i)},splitWith:function(n,r){return[_.takeWhile(n,r),_.dropWhile(n,r)]},partitionBy:function(n,e){if(_.isEmpty(n)||!t(n))return[];var u=_.first(n),i=e(u),o=r.call([u],_.takeWhile(_.rest(n),function(n){return _.isEqual(i,e(n))}));return r.call([o],_.partitionBy(_.drop(n,_.size(o)),e))},best:function(n,r){return _.reduce(n,function(n,t){return r(n,t)?n:t})},keep:function(n,r){if(!u(n))throw new TypeError("expected an array as the first argument");return _.filter(_.map(n,function(n){return r(n)}),t)}})}.call(this),function(){function n(n){return _.isElement(n)?n.children:n}function r(n,r,t,o,c,a){var f=[];return function l(n,s,p){if(_.isObject(n)){if(f.indexOf(n)>=0)throw new TypeError(i);f.push(n)}if(t){var m=t.call(c,n,s,p);if(m===u)return u;if(m===e)return}var h,g=r(n);if(_.isObject(g)&&!_.isEmpty(g)){a&&(h=_.isArray(n)?[]:{});var y=_.any(g,function(r,t){var e=l(r,t,n);return e===u?!0:(h&&(h[t]=e),void 0)});if(y)return u}return o?o.call(c,n,s,p,h):void 0}(n)}function t(n,r,t){var u=[];return this.preorder(n,function(n,i){return t||i!=r?(_.has(n,r)&&(u[u.length]=n[r]),void 0):e}),u}"object"==typeof o&&(_=module.exports=require("underscore"));var e={},u={},i="Not a tree: same object found in two different branches",o={find:function(n,r,t){var e;return this.preorder(n,function(n,i,o){return r.call(t,n,i,o)?(e=n,u):void 0},t),e},filter:function(n,r,t,e){var u=[];return null==n?u:(r(n,function(n,r,i){t.call(e,n,r,i)&&u.push(n)},null,this._traversalStrategy),u)},reject:function(n,r,t,e){return this.filter(n,r,function(n,r,u){return!t.call(e,n,r,u)})},map:function(n,r,t,e){var u=[];return r(n,function(n,r,i){u[u.length]=t.call(e,n,r,i)},null,this._traversalStrategy),u},pluck:function(n,r){return t.call(this,n,r,!1)},pluckRec:function(n,r){return t.call(this,n,r,!0)},postorder:function(n,t,e,u){u=u||this._traversalStrategy,r(n,u,null,t,e)},preorder:function(n,t,e,u){u=u||this._traversalStrategy,r(n,u,t,null,e)},reduce:function(n,t,e,u){var i=function(n,r,u,i){return t(i||e,n,r,u)};return r(n,this._traversalStrategy,null,i,u,!0)}};o.collect=o.map,o.detect=o.find,o.select=o.filter,_.walk=function(r){var t=_.clone(o);return _.bindAll.apply(null,[t].concat(_.keys(t))),t._traversalStrategy=r||n,t},_.extend(_.walk,_.walk())}.call(this),function(){function n(n){return function(){if(1===arguments.length)return n.apply(this,arguments);throw new RangeError("Only a single argument may be accepted.")}}"object"==typeof exports&&(_=module.exports=require("underscore"));var r=function(){function r(t,e,u,i,o,c){return c===!0?i.unshift(o):i.push(o),i.length==u?t.apply(e,i):n(function(){return r(t,e,u,i.slice(0),arguments[0],c)})}return function(t,e){var u=this;return n(function(){return r(t,u,t.length,[],arguments[0],e)})}}(),t=function(){var n=[];return function(r){if("function"!=typeof r)throw Error("Argument 1 must be a function.");var t=r.length;return void 0===n[t]&&(n[t]=function(n){return function(){if(arguments.length!==t)throw new RangeError(t+" arguments must be applied.");return n.apply(this,arguments)}}),n[t](r)}}(),e=function(n){return r.call(this,n,!0)},u=function(r){return n(function(t){return n(function(n){return r.call(this,n,t)})})},i=function(r){return n(function(t){return n(function(e){return n(function(n){return r.call(this,n,e,t)})})})};_.mixin({fix:function(n){var r=_.rest(arguments),t=function(){for(var t=r.slice(),e=0,u=0;(t.length||arguments.length>e)>u;u++)t[u]===_&&(t[u]=arguments[e++]);return n.apply(null,t)};return t._original=n,t},unary:function(n){return function(r){return n.call(this,r)}},binary:function(n){return function(r,t){return n.call(this,r,t)}},ternary:function(n){return function(r,t,e){return n.call(this,r,t,e)}},quaternary:function(n){return function(r,t,e,u){return n.call(this,r,t,e,u)}},curry:r,curryRight:e,rCurry:e,curry2:function(r){return n(function(t){return n(function(n){return r.call(this,t,n)})})},curry3:function(r){return n(function(t){return n(function(e){return n(function(n){return r.call(this,t,e,n)})})})},curryRight2:u,rcurry2:u,curryRight3:i,rcurry3:i,enforce:t}),_.arity=function(){var n={};return function r(t,e){if(null==n[t]){for(var u=Array(t),i=0;t>i;++i)u[i]="__"+i;var o=u.join(),c="return function ("+o+") { return fun.apply(this, arguments); };";n[t]=Function(["fun"],c)}return null==e?function(n){return r(t,n)}:n[t](e)}}()}.call(this),function(){function n(n,r){return _.arity(n.length,function(){return n.apply(this,i.call(arguments,r))})}"object"==typeof exports&&(_=module.exports=require("underscore"));var r=function(n){return null!=n},t=function(n){return n!==!1&&r(n)},e=[].reverse,u=[].slice,i=[].map,o=function(n){return function(r,t){return 1===arguments.length?function(t){return n(r,t)}:n(r,t)}},c=function(n){var r=_(arguments).tail();return function(t){var e=_(t).cat();return _[n](e,function(t){return _[n](r,function(n){return n(t)})})}};_.mixin({always:_.constant,pipeline:function(){var n=_.isArray(arguments[0])?arguments[0]:arguments;return function(r){return _.reduce(n,function(n,r){return r(n)},r)}},conjoin:_.partial(c,"every"),disjoin:_.partial(c,"some"),comparator:function(n){return function(r,e){return t(n(r,e))?-1:t(n(e,r))?1:0}},complement:function(n){return function(){return!n.apply(this,arguments)}},splat:function(n){return function(r){return n.apply(this,r)}},unsplat:function(n){var r=n.length;return 1>r?n:1===r?function(){return n.call(this,u.call(arguments,0))}:function(){var t=arguments.length,e=u.call(arguments,0,r-1),i=Math.max(r-t-1,0),o=Array(i),c=u.call(arguments,n.length-1);return n.apply(this,e.concat(o).concat([c]))}},unsplatl:function(n){var r=n.length;return 1>r?n:1===r?function(){return n.call(this,u.call(arguments,0))}:function(){var t=arguments.length,e=u.call(arguments,Math.max(t-r+1,0)),i=u.call(arguments,0,Math.max(t-r+1,0));return n.apply(this,[i].concat(e))}},mapArgs:o(n),juxt:function(){var n=arguments;return function(){var r=arguments;return _.map(n,function(n){return n.apply(this,r)},this)}},fnull:function(n){var t=_.rest(arguments);return function(){for(var e=_.toArray(arguments),u=_.size(t),i=0;u>i;i++)r(e[i])||(e[i]=t[i]);return n.apply(this,e)}},flip2:function(n){return function(){var r=u.call(arguments);return r[0]=arguments[1],r[1]=arguments[0],n.apply(this,r)}},flip:function(n){return function(){var r=e.call(arguments);return n.apply(this,r)}},functionalize:function(n){return function(r){return n.apply(r,_.rest(arguments))}},methodize:function(n){return function(){return n.apply(null,_.cons(this,arguments))}},k:_.always,t:_.pipeline}),_.unsplatr=_.unsplat,_.mapArgsWith=o(_.flip(n)),_.bound=function(n,r){var t=n[r];if(!_.isFunction(t))throw new TypeError("Expected property to be a function");return _.bind(t,n)}}.call(this),function(){"object"==typeof exports&&(_=module.exports=require("underscore"));var n=Array.prototype.slice;_.mixin({attempt:function(r,t){if(null==r)return void 0;var e=r[t],u=n.call(arguments,2);return _.isFunction(e)?e.apply(r,u):void 0}})}.call(this),function(){function n(n){return function(r){return n.call(this,r)}}function r(n,r,t){var e,u;for(e=void 0!==t?t:n(),u=n();null!=u;)e=r.call(u,e,u),u=n();return e}function t(n,r){var t=w;return function(){return t===w?t=n:null!=t&&(t=r.call(t,t)),t}}function e(n,r){var t,e,u=n;return function(){return null!=u?(t=r.call(u,u),e=t[1],u=null!=e?t[0]:void 0,e):void 0}}function u(n,r,t){var e=t;return function(){var t=n();return null==t?t:e=void 0===e?t:r.call(t,e,t)}}function i(n,r,t){var e,u,i=t;return function(){return u=n(),null==u?u:void 0===i?i=u:(e=r.call(u,i,u),i=e[0],e[1])}}function o(n,r){return function(){var t;return t=n(),null!=t?r.call(t,t):void 0}}function c(n,r){var t=null;return function(){var e,u;if(null==t){if(u=n(),null==u)return t=null,void 0;t=r.call(u,u)}for(;null==e;)if(e=t(),null==e){if(u=n(),null==u)return t=null,void 0;t=r.call(u,u)}return e}}function a(n,r){return function(){var t;for(t=n();null!=t;){if(r.call(t,t))return t;t=n()}return void 0}}function f(n,r){return a(n,function(n){return!r(n)})}function l(n,r){return a(n,r)()}function s(n,r,t){for(var e=0;r-->0;)n();return null!=t?function(){return t>=++e?n():void 0}:n}function p(n,r){return s(n,null==r?1:r)}function m(n,r){return s(n,0,null==r?1:r)}function h(n){var r=0;return function(){return n[r++]}}function g(n){var r=0,t=n.length;return function(){return n[r++%t]}}function y(n){var r,t,e;return r=0,e=[],t=function(){var u,i;return u=n[r++],u instanceof Array?(e.push({array:n,index:r}),n=u,r=0,t()):void 0===u?e.length>0?(i=e.pop(),n=i.array,r=i.index,t()):void 0:u}}function v(n){return function(){return n}}function d(n,r,t){return function(){var e;return n>r?void 0:(e=n,n+=t,e)}}function x(n,r,t){return function(){var e;return r>n?void 0:(e=n,n-=t,e)}}function b(n,r,t){return null==n?d(1,1/0,1):null==r?d(n,1/0,1):null==t?r>=n?d(n,r,1):x(n,r,1):t>0?d(n,r,t):0>t?x(n,r,Math.abs(t)):k(n)}"object"==typeof exports&&(_=module.exports=require("underscore"));var w={},A=n(b);_.iterators={accumulate:u,accumulateWithReturn:i,foldl:r,reduce:r,unfold:t,unfoldWithReturn:e,map:o,mapcat:c,select:a,reject:f,filter:a,find:l,slice:s,drop:p,take:m,List:h,Tree:y,constant:v,K:v,numbers:A,range:b,cycle:g}}.call(this,void 0),"object"==typeof exports&&(_=module.exports=require("underscore")),_.mixin({isInstanceOf:function(n,r){return n instanceof r},isAssociative:function(n){return _.isArray(n)||_.isObject(n)||_.isArguments(n)},isIndexed:function(n){return _.isArray(n)||_.isString(n)||_.isArguments(n)},isSequential:function(n){return _.isArray(n)||_.isArguments(n)},isPlainObject:function(n){return _.isObject(n)&&n.constructor===Object},isZero:function(n){return 0===n},isEven:function(n){return _.isFinite(n)&&0===(1&n)},isOdd:function(n){return _.isFinite(n)&&!_.isEven(n)},isPositive:function(n){return n>0},isNegative:function(n){return 0>n},isValidDate:function(n){return _.isDate(n)&&!_.isNaN(n.getTime())},isNumeric:function(n){return!isNaN(parseFloat(n))&&isFinite(n)},isInteger:function(n){return _.isNumeric(n)&&0===n%1},isFloat:function(n){return _.isNumeric(n)&&!_.isInteger(n)},isJSON:function(n){try{JSON.parse(n)}catch(r){return!1}return!0},isIncreasing:function(){var n=_.size(arguments);if(1===n)return!0;if(2===n)return arguments[0]r;r++)if(arguments[r-1]>=arguments[r])return!1;return!0},isDecreasing:function(){var n=_.size(arguments);if(1===n)return!0;if(2===n)return arguments[0]>arguments[1];for(var r=1;n>r;r++)if(arguments[r-1]<=arguments[r])return!1;return!0}}),function(){"object"==typeof exports&&(_=module.exports=require("underscore"));var n=(Array.prototype.slice,Array.prototype.concat),r=function(n){return null!=n},t=function(n){return n!==!1&&r(n)},e=function(n){return _.isArray(n)||_.isObject(n)},u=function(n){return function(r){return function(t){return n(t,r)}}};_.mixin({merge:function(){var r=_.some(arguments)?{}:null;return t(r)&&_.extend.apply(null,n.call([r],_.toArray(arguments))),r},renameKeys:function(t,e){return _.reduce(e,function(n,e,u){return r(t[u])?(n[e]=t[u],n):n},_.omit.apply(null,n.call([t],_.keys(e))))},snapshot:function(n){if(null==n||"object"!=typeof n)return n;var r=new n.constructor;for(var t in n)n.hasOwnProperty(t)&&(r[t]=_.snapshot(n[t]));return r},updatePath:function(n,t,u,i){if(!e(n))throw new TypeError("Attempted to update a non-associative object.");if(!r(u))return t(n);var o=_.isArray(u),c=o?u:[u],a=o?_.snapshot(n):_.clone(n),f=_.last(c),l=a;return _.each(_.initial(c),function(n){i&&!_.has(l,n)&&(l[n]=_.clone(i)),l=l[n]}),l[f]=t(l[f]),a},setPath:function(n,t,e,u){if(!r(e))throw new TypeError("Attempted to set a property at a null path.");return _.updatePath(n,function(){return t},e,u)},frequencies:u(_.countBy)(_.identity)})}.call(this),function(){function n(n){for(var r,t=/\[("|')(.+)\1\]|([^.\[\]]+)/g,e=[];null!==(r=t.exec(n));)e.push(r[2]||r[3]);return e}"object"==typeof exports&&(_=module.exports=require("underscore"));var r=Array.prototype.concat,t=Array.prototype;t.slice,_.mixin({accessor:function(n){return function(r){return r&&r[n]}},dictionary:function(n){return function(r){return n&&r&&n[r]}},selectKeys:function(n,t){return _.pick.apply(null,r.call([n],t))},kv:function(n,r){return _.has(n,r)?[r,n[r]]:void 0},getPath:function(r,t){t="string"==typeof t?n(t):t;for(var e=-1,u=t.length;u>++e&&null!=r;)r=r[t[e]];return e===u?r:void 0},hasPath:function(r,t){t="string"==typeof t?n(t):t;for(var e=-1,u=t.length;u>++e&&_.isObject(r);){if(!(t[e]in r))return!1;r=r[t[e]]}return e===u},keysFromPath:n,pickWhen:function(n,r){var t={};return _.each(n,function(e,u){r(n[u])&&(t[u]=n[u])}),t},omitWhen:function(n,r){return _.pickWhen(n,function(n){return!r(n)})}})}.call(this),"object"==typeof exports&&(_=module.exports=require("underscore")),_.mixin({exists:function(n){return null!=n},truthy:function(n){return n!==!1&&_.exists(n)},falsey:function(n){return!_.truthy(n)},not:function(n){return!n},firstExisting:function(){for(var n=0;arguments.length>n;n++)if(null!=arguments[n])return arguments[n]}}),function(){function n(n){return t(function(r){return _.reduce(r,n)})}function r(n){return t(function(r){for(var t,e=0;r.length-1>e;e++)if(t=n(r[e],r[e+1]),t===!1)return t;return t})}function t(n){return function(r){var t=e(r)?r:arguments;return n(t)}}function e(n){return null!=n&&"number"==typeof n.length}function u(n){return function(){return!n.apply(this,arguments)}}function i(n,r){return n+r}function o(n,r){return n-r}function c(n,r){return n*r}function a(n,r){return n/r}function f(n,r){return n%r}function l(n){return++n}function s(n){return--n}function p(n){return-n}function m(n,r){return n&r}function h(n,r){return n|r}function g(n,r){return n^r}function y(n,r){return n<>r}function d(n,r){return n>>>r}function x(n){return~n}function b(n,r){return n==r}function w(n,r){return n===r}function A(n){return!n}function j(n,r){return n>r}function k(n,r){return r>n}function E(n,r){return n>=r}function q(n,r){return r>=n}"object"==typeof exports&&(_=module.exports=require("underscore")),_.mixin({add:n(i),sub:n(o),mul:n(c),div:n(a),mod:f,inc:l,dec:s,neg:p,eq:r(b),seq:r(w),neq:u(r(b)),sneq:u(r(w)),not:A,gt:r(j),lt:r(k),gte:r(E),lte:r(q),bitwiseAnd:n(m),bitwiseOr:n(h),bitwiseXor:n(g),bitwiseNot:x,bitwiseLeft:n(y),bitwiseRight:n(v),bitwiseZ:n(d)})}.call(this),function(){"object"==typeof exports&&(_=module.exports=require("underscore"));var n=/\+/g,r=/\%20/g,t=/(?:([^\[]+))|(?:\[(.*?)\])/g,e=function(r){return decodeURIComponent(r.replace(n,"%20"))},u=function(n){return encodeURIComponent(n).replace(r,"+")},i=function(n,r,t){return _.isUndefined(t)&&(t=!0),_.isArray(r)?_.map(r,function(r,e){return i(t?e:n+"[]",r,!1)}).join("&"):_.isObject(r)?_.map(r,function(r,e){return i(t?e:n+"["+e+"]",r,!1)}).join("&"):u(n)+"="+u(r)};_.mixin({explode:function(n){return n.split("")},fromQuery:function(n){var r,u,i,o,c,a=n.split("&"),f={};return _.each(a,function(n){for(n=n.split("="),r=e(n[0]),i=r,c=f,t.lastIndex=0;null!==(u=t.exec(r));)_.isUndefined(u[1])?(o=u[2],c[i]=c[i]||(o?{}:[]),c=c[i]):o=u[1],i=o||_.size(c);c[i]=e(n[1])}),f},implode:function(n){return n.join("")},camelCase:function(n,r){if(r=r||"-","string"!=typeof r)throw new TypeError("Separator must be a string.");if(1!=r.length)throw Error("Separator must be one character.");return n.replace(RegExp(r+"([a-z])","g"),function(n){return n[1].toUpperCase()})},toDash:function(n,r){if(r=r||"-","string"!=typeof r)throw new TypeError("Separator must be a string.");if(1!=r.length)throw Error("Separator must be one character.");return n=n.replace(/([A-Z])/g,function(n){return r+n.toLowerCase()}),n.charAt(0)==r?n.substr(1):n},toQuery:function(n){return i("",n)},strContains:function(n,r){if("string"!=typeof n)throw new TypeError;return-1!=n.indexOf(r)}})}.call(this),"object"==typeof exports&&(_=module.exports=require("underscore")),_.mixin({done:function(n){var r=_(n);return r.stopTrampoline=!0,r},trampoline:function(n){for(var r=n.apply(n,_.rest(arguments));_.isFunction(r)&&(r=r(),!(r instanceof _&&r.stopTrampoline)););return r.value()}}); \ No newline at end of file diff --git a/docs/underscore.util.strings.js.md b/docs/underscore.util.strings.js.md index 7a1112d..bca3ad7 100644 --- a/docs/underscore.util.strings.js.md +++ b/docs/underscore.util.strings.js.md @@ -6,13 +6,17 @@ #### camelCase -**Signature:** `_.camelCase(string:String)` +**Signature:** `_.camelCase(string:String[, separator:String])` -Converts a dash-separated string to camel case. Opposite of [toDash](#todash). +Converts a dash-separated string to camel case. If separator is specified, +it's used instead of dash. Opposite of [toDash](#todash). ```javascript _.camelCase("ancient-greece"); // => "ancientGreece" + +_.camelCase("ancient_greece", "_"); +// => "ancientGreece" ``` -------------------------------------------------------------------------------- @@ -72,13 +76,17 @@ _.strContains("Acropolis", "polis"); #### toDash -**Signature:** `_.toDash(string:String)` +**Signature:** `_.toDash(string:String [, ])` -Converts a camel case string to a dashed string. Opposite of [camelCase](#camelcase). +Converts a camel case string to a dashed string. If separator is specified, +it's used instead of dash. Opposite of [camelCase](#camelcase). ```javascript _.toDash("thisIsSparta"); // => "this-is-sparta" + +_.toDash("thisIsSparta", '_'); +// => "this_is_sparta" ``` -------------------------------------------------------------------------------- diff --git a/package.json b/package.json index 7da9fc4..4131ac6 100644 --- a/package.json +++ b/package.json @@ -10,7 +10,7 @@ "grunt-cli": "~0.1.11", "grunt-contrib-concat": "0.3.0", "grunt-contrib-jshint": "^0.10.0", - "grunt-contrib-qunit": "~0.2.2", + "grunt-contrib-qunit": "^1.2.0", "grunt-contrib-uglify": "0.2.0", "grunt-contrib-watch": "~0.5.3", "grunt-docco": "~0.3.0", diff --git a/test/util.strings.js b/test/util.strings.js index dc7d071..28f6ea3 100644 --- a/test/util.strings.js +++ b/test/util.strings.js @@ -32,11 +32,25 @@ $(document).ready(function() { test('camelCase', function() { equal(_.camelCase('punic-wars'), 'punicWars', 'Should convert a dashed-format string to camelCase.'); + equal(_.camelCase('punic_wars', '_'), 'punicWars', 'Should convert a snake_case string to camelCase.'); + + var thrower = function() { _.camelCase('trojan-war', 12); }; + throws(thrower, TypeError, 'Throws TypeError if second argument is not a string.'); + + thrower = function() { _.camelCase('trojan-war', '__'); }; + throws(thrower, Error, 'Throws TypeError if separator is not one character.'); }); test('toDash', function() { equal(_.toDash('trojanWar'), 'trojan-war', 'Should convert a camelCase string to dashed-format.'); equal(_.toDash('PersianWar'), 'persian-war', 'Should convert a PascalCase string to dashed-format.'); + equal(_.toDash('persianWar', '_'), 'persian_war', 'Should convert a camelCase string to snake_case.'); + + var thrower = function() { _.toDash('trojanWar', 12); }; + throws(thrower, TypeError, 'Throws TypeError if second argument is not a string.'); + + thrower = function() { _.toDash('trojanWar', '__'); }; + throws(thrower, Error, 'Throws TypeError if separator is not one character.'); }); test('toQuery', function() { diff --git a/underscore.util.strings.js b/underscore.util.strings.js index 1ff95ab..b15ec89 100644 --- a/underscore.util.strings.js +++ b/underscore.util.strings.js @@ -105,15 +105,21 @@ }, // Converts a string to camel case - camelCase : function( string ){ - return string.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase(); }); + camelCase : function( string, separator ){ + separator = separator || '-'; + if (typeof separator != 'string') throw new TypeError('Separator must be a string.'); + if (separator.length != 1) throw new Error('Separator must be one character.'); + return string.replace(new RegExp(separator+'([a-z])', 'g'), function (g) { return g[1].toUpperCase(); }); }, // Converts camel case to dashed (opposite of _.camelCase) - toDash : function( string ){ - string = string.replace(/([A-Z])/g, function($1){return "-"+$1.toLowerCase();}); + toDash : function( string, separator ){ + separator = separator || '-'; + if (typeof separator != 'string') throw new TypeError('Separator must be a string.'); + if (separator.length != 1) throw new Error('Separator must be one character.'); + string = string.replace(/([A-Z])/g, function($1){return separator+$1.toLowerCase();}); // remove first dash - return ( string.charAt( 0 ) == '-' ) ? string.substr(1) : string; + return ( string.charAt( 0 ) == separator ) ? string.substr(1) : string; }, // Creates a query string from a hash