diff --git a/lodash.js b/lodash.js index 9058b44a4..1252eb89c 100644 --- a/lodash.js +++ b/lodash.js @@ -28,6 +28,9 @@ /** Used to generate unique IDs */ var idCounter = 0; + /** Used to detect words composed of all capital letters */ + var reAllCaps = /^[A-Z]+$/; + /** Used to match empty string literals in compiled template source */ var reEmptyStringLeading = /\b__p \+= '';/g, reEmptyStringMiddle = /\b(__p \+=) '' \+/g, @@ -78,7 +81,7 @@ var reUnescapedString = /['\n\r\u2028\u2029\\]/g; /** Used to match words to create compound words */ - var reWords = /[A-Z]{2,}|[a-zA-Z0-9][a-z0-9]*/g; + var reWords = /[A-Z]{2,}(?=[A-Z][a-z]+[0-9]*|\b)|[A-Z]?[a-z]+[0-9]*|[A-Z]|[a-z]+|[0-9]+/g; /** Used to detect and test whitespace */ var whitespace = ( @@ -6946,8 +6949,14 @@ * _.camelCase('__hello_world__'); * // => 'helloWorld' */ - var camelCase = createCompounder(function(result, word, index) { - return result + word.charAt(0)[index ? 'toUpperCase' : 'toLowerCase']() + word.slice(1); + var camelCase = createCompounder(function(result, word, index, words) { + if (!index && reAllCaps.test(word)) { + return result + word.toLowerCase(); + } + var lastWord = index && words[index - 1], + isCapped = index && !(index > 1 && words.length == 3 && (lastWord == 2 || lastWord == 4)); + + return result + (word.charAt(0)[isCapped ? 'toUpperCase' : 'toLowerCase']() + word.slice(1)); }); /** diff --git a/test/test.js b/test/test.js index 048f38730..e425d02e3 100644 --- a/test/test.js +++ b/test/test.js @@ -1025,6 +1025,12 @@ }); }); + test('`_.' + methodName + '` should handle double-converting strings', 4, function() { + _.forEach(['Hello world', 'helloWorld', '--hello-world', '__hello_world__'], function(string) { + equal(func(func(string)), expected); + }); + }); + test('`_.' + methodName + '` should deburr letters', 1, function() { var actual = _.map(burredLetters, function(burred, index) { var isCamel = caseName == 'camel', @@ -1059,6 +1065,25 @@ /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.camelCase'); + + (function() { + test('should work with numbers', 6, function() { + equal(_.camelCase('P2P'), 'p2p'); + equal(_.camelCase('ascii 2 unicode'), 'ascii2unicode'); + equal(_.camelCase('two 4 one'), 'two4one'); + equal(_.camelCase('walk 500 miles'), 'walk500Miles'); + equal(_.camelCase('xhr2 request'), 'xhr2Request'); + equal(_.camelCase('too legit 2 quit'), 'tooLegit2Quit'); + }); + + test('should handle acronyms', 1, function() { + equal(_.camelCase('XMLHttpRequest'), 'xmlHttpRequest'); + }); + }()); + + /*--------------------------------------------------------------------------*/ + QUnit.module('lodash.capitalize'); (function() {