├── .gitignore ├── Gruntfile.js ├── README.md ├── SpecRunner.html ├── lib └── jasmine-2.1.3 │ ├── boot.js │ ├── console.js │ ├── jasmine-html.js │ ├── jasmine.css │ ├── jasmine.js │ └── jasmine_favicon.png ├── package.json ├── spec ├── arraysSpec.coffee ├── arraysSpec.js ├── chainingSpec.coffee ├── chainingSpec.js ├── collectionsSpec.coffee ├── collectionsSpec.js ├── functionsSpec.coffee ├── functionsSpec.js ├── objectsSpec.coffee ├── objectsSpec.js ├── utilitiesSpec.coffee └── utilitiesSpec.js └── src ├── arrays.coffee ├── arrays.js ├── collections.coffee ├── collections.js ├── functions.coffee ├── functions.js ├── objects.coffee ├── objects.js ├── utilities.coffee └── utilities.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | coffee: { 4 | src: { 5 | expand: true, 6 | flatten: true, 7 | cwd: './src', 8 | src: ['*.coffee'], 9 | dest: './src', 10 | ext: '.js' 11 | }, 12 | 13 | spec: { 14 | expand: true, 15 | flatten: true, 16 | cwd: './spec', 17 | src: ['*.coffee'], 18 | dest: './spec', 19 | ext: '.js' 20 | } 21 | }, 22 | 23 | watch: { 24 | scripts: { 25 | files: ['./spec/*.coffee', './src/*.coffee'], 26 | tasks: ['coffee'], 27 | options: { 28 | spawn: false 29 | } 30 | } 31 | } 32 | }); 33 | grunt.loadNpmTasks('grunt-contrib-coffee'); 34 | grunt.loadNpmTasks('grunt-contrib-watch'); 35 | grunt.registerTask('default', ['watch']); 36 | }; 37 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |

UnderScore.coffee

2 |

A utility library for JavaScript and CoffeeScript applications. 3 | UnderScore.coffee is the CoffeeScript adaption of the underscore library created by Jeremy Ashkenas.

5 | 6 |

Testing

7 |

UnderScore.coffee has rigorous specs implemented using the Jasmine testing 9 | framework. The specs are ran by opening SpecRunner.html in a 10 | browser. Grunt is used for automatic compiling of CoffeeScript into 11 | JavaScript.

12 | 13 |

Technology Stack

14 |
    15 |
  1. CoffeeScript
  2. 16 |
  3. Jasmine
  4. 17 |
  5. Grunt
  6. 18 |
19 | 20 | 21 | -------------------------------------------------------------------------------- /SpecRunner.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Jasmine Spec Runner v2.1.3 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | -------------------------------------------------------------------------------- /lib/jasmine-2.1.3/boot.js: -------------------------------------------------------------------------------- 1 | /** 2 | Starting with version 2.0, this file "boots" Jasmine, performing all of the necessary initialization before executing the loaded environment and all of a project's specs. This file should be loaded after `jasmine.js` and `jasmine_html.js`, but before any project source files or spec files are loaded. Thus this file can also be used to customize Jasmine for a project. 3 | 4 | If a project is using Jasmine via the standalone distribution, this file can be customized directly. If a project is using Jasmine via the [Ruby gem][jasmine-gem], this file can be copied into the support directory via `jasmine copy_boot_js`. Other environments (e.g., Python) will have different mechanisms. 5 | 6 | The location of `boot.js` can be specified and/or overridden in `jasmine.yml`. 7 | 8 | [jasmine-gem]: http://github.com/pivotal/jasmine-gem 9 | */ 10 | 11 | (function() { 12 | 13 | /** 14 | * ## Require & Instantiate 15 | * 16 | * Require Jasmine's core files. Specifically, this requires and attaches all of Jasmine's code to the `jasmine` reference. 17 | */ 18 | window.jasmine = jasmineRequire.core(jasmineRequire); 19 | 20 | /** 21 | * Since this is being run in a browser and the results should populate to an HTML page, require the HTML-specific Jasmine code, injecting the same reference. 22 | */ 23 | jasmineRequire.html(jasmine); 24 | 25 | /** 26 | * Create the Jasmine environment. This is used to run all specs in a project. 27 | */ 28 | var env = jasmine.getEnv(); 29 | 30 | /** 31 | * ## The Global Interface 32 | * 33 | * Build up the functions that will be exposed as the Jasmine public interface. A project can customize, rename or alias any of these functions as desired, provided the implementation remains unchanged. 34 | */ 35 | var jasmineInterface = jasmineRequire.interface(jasmine, env); 36 | 37 | /** 38 | * Add all of the Jasmine global/public interface to the proper global, so a project can use the public interface directly. For example, calling `describe` in specs instead of `jasmine.getEnv().describe`. 39 | */ 40 | if (typeof window == "undefined" && typeof exports == "object") { 41 | extend(exports, jasmineInterface); 42 | } else { 43 | extend(window, jasmineInterface); 44 | } 45 | 46 | /** 47 | * ## Runner Parameters 48 | * 49 | * More browser specific code - wrap the query string in an object and to allow for getting/setting parameters from the runner user interface. 50 | */ 51 | 52 | var queryString = new jasmine.QueryString({ 53 | getWindowLocation: function() { return window.location; } 54 | }); 55 | 56 | var catchingExceptions = queryString.getParam("catch"); 57 | env.catchExceptions(typeof catchingExceptions === "undefined" ? true : catchingExceptions); 58 | 59 | /** 60 | * ## Reporters 61 | * The `HtmlReporter` builds all of the HTML UI for the runner page. This reporter paints the dots, stars, and x's for specs, as well as all spec names and all failures (if any). 62 | */ 63 | var htmlReporter = new jasmine.HtmlReporter({ 64 | env: env, 65 | onRaiseExceptionsClick: function() { queryString.setParam("catch", !env.catchingExceptions()); }, 66 | getContainer: function() { return document.body; }, 67 | createElement: function() { return document.createElement.apply(document, arguments); }, 68 | createTextNode: function() { return document.createTextNode.apply(document, arguments); }, 69 | timer: new jasmine.Timer() 70 | }); 71 | 72 | /** 73 | * The `jsApiReporter` also receives spec results, and is used by any environment that needs to extract the results from JavaScript. 74 | */ 75 | env.addReporter(jasmineInterface.jsApiReporter); 76 | env.addReporter(htmlReporter); 77 | 78 | /** 79 | * Filter which specs will be run by matching the start of the full name against the `spec` query param. 80 | */ 81 | var specFilter = new jasmine.HtmlSpecFilter({ 82 | filterString: function() { return queryString.getParam("spec"); } 83 | }); 84 | 85 | env.specFilter = function(spec) { 86 | return specFilter.matches(spec.getFullName()); 87 | }; 88 | 89 | /** 90 | * Setting up timing functions to be able to be overridden. Certain browsers (Safari, IE 8, phantomjs) require this hack. 91 | */ 92 | window.setTimeout = window.setTimeout; 93 | window.setInterval = window.setInterval; 94 | window.clearTimeout = window.clearTimeout; 95 | window.clearInterval = window.clearInterval; 96 | 97 | /** 98 | * ## Execution 99 | * 100 | * Replace the browser window's `onload`, ensure it's called, and then run all of the loaded specs. This includes initializing the `HtmlReporter` instance and then executing the loaded Jasmine environment. All of this will happen after all of the specs are loaded. 101 | */ 102 | var currentWindowOnload = window.onload; 103 | 104 | window.onload = function() { 105 | if (currentWindowOnload) { 106 | currentWindowOnload(); 107 | } 108 | htmlReporter.initialize(); 109 | env.execute(); 110 | }; 111 | 112 | /** 113 | * Helper function for readability above. 114 | */ 115 | function extend(destination, source) { 116 | for (var property in source) destination[property] = source[property]; 117 | return destination; 118 | } 119 | 120 | }()); 121 | -------------------------------------------------------------------------------- /lib/jasmine-2.1.3/console.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | function getJasmineRequireObj() { 24 | if (typeof module !== 'undefined' && module.exports) { 25 | return exports; 26 | } else { 27 | window.jasmineRequire = window.jasmineRequire || {}; 28 | return window.jasmineRequire; 29 | } 30 | } 31 | 32 | getJasmineRequireObj().console = function(jRequire, j$) { 33 | j$.ConsoleReporter = jRequire.ConsoleReporter(); 34 | }; 35 | 36 | getJasmineRequireObj().ConsoleReporter = function() { 37 | 38 | var noopTimer = { 39 | start: function(){}, 40 | elapsed: function(){ return 0; } 41 | }; 42 | 43 | function ConsoleReporter(options) { 44 | var print = options.print, 45 | showColors = options.showColors || false, 46 | onComplete = options.onComplete || function() {}, 47 | timer = options.timer || noopTimer, 48 | specCount, 49 | failureCount, 50 | failedSpecs = [], 51 | pendingCount, 52 | ansi = { 53 | green: '\x1B[32m', 54 | red: '\x1B[31m', 55 | yellow: '\x1B[33m', 56 | none: '\x1B[0m' 57 | }, 58 | failedSuites = []; 59 | 60 | print('ConsoleReporter is deprecated and will be removed in a future version.'); 61 | 62 | this.jasmineStarted = function() { 63 | specCount = 0; 64 | failureCount = 0; 65 | pendingCount = 0; 66 | print('Started'); 67 | printNewline(); 68 | timer.start(); 69 | }; 70 | 71 | this.jasmineDone = function() { 72 | printNewline(); 73 | for (var i = 0; i < failedSpecs.length; i++) { 74 | specFailureDetails(failedSpecs[i]); 75 | } 76 | 77 | if(specCount > 0) { 78 | printNewline(); 79 | 80 | var specCounts = specCount + ' ' + plural('spec', specCount) + ', ' + 81 | failureCount + ' ' + plural('failure', failureCount); 82 | 83 | if (pendingCount) { 84 | specCounts += ', ' + pendingCount + ' pending ' + plural('spec', pendingCount); 85 | } 86 | 87 | print(specCounts); 88 | } else { 89 | print('No specs found'); 90 | } 91 | 92 | printNewline(); 93 | var seconds = timer.elapsed() / 1000; 94 | print('Finished in ' + seconds + ' ' + plural('second', seconds)); 95 | printNewline(); 96 | 97 | for(i = 0; i < failedSuites.length; i++) { 98 | suiteFailureDetails(failedSuites[i]); 99 | } 100 | 101 | onComplete(failureCount === 0); 102 | }; 103 | 104 | this.specDone = function(result) { 105 | specCount++; 106 | 107 | if (result.status == 'pending') { 108 | pendingCount++; 109 | print(colored('yellow', '*')); 110 | return; 111 | } 112 | 113 | if (result.status == 'passed') { 114 | print(colored('green', '.')); 115 | return; 116 | } 117 | 118 | if (result.status == 'failed') { 119 | failureCount++; 120 | failedSpecs.push(result); 121 | print(colored('red', 'F')); 122 | } 123 | }; 124 | 125 | this.suiteDone = function(result) { 126 | if (result.failedExpectations && result.failedExpectations.length > 0) { 127 | failureCount++; 128 | failedSuites.push(result); 129 | } 130 | }; 131 | 132 | return this; 133 | 134 | function printNewline() { 135 | print('\n'); 136 | } 137 | 138 | function colored(color, str) { 139 | return showColors ? (ansi[color] + str + ansi.none) : str; 140 | } 141 | 142 | function plural(str, count) { 143 | return count == 1 ? str : str + 's'; 144 | } 145 | 146 | function repeat(thing, times) { 147 | var arr = []; 148 | for (var i = 0; i < times; i++) { 149 | arr.push(thing); 150 | } 151 | return arr; 152 | } 153 | 154 | function indent(str, spaces) { 155 | var lines = (str || '').split('\n'); 156 | var newArr = []; 157 | for (var i = 0; i < lines.length; i++) { 158 | newArr.push(repeat(' ', spaces).join('') + lines[i]); 159 | } 160 | return newArr.join('\n'); 161 | } 162 | 163 | function specFailureDetails(result) { 164 | printNewline(); 165 | print(result.fullName); 166 | 167 | for (var i = 0; i < result.failedExpectations.length; i++) { 168 | var failedExpectation = result.failedExpectations[i]; 169 | printNewline(); 170 | print(indent(failedExpectation.message, 2)); 171 | print(indent(failedExpectation.stack, 2)); 172 | } 173 | 174 | printNewline(); 175 | } 176 | 177 | function suiteFailureDetails(result) { 178 | for (var i = 0; i < result.failedExpectations.length; i++) { 179 | printNewline(); 180 | print(colored('red', 'An error was thrown in an afterAll')); 181 | printNewline(); 182 | print(colored('red', 'AfterAll ' + result.failedExpectations[i].message)); 183 | 184 | } 185 | printNewline(); 186 | } 187 | } 188 | 189 | return ConsoleReporter; 190 | }; 191 | -------------------------------------------------------------------------------- /lib/jasmine-2.1.3/jasmine-html.js: -------------------------------------------------------------------------------- 1 | /* 2 | Copyright (c) 2008-2014 Pivotal Labs 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining 5 | a copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 22 | */ 23 | jasmineRequire.html = function(j$) { 24 | j$.ResultsNode = jasmineRequire.ResultsNode(); 25 | j$.HtmlReporter = jasmineRequire.HtmlReporter(j$); 26 | j$.QueryString = jasmineRequire.QueryString(); 27 | j$.HtmlSpecFilter = jasmineRequire.HtmlSpecFilter(); 28 | }; 29 | 30 | jasmineRequire.HtmlReporter = function(j$) { 31 | 32 | var noopTimer = { 33 | start: function() {}, 34 | elapsed: function() { return 0; } 35 | }; 36 | 37 | function HtmlReporter(options) { 38 | var env = options.env || {}, 39 | getContainer = options.getContainer, 40 | createElement = options.createElement, 41 | createTextNode = options.createTextNode, 42 | onRaiseExceptionsClick = options.onRaiseExceptionsClick || function() {}, 43 | timer = options.timer || noopTimer, 44 | results = [], 45 | specsExecuted = 0, 46 | failureCount = 0, 47 | pendingSpecCount = 0, 48 | htmlReporterMain, 49 | symbols, 50 | failedSuites = []; 51 | 52 | this.initialize = function() { 53 | clearPrior(); 54 | htmlReporterMain = createDom('div', {className: 'jasmine_html-reporter'}, 55 | createDom('div', {className: 'banner'}, 56 | createDom('a', {className: 'title', href: 'http://jasmine.github.io/', target: '_blank'}), 57 | createDom('span', {className: 'version'}, j$.version) 58 | ), 59 | createDom('ul', {className: 'symbol-summary'}), 60 | createDom('div', {className: 'alert'}), 61 | createDom('div', {className: 'results'}, 62 | createDom('div', {className: 'failures'}) 63 | ) 64 | ); 65 | getContainer().appendChild(htmlReporterMain); 66 | 67 | symbols = find('.symbol-summary'); 68 | }; 69 | 70 | var totalSpecsDefined; 71 | this.jasmineStarted = function(options) { 72 | totalSpecsDefined = options.totalSpecsDefined || 0; 73 | timer.start(); 74 | }; 75 | 76 | var summary = createDom('div', {className: 'summary'}); 77 | 78 | var topResults = new j$.ResultsNode({}, '', null), 79 | currentParent = topResults; 80 | 81 | this.suiteStarted = function(result) { 82 | currentParent.addChild(result, 'suite'); 83 | currentParent = currentParent.last(); 84 | }; 85 | 86 | this.suiteDone = function(result) { 87 | if (result.status == 'failed') { 88 | failedSuites.push(result); 89 | } 90 | 91 | if (currentParent == topResults) { 92 | return; 93 | } 94 | 95 | currentParent = currentParent.parent; 96 | }; 97 | 98 | this.specStarted = function(result) { 99 | currentParent.addChild(result, 'spec'); 100 | }; 101 | 102 | var failures = []; 103 | this.specDone = function(result) { 104 | if(noExpectations(result) && typeof console !== 'undefined' && typeof console.error !== 'undefined') { 105 | console.error('Spec \'' + result.fullName + '\' has no expectations.'); 106 | } 107 | 108 | if (result.status != 'disabled') { 109 | specsExecuted++; 110 | } 111 | 112 | symbols.appendChild(createDom('li', { 113 | className: noExpectations(result) ? 'empty' : result.status, 114 | id: 'spec_' + result.id, 115 | title: result.fullName 116 | } 117 | )); 118 | 119 | if (result.status == 'failed') { 120 | failureCount++; 121 | 122 | var failure = 123 | createDom('div', {className: 'spec-detail failed'}, 124 | createDom('div', {className: 'description'}, 125 | createDom('a', {title: result.fullName, href: specHref(result)}, result.fullName) 126 | ), 127 | createDom('div', {className: 'messages'}) 128 | ); 129 | var messages = failure.childNodes[1]; 130 | 131 | for (var i = 0; i < result.failedExpectations.length; i++) { 132 | var expectation = result.failedExpectations[i]; 133 | messages.appendChild(createDom('div', {className: 'result-message'}, expectation.message)); 134 | messages.appendChild(createDom('div', {className: 'stack-trace'}, expectation.stack)); 135 | } 136 | 137 | failures.push(failure); 138 | } 139 | 140 | if (result.status == 'pending') { 141 | pendingSpecCount++; 142 | } 143 | }; 144 | 145 | this.jasmineDone = function() { 146 | var banner = find('.banner'); 147 | banner.appendChild(createDom('span', {className: 'duration'}, 'finished in ' + timer.elapsed() / 1000 + 's')); 148 | 149 | var alert = find('.alert'); 150 | 151 | alert.appendChild(createDom('span', { className: 'exceptions' }, 152 | createDom('label', { className: 'label', 'for': 'raise-exceptions' }, 'raise exceptions'), 153 | createDom('input', { 154 | className: 'raise', 155 | id: 'raise-exceptions', 156 | type: 'checkbox' 157 | }) 158 | )); 159 | var checkbox = find('#raise-exceptions'); 160 | 161 | checkbox.checked = !env.catchingExceptions(); 162 | checkbox.onclick = onRaiseExceptionsClick; 163 | 164 | if (specsExecuted < totalSpecsDefined) { 165 | var skippedMessage = 'Ran ' + specsExecuted + ' of ' + totalSpecsDefined + ' specs - run all'; 166 | alert.appendChild( 167 | createDom('span', {className: 'bar skipped'}, 168 | createDom('a', {href: '?', title: 'Run all specs'}, skippedMessage) 169 | ) 170 | ); 171 | } 172 | var statusBarMessage = ''; 173 | var statusBarClassName = 'bar '; 174 | 175 | if (totalSpecsDefined > 0) { 176 | statusBarMessage += pluralize('spec', specsExecuted) + ', ' + pluralize('failure', failureCount); 177 | if (pendingSpecCount) { statusBarMessage += ', ' + pluralize('pending spec', pendingSpecCount); } 178 | statusBarClassName += (failureCount > 0) ? 'failed' : 'passed'; 179 | } else { 180 | statusBarClassName += 'skipped'; 181 | statusBarMessage += 'No specs found'; 182 | } 183 | 184 | alert.appendChild(createDom('span', {className: statusBarClassName}, statusBarMessage)); 185 | 186 | for(i = 0; i < failedSuites.length; i++) { 187 | var failedSuite = failedSuites[i]; 188 | for(var j = 0; j < failedSuite.failedExpectations.length; j++) { 189 | var errorBarMessage = 'AfterAll ' + failedSuite.failedExpectations[j].message; 190 | var errorBarClassName = 'bar errored'; 191 | alert.appendChild(createDom('span', {className: errorBarClassName}, errorBarMessage)); 192 | } 193 | } 194 | 195 | var results = find('.results'); 196 | results.appendChild(summary); 197 | 198 | summaryList(topResults, summary); 199 | 200 | function summaryList(resultsTree, domParent) { 201 | var specListNode; 202 | for (var i = 0; i < resultsTree.children.length; i++) { 203 | var resultNode = resultsTree.children[i]; 204 | if (resultNode.type == 'suite') { 205 | var suiteListNode = createDom('ul', {className: 'suite', id: 'suite-' + resultNode.result.id}, 206 | createDom('li', {className: 'suite-detail'}, 207 | createDom('a', {href: specHref(resultNode.result)}, resultNode.result.description) 208 | ) 209 | ); 210 | 211 | summaryList(resultNode, suiteListNode); 212 | domParent.appendChild(suiteListNode); 213 | } 214 | if (resultNode.type == 'spec') { 215 | if (domParent.getAttribute('class') != 'specs') { 216 | specListNode = createDom('ul', {className: 'specs'}); 217 | domParent.appendChild(specListNode); 218 | } 219 | var specDescription = resultNode.result.description; 220 | if(noExpectations(resultNode.result)) { 221 | specDescription = 'SPEC HAS NO EXPECTATIONS ' + specDescription; 222 | } 223 | specListNode.appendChild( 224 | createDom('li', { 225 | className: resultNode.result.status, 226 | id: 'spec-' + resultNode.result.id 227 | }, 228 | createDom('a', {href: specHref(resultNode.result)}, specDescription) 229 | ) 230 | ); 231 | } 232 | } 233 | } 234 | 235 | if (failures.length) { 236 | alert.appendChild( 237 | createDom('span', {className: 'menu bar spec-list'}, 238 | createDom('span', {}, 'Spec List | '), 239 | createDom('a', {className: 'failures-menu', href: '#'}, 'Failures'))); 240 | alert.appendChild( 241 | createDom('span', {className: 'menu bar failure-list'}, 242 | createDom('a', {className: 'spec-list-menu', href: '#'}, 'Spec List'), 243 | createDom('span', {}, ' | Failures '))); 244 | 245 | find('.failures-menu').onclick = function() { 246 | setMenuModeTo('failure-list'); 247 | }; 248 | find('.spec-list-menu').onclick = function() { 249 | setMenuModeTo('spec-list'); 250 | }; 251 | 252 | setMenuModeTo('failure-list'); 253 | 254 | var failureNode = find('.failures'); 255 | for (var i = 0; i < failures.length; i++) { 256 | failureNode.appendChild(failures[i]); 257 | } 258 | } 259 | }; 260 | 261 | return this; 262 | 263 | function find(selector) { 264 | return getContainer().querySelector('.jasmine_html-reporter ' + selector); 265 | } 266 | 267 | function clearPrior() { 268 | // return the reporter 269 | var oldReporter = find(''); 270 | 271 | if(oldReporter) { 272 | getContainer().removeChild(oldReporter); 273 | } 274 | } 275 | 276 | function createDom(type, attrs, childrenVarArgs) { 277 | var el = createElement(type); 278 | 279 | for (var i = 2; i < arguments.length; i++) { 280 | var child = arguments[i]; 281 | 282 | if (typeof child === 'string') { 283 | el.appendChild(createTextNode(child)); 284 | } else { 285 | if (child) { 286 | el.appendChild(child); 287 | } 288 | } 289 | } 290 | 291 | for (var attr in attrs) { 292 | if (attr == 'className') { 293 | el[attr] = attrs[attr]; 294 | } else { 295 | el.setAttribute(attr, attrs[attr]); 296 | } 297 | } 298 | 299 | return el; 300 | } 301 | 302 | function pluralize(singular, count) { 303 | var word = (count == 1 ? singular : singular + 's'); 304 | 305 | return '' + count + ' ' + word; 306 | } 307 | 308 | function specHref(result) { 309 | return '?spec=' + encodeURIComponent(result.fullName); 310 | } 311 | 312 | function setMenuModeTo(mode) { 313 | htmlReporterMain.setAttribute('class', 'jasmine_html-reporter ' + mode); 314 | } 315 | 316 | function noExpectations(result) { 317 | return (result.failedExpectations.length + result.passedExpectations.length) === 0 && 318 | result.status === 'passed'; 319 | } 320 | } 321 | 322 | return HtmlReporter; 323 | }; 324 | 325 | jasmineRequire.HtmlSpecFilter = function() { 326 | function HtmlSpecFilter(options) { 327 | var filterString = options && options.filterString() && options.filterString().replace(/[-[\]{}()*+?.,\\^$|#\s]/g, '\\$&'); 328 | var filterPattern = new RegExp(filterString); 329 | 330 | this.matches = function(specName) { 331 | return filterPattern.test(specName); 332 | }; 333 | } 334 | 335 | return HtmlSpecFilter; 336 | }; 337 | 338 | jasmineRequire.ResultsNode = function() { 339 | function ResultsNode(result, type, parent) { 340 | this.result = result; 341 | this.type = type; 342 | this.parent = parent; 343 | 344 | this.children = []; 345 | 346 | this.addChild = function(result, type) { 347 | this.children.push(new ResultsNode(result, type, this)); 348 | }; 349 | 350 | this.last = function() { 351 | return this.children[this.children.length - 1]; 352 | }; 353 | } 354 | 355 | return ResultsNode; 356 | }; 357 | 358 | jasmineRequire.QueryString = function() { 359 | function QueryString(options) { 360 | 361 | this.setParam = function(key, value) { 362 | var paramMap = queryStringToParamMap(); 363 | paramMap[key] = value; 364 | options.getWindowLocation().search = toQueryString(paramMap); 365 | }; 366 | 367 | this.getParam = function(key) { 368 | return queryStringToParamMap()[key]; 369 | }; 370 | 371 | return this; 372 | 373 | function toQueryString(paramMap) { 374 | var qStrPairs = []; 375 | for (var prop in paramMap) { 376 | qStrPairs.push(encodeURIComponent(prop) + '=' + encodeURIComponent(paramMap[prop])); 377 | } 378 | return '?' + qStrPairs.join('&'); 379 | } 380 | 381 | function queryStringToParamMap() { 382 | var paramStr = options.getWindowLocation().search.substring(1), 383 | params = [], 384 | paramMap = {}; 385 | 386 | if (paramStr.length > 0) { 387 | params = paramStr.split('&'); 388 | for (var i = 0; i < params.length; i++) { 389 | var p = params[i].split('='); 390 | var value = decodeURIComponent(p[1]); 391 | if (value === 'true' || value === 'false') { 392 | value = JSON.parse(value); 393 | } 394 | paramMap[decodeURIComponent(p[0])] = value; 395 | } 396 | } 397 | 398 | return paramMap; 399 | } 400 | 401 | } 402 | 403 | return QueryString; 404 | }; 405 | -------------------------------------------------------------------------------- /lib/jasmine-2.1.3/jasmine.css: -------------------------------------------------------------------------------- 1 | body { overflow-y: scroll; } 2 | 3 | .jasmine_html-reporter { background-color: #eeeeee; padding: 5px; margin: -8px; font-size: 11px; font-family: Monaco, "Lucida Console", monospace; line-height: 14px; color: #333333; } 4 | .jasmine_html-reporter a { text-decoration: none; } 5 | .jasmine_html-reporter a:hover { text-decoration: underline; } 6 | .jasmine_html-reporter p, .jasmine_html-reporter h1, .jasmine_html-reporter h2, .jasmine_html-reporter h3, .jasmine_html-reporter h4, .jasmine_html-reporter h5, .jasmine_html-reporter h6 { margin: 0; line-height: 14px; } 7 | .jasmine_html-reporter .banner, .jasmine_html-reporter .symbol-summary, .jasmine_html-reporter .summary, .jasmine_html-reporter .result-message, .jasmine_html-reporter .spec .description, .jasmine_html-reporter .spec-detail .description, .jasmine_html-reporter .alert .bar, .jasmine_html-reporter .stack-trace { padding-left: 9px; padding-right: 9px; } 8 | .jasmine_html-reporter .banner { position: relative; } 9 | .jasmine_html-reporter .banner .title { background: url('data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAFoAAAAZCAMAAACGusnyAAACdlBMVEX/////AP+AgICqVaqAQICZM5mAVYCSSZKAQICOOY6ATYCLRouAQICJO4mSSYCIRIiPQICHPIeOR4CGQ4aMQICGPYaLRoCFQ4WKQICPPYWJRYCOQoSJQICNPoSIRICMQoSHQICHRICKQoOHQICKPoOJO4OJQYOMQICMQ4CIQYKLQICIPoKLQ4CKQICNPoKJQISMQ4KJQoSLQYKJQISLQ4KIQoSKQYKIQICIQISMQoSKQYKLQIOLQoOJQYGLQIOKQIOMQoGKQYOLQYGKQIOLQoGJQYOJQIOKQYGJQIOKQoGKQIGLQIKLQ4KKQoGLQYKJQIGKQYKJQIGKQIKJQoGKQYKLQIGKQYKLQIOJQoKKQoOJQYKKQIOJQoKKQoOKQIOLQoKKQYOLQYKJQIOKQoKKQYKKQoKJQYOKQYKLQIOKQoKLQYOKQYKLQIOJQoGKQYKJQYGJQoGKQYKLQoGLQYGKQoGJQYKKQYGJQIKKQoGJQYKLQIKKQYGLQYKKQYGKQYGKQYKJQYOKQoKJQYOKQYKLQYOLQYOKQYKLQYOKQoKKQYKKQYOKQYOJQYKKQYKLQYKKQIKKQoKKQYKKQYKKQoKJQIKKQYKLQYKKQYKKQIKKQYKKQYKKQYKKQIKKQYKJQYGLQYGKQYKKQYKKQYGKQIKKQYGKQYOJQoKKQYOLQYKKQYOKQoKKQYKKQoKKQYKKQYKJQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKJQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKLQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKKQYKmIDpEAAAA0XRSTlMAAQIDBAUGBwgJCgsMDQ4PEBESExQVFhcYGRobHB0eHyAiIyQlJycoKissLS4wMTQ1Njc4OTo7PDw+P0BCQ0RISUpLTE1OUFNUVVdYWFlaW15fYGFiY2ZnaGlqa2xtb3BxcnN0dnh5ent8fX5/gIGChIWIioyNjo+QkZOUlZaYmZqbnJ2eoKGio6WmqKmsra6vsLGztre4ubq7vL2+wMHDxMjJysvNzs/Q0dLU1tfY2dvc3t/g4eLj5ebn6Onq6+zt7u/w8vP09fb3+Pn6+/z9/vkVQXAAAAMaSURBVHhe5dXxV1N1GMfxz2ABbDgIAm5VDJOyVDIJLUMaVpBWUZUaGbmqoGpZRSiGiRWp6KoZ5AB0ZY50RImZQIlahKkMYXv/R90dBvET/rJfOr3Ouc8v99zPec59zvf56j+vYKlViSf7250X4Mr3O29Tgq08BdGB4DhcekEJ5YkQKFsgWZdtj9JpV+I8xPjLFqkrsEIqO8PHSpis36jWazcqjEsfJjkvRssVU37SdIOu4XCf5vEJPsnwJpnRNU9JmxhMk8l1gehIrq7hTFjzOD+Vf88629qKMJVNltInFeRexRQyJlNeqd1iGDlSzrIUIyXbyFfm3RYprcQRe7lqtWyGYbfc6dT0R2vmdOOkX3u55C1rP37ftiH+tDby4r/RBT0w8TyEkr+epB9XgPDmSYYWbrhCuFYaIyw3fDQAXTnSkh+ANofiHmWf9l+FY1I90FdQTetstO00o23novzVsJ7uB3/C5TkbjRwZ5JerwV4iRWq9HFbFMaK/d0TYqayRiQPuIxxS3Bu8JWU90/60tKi7vkhaznez0a/TbVOKj5CaOZh6fWG6/Lyv9B/ZLR1gw/S/fpbeVD3MCW1li6SvWDOn65tr99/uvWtBS0XDm4s1t+sOHpG0kpBKx/l77wOSnxLpcx6TXmXLTPQOKYOf9Q1dfr8/SJ2mFdCvl1Yl93DiHUZvXeLJbGSzYu5gVJ2slbSakOR8dxCq5adQ2oFLqsE9Ex3L4qQO0eOPeU5x56bypXp4onSEb5OkICX6lDat55TeoztNKQcJaakrz9KCb95oD69IKq+yKW4XPjknaS52V0TZqE2cTtXjcHSCRmUO88e+85hj3EP74i9p8pylw7lxgMDyyl6OV7ZejnjNMfatu87LxRbH0IS35gt2a4ZjmGpVBdKK3Wr6INk8jWWSGqbA55CKgjBRC6E9w78ydTg3ABS3AFV1QN0Y4Aa2pgEjWnQURj9L0ayK6R2ysEqxHUKzYnLvvyU+i9KM2JHJzE4vyZOyDcOwOsySajeLPc8sNvPJkFlyJd20wpqAzZeAfZ3oWybxd+P/3j+SG3uSBdf2VQAAAABJRU5ErkJggg==') no-repeat; background: url('data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0iVVRGLTgiIHN0YW5kYWxvbmU9Im5vIj8+CjwhLS0gQ3JlYXRlZCB3aXRoIElua3NjYXBlIChodHRwOi8vd3d3Lmlua3NjYXBlLm9yZy8pIC0tPgoKPHN2ZwogICB4bWxuczpkYz0iaHR0cDovL3B1cmwub3JnL2RjL2VsZW1lbnRzLzEuMS8iCiAgIHhtbG5zOmNjPSJodHRwOi8vY3JlYXRpdmVjb21tb25zLm9yZy9ucyMiCiAgIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyIKICAgeG1sbnM6c3ZnPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIKICAgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIgogICB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIKICAgdmVyc2lvbj0iMS4xIgogICB3aWR0aD0iNjgxLjk2MjUyIgogICBoZWlnaHQ9IjE4Ny41IgogICBpZD0ic3ZnMiIKICAgeG1sOnNwYWNlPSJwcmVzZXJ2ZSI+PG1ldGFkYXRhCiAgICAgaWQ9Im1ldGFkYXRhOCI+PHJkZjpSREY+PGNjOldvcmsKICAgICAgICAgcmRmOmFib3V0PSIiPjxkYzpmb3JtYXQ+aW1hZ2Uvc3ZnK3htbDwvZGM6Zm9ybWF0PjxkYzp0eXBlCiAgICAgICAgICAgcmRmOnJlc291cmNlPSJodHRwOi8vcHVybC5vcmcvZGMvZGNtaXR5cGUvU3RpbGxJbWFnZSIgLz48L2NjOldvcms+PC9yZGY6UkRGPjwvbWV0YWRhdGE+PGRlZnMKICAgICBpZD0iZGVmczYiPjxjbGlwUGF0aAogICAgICAgaWQ9ImNsaXBQYXRoMTgiPjxwYXRoCiAgICAgICAgIGQ9Ik0gMCwxNTAwIDAsMCBsIDU0NTUuNzQsMCAwLDE1MDAgTCAwLDE1MDAgeiIKICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgaWQ9InBhdGgyMCIgLz48L2NsaXBQYXRoPjwvZGVmcz48ZwogICAgIHRyYW5zZm9ybT0ibWF0cml4KDEuMjUsMCwwLC0xLjI1LDAsMTg3LjUpIgogICAgIGlkPSJnMTAiPjxnCiAgICAgICB0cmFuc2Zvcm09InNjYWxlKDAuMSwwLjEpIgogICAgICAgaWQ9ImcxMiI+PGcKICAgICAgICAgaWQ9ImcxNCI+PGcKICAgICAgICAgICBjbGlwLXBhdGg9InVybCgjY2xpcFBhdGgxOCkiCiAgICAgICAgICAgaWQ9ImcxNiI+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTU0NCw1OTkuNDM0IGMgMC45MiwtNDAuMzUyIDI1LjY4LC04MS42MDIgNzEuNTMsLTgxLjYwMiAyNy41MSwwIDQ3LjY4LDEyLjgzMiA2MS40NCwzNS43NTQgMTIuODMsMjIuOTMgMTIuODMsNTYuODUyIDEyLjgzLDgyLjUyNyBsIDAsMzI5LjE4NCAtNzEuNTIsMCAwLDEwNC41NDMgMjY2LjgzLDAgMCwtMTA0LjU0MyAtNzAuNiwwIDAsLTM0NC43NyBjIDAsLTU4LjY5MSAtMy42OCwtMTA0LjUzMSAtNDQuOTMsLTE1Mi4yMTggLTM2LjY4LC00Mi4xOCAtOTYuMjgsLTY2LjAyIC0xNTMuMTQsLTY2LjAyIC0xMTcuMzcsMCAtMjA3LjI0LDc3Ljk0MSAtMjAyLjY0LDE5Ny4xNDUgbCAxMzAuMiwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMjIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDIzMDEuNCw2NjIuNjk1IGMgMCw4MC43MDMgLTY2Ljk0LDE0NS44MTMgLTE0Ny42MywxNDUuODEzIC04My40NCwwIC0xNDcuNjMsLTY4Ljc4MSAtMTQ3LjYzLC0xNTEuMzAxIDAsLTc5Ljc4NSA2Ni45NCwtMTQ1LjgwMSAxNDUuOCwtMTQ1LjgwMSA4NC4zNSwwIDE0OS40Niw2Ny44NTIgMTQ5LjQ2LDE1MS4yODkgeiBtIC0xLjgzLC0xODEuNTQ3IGMgLTM1Ljc3LC01NC4wOTcgLTkzLjUzLC03OC44NTkgLTE1Ny43MiwtNzguODU5IC0xNDAuMywwIC0yNTEuMjQsMTE2LjQ0OSAtMjUxLjI0LDI1NC45MTggMCwxNDIuMTI5IDExMy43LDI2MC40MSAyNTYuNzQsMjYwLjQxIDYzLjI3LDAgMTE4LjI5LC0yOS4zMzYgMTUyLjIyLC04Mi41MjMgbCAwLDY5LjY4NyAxNzUuMTQsMCAwLC0xMDQuNTI3IC02MS40NCwwIDAsLTI4MC41OTggNjEuNDQsMCAwLC0xMDQuNTI3IC0xNzUuMTQsMCAwLDY2LjAxOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAyNjIyLjMzLDU1Ny4yNTggYyAzLjY3LC00NC4wMTYgMzMuMDEsLTczLjM0OCA3OC44NiwtNzMuMzQ4IDMzLjkzLDAgNjYuOTMsMjMuODI0IDY2LjkzLDYwLjUwNCAwLDQ4LjYwNiAtNDUuODQsNTYuODU2IC04My40NCw2Ni45NDEgLTg1LjI4LDIyLjAwNCAtMTc4LjgxLDQ4LjYwNiAtMTc4LjgxLDE1NS44NzkgMCw5My41MzYgNzguODYsMTQ3LjYzMyAxNjUuOTgsMTQ3LjYzMyA0NCwwIDgzLjQzLC05LjE3NiAxMTAuOTQsLTQ0LjAwOCBsIDAsMzMuOTIyIDgyLjUzLDAgMCwtMTMyLjk2NSAtMTA4LjIxLDAgYyAtMS44MywzNC44NTYgLTI4LjQyLDU3Ljc3NCAtNjMuMjYsNTcuNzc0IC0zMC4yNiwwIC02Mi4zNSwtMTcuNDIyIC02Mi4zNSwtNTEuMzQ4IDAsLTQ1Ljg0NyA0NC45MywtNTUuOTMgODAuNjksLTY0LjE4IDg4LjAyLC0yMC4xNzUgMTgyLjQ3LC00Ny42OTUgMTgyLjQ3LC0xNTcuNzM0IDAsLTk5LjAyNyAtODMuNDQsLTE1NC4wMzkgLTE3NS4xMywtMTU0LjAzOSAtNDkuNTMsMCAtOTQuNDYsMTUuNTgyIC0xMjYuNTUsNTMuMTggbCAwLC00MC4zNCAtODUuMjcsMCAwLDE0Mi4xMjkgMTE0LjYyLDAiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGgyNiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMjk4OC4xOCw4MDAuMjU0IC02My4yNiwwIDAsMTA0LjUyNyAxNjUuMDUsMCAwLC03My4zNTUgYyAzMS4xOCw1MS4zNDcgNzguODYsODUuMjc3IDE0MS4yMSw4NS4yNzcgNjcuODUsMCAxMjQuNzEsLTQxLjI1OCAxNTIuMjEsLTEwMi42OTkgMjYuNiw2Mi4zNTEgOTIuNjIsMTAyLjY5OSAxNjAuNDcsMTAyLjY5OSA1My4xOSwwIDEwNS40NiwtMjIgMTQxLjIxLC02Mi4zNTEgMzguNTIsLTQ0LjkzOCAzOC41MiwtOTMuNTMyIDM4LjUyLC0xNDkuNDU3IGwgMCwtMTg1LjIzOSA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40MiwwIDAsMTA0LjUyNyA2My4yOCwwIDAsMTU3LjcxNSBjIDAsMzIuMTAyIDAsNjAuNTI3IC0xNC42Nyw4OC45NTcgLTE4LjM0LDI2LjU4MiAtNDguNjEsNDAuMzQ0IC03OS43Nyw0MC4zNDQgLTMwLjI2LDAgLTYzLjI4LC0xMi44NDQgLTgyLjUzLC0zNi42NzIgLTIyLjkzLC0yOS4zNTUgLTIyLjkzLC01Ni44NjMgLTIyLjkzLC05Mi42MjkgbCAwLC0xNTcuNzE1IDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM4LjQxLDAgMCwxMDQuNTI3IDYzLjI4LDAgMCwxNTAuMzgzIGMgMCwyOS4zNDggMCw2Ni4wMjMgLTE0LjY3LDkxLjY5OSAtMTUuNTksMjkuMzM2IC00Ny42OSw0NC45MzQgLTgwLjcsNDQuOTM0IC0zMS4xOCwwIC01Ny43NywtMTEuMDA4IC03Ny45NCwtMzUuNzc0IC0yNC43NywtMzAuMjUzIC0yNi42LC02Mi4zNDMgLTI2LjYsLTk5Ljk0MSBsIDAsLTE1MS4zMDEgNjMuMjcsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNiwwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDI4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSAzOTk4LjY2LDk1MS41NDcgLTExMS44NywwIDAsMTE4LjI5MyAxMTEuODcsMCAwLC0xMTguMjkzIHogbSAwLC00MzEuODkxIDYzLjI3LDAgMCwtMTA0LjUyNyAtMjM5LjMzLDAgMCwxMDQuNTI3IDY0LjE5LDAgMCwyODAuNTk4IC02My4yNywwIDAsMTA0LjUyNyAxNzUuMTQsMCAwLC0zODUuMTI1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzAiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDQxNTkuMTIsODAwLjI1NCAtNjMuMjcsMCAwLDEwNC41MjcgMTc1LjE0LDAgMCwtNjkuNjg3IGMgMjkuMzUsNTQuMTAxIDg0LjM2LDgwLjY5OSAxNDQuODcsODAuNjk5IDUzLjE5LDAgMTA1LjQ1LC0yMi4wMTYgMTQxLjIyLC02MC41MjcgNDAuMzQsLTQ0LjkzNCA0MS4yNiwtODguMDMyIDQxLjI2LC0xNDMuOTU3IGwgMCwtMTkxLjY1MyA2My4yNywwIDAsLTEwNC41MjcgLTIzOC40LDAgMCwxMDQuNTI3IDYzLjI2LDAgMCwxNTguNjM3IGMgMCwzMC4yNjIgMCw2MS40MzQgLTE5LjI2LDg4LjAzNSAtMjAuMTcsMjYuNTgyIC01My4xOCwzOS40MTQgLTg2LjE5LDM5LjQxNCAtMzMuOTMsMCAtNjguNzcsLTEzLjc1IC04OC45NCwtNDEuMjUgLTIxLjA5LC0yNy41IC0yMS4wOSwtNjkuNjg3IC0yMS4wOSwtMTAyLjcwNyBsIDAsLTE0Mi4xMjkgNjMuMjYsMCAwLC0xMDQuNTI3IC0yMzguNCwwIDAsMTA0LjUyNyA2My4yNywwIDAsMjgwLjU5OCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDMyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA1MDgyLjQ4LDcwMy45NjUgYyAtMTkuMjQsNzAuNjA1IC04MS42LDExNS41NDcgLTE1NC4wNCwxMTUuNTQ3IC02Ni4wNCwwIC0xMjkuMywtNTEuMzQ4IC0xNDMuMDUsLTExNS41NDcgbCAyOTcuMDksMCB6IG0gODUuMjcsLTE0NC44ODMgYyAtMzguNTEsLTkzLjUyMyAtMTI5LjI3LC0xNTYuNzkzIC0yMzEuMDUsLTE1Ni43OTMgLTE0My4wNywwIC0yNTcuNjgsMTExLjg3MSAtMjU3LjY4LDI1NS44MzYgMCwxNDQuODgzIDEwOS4xMiwyNjEuMzI4IDI1NC45MSwyNjEuMzI4IDY3Ljg3LDAgMTM1LjcyLC0zMC4yNTggMTgzLjM5LC03OC44NjMgNDguNjIsLTUxLjM0NCA2OC43OSwtMTEzLjY5NSA2OC43OSwtMTgzLjM4MyBsIC0zLjY3LC0zOS40MzQgLTM5Ni4xMywwIGMgMTQuNjcsLTY3Ljg2MyA3Ny4wMywtMTE3LjM2MyAxNDYuNzIsLTExNy4zNjMgNDguNTksMCA5MC43NiwxOC4zMjggMTE4LjI4LDU4LjY3MiBsIDExNi40NCwwIgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDY5MC44OTUsODUwLjcwMyA5MC43NSwwIDIyLjU0MywzMS4wMzUgMCwyNDMuMTIyIC0xMzUuODI5LDAgMCwtMjQzLjE0MSAyMi41MzYsLTMxLjAxNiIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDM2IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA2MzIuMzk1LDc0Mi4yNTggMjguMDM5LDg2LjMwNCAtMjIuNTUxLDMxLjA0IC0yMzEuMjIzLDc1LjEyOCAtNDEuOTc2LC0xMjkuMTgzIDIzMS4yNTcsLTc1LjEzNyAzNi40NTQsMTEuODQ4IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoMzgiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDcxNy40NDksNjUzLjEwNSAtNzMuNDEsNTMuMzYgLTM2LjQ4OCwtMTEuODc1IC0xNDIuOTAzLC0xOTYuNjkyIDEwOS44ODMsLTc5LjgyOCAxNDIuOTE4LDE5Ni43MDMgMCwzOC4zMzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0MCIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gODI4LjUyLDcwNi40NjUgLTczLjQyNiwtNTMuMzQgMC4wMTEsLTM4LjM1OSBMIDg5OC4wMDQsNDE4LjA3IDEwMDcuOSw0OTcuODk4IDg2NC45NzMsNjk0LjYwOSA4MjguNTIsNzA2LjQ2NSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQyIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA4MTIuMDg2LDgyOC41ODYgMjguMDU1LC04Ni4zMiAzNi40ODQsLTExLjgzNiAyMzEuMjI1LDc1LjExNyAtNDEuOTcsMTI5LjE4MyAtMjMxLjIzOSwtNzUuMTQgLTIyLjU1NSwtMzEuMDA0IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNDQiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDczNi4zMDEsMTMzNS44OCBjIC0zMjMuMDQ3LDAgLTU4NS44NzUsLTI2Mi43OCAtNTg1Ljg3NSwtNTg1Ljc4MiAwLC0zMjMuMTE4IDI2Mi44MjgsLTU4NS45NzcgNTg1Ljg3NSwtNTg1Ljk3NyAzMjMuMDE5LDAgNTg1LjgwOSwyNjIuODU5IDU4NS44MDksNTg1Ljk3NyAwLDMyMy4wMDIgLTI2Mi43OSw1ODUuNzgyIC01ODUuODA5LDU4NS43ODIgbCAwLDAgeiBtIDAsLTExOC42MSBjIDI1Ny45NzIsMCA0NjcuMTg5LC0yMDkuMTMgNDY3LjE4OSwtNDY3LjE3MiAwLC0yNTguMTI5IC0yMDkuMjE3LC00NjcuMzQ4IC00NjcuMTg5LC00NjcuMzQ4IC0yNTguMDc0LDAgLTQ2Ny4yNTQsMjA5LjIxOSAtNDY3LjI1NCw0NjcuMzQ4IDAsMjU4LjA0MiAyMDkuMTgsNDY3LjE3MiA0NjcuMjU0LDQ2Ny4xNzIiCiAgICAgICAgICAgICBpbmtzY2FwZTpjb25uZWN0b3ItY3VydmF0dXJlPSIwIgogICAgICAgICAgICAgaWQ9InBhdGg0NiIKICAgICAgICAgICAgIHN0eWxlPSJmaWxsOiM4YTQxODI7ZmlsbC1vcGFjaXR5OjE7ZmlsbC1ydWxlOm5vbnplcm87c3Ryb2tlOm5vbmUiIC8+PHBhdGgKICAgICAgICAgICAgIGQ9Im0gMTA5MS4xMyw2MTkuODgzIC0xNzUuNzcxLDU3LjEyMSAxMS42MjksMzUuODA4IDE3NS43NjIsLTU3LjEyMSAtMTEuNjIsLTM1LjgwOCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDQ4IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA4NjYuOTU3LDkwMi4wNzQgODM2LjUsOTI0LjE5OSA5NDUuMTIxLDEwNzMuNzMgOTc1LjU4NiwxMDUxLjYxIDg2Ni45NTcsOTAyLjA3NCIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDUwIgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0iTSA2MDcuNDY1LDkwMy40NDUgNDk4Ljg1NSwxMDUyLjk3IDUyOS4zMiwxMDc1LjEgNjM3LjkzLDkyNS41NjYgNjA3LjQ2NSw5MDMuNDQ1IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTIiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjxwYXRoCiAgICAgICAgICAgICBkPSJtIDM4MC42ODgsNjIyLjEyOSAtMTEuNjI2LDM1LjgwMSAxNzUuNzU4LDU3LjA5IDExLjYyMSwtMzUuODAxIC0xNzUuNzUzLC01Ny4wOSIKICAgICAgICAgICAgIGlua3NjYXBlOmNvbm5lY3Rvci1jdXJ2YXR1cmU9IjAiCiAgICAgICAgICAgICBpZD0icGF0aDU0IgogICAgICAgICAgICAgc3R5bGU9ImZpbGw6IzhhNDE4MjtmaWxsLW9wYWNpdHk6MTtmaWxsLXJ1bGU6bm9uemVybztzdHJva2U6bm9uZSIgLz48cGF0aAogICAgICAgICAgICAgZD0ibSA3MTYuMjg5LDM3Ni41OSAzNy42NDA2LDAgMCwxODQuODE2IC0zNy42NDA2LDAgMCwtMTg0LjgxNiB6IgogICAgICAgICAgICAgaW5rc2NhcGU6Y29ubmVjdG9yLWN1cnZhdHVyZT0iMCIKICAgICAgICAgICAgIGlkPSJwYXRoNTYiCiAgICAgICAgICAgICBzdHlsZT0iZmlsbDojOGE0MTgyO2ZpbGwtb3BhY2l0eToxO2ZpbGwtcnVsZTpub256ZXJvO3N0cm9rZTpub25lIiAvPjwvZz48L2c+PC9nPjwvZz48L3N2Zz4=') no-repeat, none; -webkit-background-size: 100%; -moz-background-size: 100%; -o-background-size: 100%; background-size: 100%; display: block; float: left; width: 90px; height: 25px; } 10 | .jasmine_html-reporter .banner .version { margin-left: 14px; position: relative; top: 6px; } 11 | .jasmine_html-reporter .banner .duration { position: absolute; right: 14px; top: 6px; } 12 | .jasmine_html-reporter #jasmine_content { position: fixed; right: 100%; } 13 | .jasmine_html-reporter .version { color: #aaaaaa; } 14 | .jasmine_html-reporter .banner { margin-top: 14px; } 15 | .jasmine_html-reporter .duration { color: #aaaaaa; float: right; } 16 | .jasmine_html-reporter .symbol-summary { overflow: hidden; *zoom: 1; margin: 14px 0; } 17 | .jasmine_html-reporter .symbol-summary li { display: inline-block; height: 8px; width: 14px; font-size: 16px; } 18 | .jasmine_html-reporter .symbol-summary li.passed { font-size: 14px; } 19 | .jasmine_html-reporter .symbol-summary li.passed:before { color: #007069; content: "\02022"; } 20 | .jasmine_html-reporter .symbol-summary li.failed { line-height: 9px; } 21 | .jasmine_html-reporter .symbol-summary li.failed:before { color: #ca3a11; content: "\d7"; font-weight: bold; margin-left: -1px; } 22 | .jasmine_html-reporter .symbol-summary li.disabled { font-size: 14px; } 23 | .jasmine_html-reporter .symbol-summary li.disabled:before { color: #bababa; content: "\02022"; } 24 | .jasmine_html-reporter .symbol-summary li.pending { line-height: 17px; } 25 | .jasmine_html-reporter .symbol-summary li.pending:before { color: #ba9d37; content: "*"; } 26 | .jasmine_html-reporter .symbol-summary li.empty { font-size: 14px; } 27 | .jasmine_html-reporter .symbol-summary li.empty:before { color: #ba9d37; content: "\02022"; } 28 | .jasmine_html-reporter .exceptions { color: #fff; float: right; margin-top: 5px; margin-right: 5px; } 29 | .jasmine_html-reporter .bar { line-height: 28px; font-size: 14px; display: block; color: #eee; } 30 | .jasmine_html-reporter .bar.failed { background-color: #ca3a11; } 31 | .jasmine_html-reporter .bar.passed { background-color: #007069; } 32 | .jasmine_html-reporter .bar.skipped { background-color: #bababa; } 33 | .jasmine_html-reporter .bar.errored { background-color: #ca3a11; } 34 | .jasmine_html-reporter .bar.menu { background-color: #fff; color: #aaaaaa; } 35 | .jasmine_html-reporter .bar.menu a { color: #333333; } 36 | .jasmine_html-reporter .bar a { color: white; } 37 | .jasmine_html-reporter.spec-list .bar.menu.failure-list, .jasmine_html-reporter.spec-list .results .failures { display: none; } 38 | .jasmine_html-reporter.failure-list .bar.menu.spec-list, .jasmine_html-reporter.failure-list .summary { display: none; } 39 | .jasmine_html-reporter .running-alert { background-color: #666666; } 40 | .jasmine_html-reporter .results { margin-top: 14px; } 41 | .jasmine_html-reporter.showDetails .summaryMenuItem { font-weight: normal; text-decoration: inherit; } 42 | .jasmine_html-reporter.showDetails .summaryMenuItem:hover { text-decoration: underline; } 43 | .jasmine_html-reporter.showDetails .detailsMenuItem { font-weight: bold; text-decoration: underline; } 44 | .jasmine_html-reporter.showDetails .summary { display: none; } 45 | .jasmine_html-reporter.showDetails #details { display: block; } 46 | .jasmine_html-reporter .summaryMenuItem { font-weight: bold; text-decoration: underline; } 47 | .jasmine_html-reporter .summary { margin-top: 14px; } 48 | .jasmine_html-reporter .summary ul { list-style-type: none; margin-left: 14px; padding-top: 0; padding-left: 0; } 49 | .jasmine_html-reporter .summary ul.suite { margin-top: 7px; margin-bottom: 7px; } 50 | .jasmine_html-reporter .summary li.passed a { color: #007069; } 51 | .jasmine_html-reporter .summary li.failed a { color: #ca3a11; } 52 | .jasmine_html-reporter .summary li.empty a { color: #ba9d37; } 53 | .jasmine_html-reporter .summary li.pending a { color: #ba9d37; } 54 | .jasmine_html-reporter .description + .suite { margin-top: 0; } 55 | .jasmine_html-reporter .suite { margin-top: 14px; } 56 | .jasmine_html-reporter .suite a { color: #333333; } 57 | .jasmine_html-reporter .failures .spec-detail { margin-bottom: 28px; } 58 | .jasmine_html-reporter .failures .spec-detail .description { background-color: #ca3a11; } 59 | .jasmine_html-reporter .failures .spec-detail .description a { color: white; } 60 | .jasmine_html-reporter .result-message { padding-top: 14px; color: #333333; white-space: pre; } 61 | .jasmine_html-reporter .result-message span.result { display: block; } 62 | .jasmine_html-reporter .stack-trace { margin: 5px 0 0 0; max-height: 224px; overflow: auto; line-height: 18px; color: #666666; border: 1px solid #ddd; background: white; white-space: pre; } 63 | -------------------------------------------------------------------------------- /lib/jasmine-2.1.3/jasmine_favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/amZotti/UnderScore-CoffeeScript/463abf7ce38c959097265174d4af2e3ec9570a10/lib/jasmine-2.1.3/jasmine_favicon.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "UnderScore-CoffeeScript", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "echo \"Error: no test specified\" && exit 1" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "https://github.com/amZotti/UnderScore-CoffeeScript.git" 12 | }, 13 | "author": "", 14 | "license": "ISC", 15 | "bugs": { 16 | "url": "https://github.com/amZotti/UnderScore-CoffeeScript/issues" 17 | }, 18 | "homepage": "https://github.com/amZotti/UnderScore-CoffeeScript", 19 | "devDependencies": { 20 | "grunt-contrib-coffee": "^0.13.0", 21 | "grunt-contrib-watch": "^0.6.1" 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /spec/arraysSpec.coffee: -------------------------------------------------------------------------------- 1 | describe 'arrays', -> 2 | arr = null 3 | beforeEach -> 4 | arr = [5, 4, 3, 2, 1] 5 | 6 | describe '_.first', -> 7 | it 'should return the first element', -> 8 | result = _.first arr; 9 | expect(result).toEqual(5) 10 | 11 | it 'should return the first n elements when n is provided', -> 12 | result = _.first arr, 3 13 | expect(result).toEqual([5, 4, 3]) 14 | 15 | it 'should return all the elements if n exceeds size', -> 16 | result = _.first arr, 20 17 | expect(result).toEqual(arr) 18 | 19 | describe '_.initial', -> 20 | it 'should return all elements except the last', -> 21 | result = _.initial(arr); 22 | expect(result).toEqual([5, 4, 3, 2]) 23 | 24 | it 'should exclude n elements when n is provided', -> 25 | result = _.initial(arr, 2) 26 | expect(result).toEqual([5, 4, 3]) 27 | 28 | it 'should return an empty array if n exceeds size', -> 29 | result = _.initial(arr, 99) 30 | expect(result).toEqual([]) 31 | 32 | describe '_.last', -> 33 | it 'should return the last element', -> 34 | result = _.last(arr) 35 | expect(result).toEqual(1) 36 | 37 | it 'should accept argument n which will return last n elements', -> 38 | result = _.last(arr, 3) 39 | expect(result).toEqual([3, 2, 1]) 40 | 41 | it 'should return the entire array if n exceeds size', -> 42 | result = _.last(arr, 33) 43 | expect(result).toEqual(arr) 44 | 45 | describe '_.rest', -> 46 | it 'should return all elements except first', -> 47 | result = _.rest(arr) 48 | expect(result).toEqual([4, 3, 2, 1]) 49 | 50 | it 'should accept argument index which will return elements onward starting at index', -> 51 | result = _.rest(arr, 3) 52 | expect(result).toEqual([2, 1]) 53 | 54 | it 'should return the empty array if index exceeds size', -> 55 | result = _.rest(arr, 33) 56 | expect(result).toEqual([]) 57 | 58 | describe '_.compact', -> 59 | it 'should return a new array with all falsey values removed', -> 60 | result = _.compact([0, 1, false, 2, '', 3]); 61 | expect(result).toEqual([1, 2, 3]) 62 | 63 | describe '_.flatten', -> 64 | it 'should flatten a nested array', -> 65 | result = _.flatten([1, [2], [3, [[4]]]]) 66 | expect(result).toEqual([1, 2, 3, 4]) 67 | 68 | it 'should flatten only a single level if shallow argument is provided', -> 69 | result = _.flatten([1, [2], [3, [[4]]]], true) 70 | expect(result).toEqual([1, 2, 3, [[4]]]) 71 | 72 | describe '_.without', -> 73 | it 'should return a copy of the array with all instances of the values passed in as arguments removed', -> 74 | result = _.without([1, 2, 1, 0, 3, 1, 4], 0, 1) 75 | expect(result).toEqual([2, 3, 4]) 76 | 77 | describe '_.uniq', -> 78 | it 'should produce a duplicate free version of the array', -> 79 | result = _.uniq([1, 2, 1, 3, 1, 4]) 80 | expect(result).toEqual([1, 2, 3, 4]) 81 | 82 | it 'should compute unique items based on transformation', -> 83 | result = _.uniq(arr, (value) -> value % 2 is 0) 84 | expect(result).toEqual([5, 4]) 85 | 86 | describe '_.union', -> 87 | it 'should return the list of unique items in order they appear in the passed in arrays', -> 88 | result = _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]) 89 | expect(result).toEqual([1, 2, 3, 101, 10]) 90 | 91 | describe '_.zip', -> 92 | it 'should merge together arrays with corresponding positions', -> 93 | result = _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]) 94 | expect(result).toEqual([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]) 95 | 96 | it 'should fill missing values in with undefined', -> 97 | result = _.zip([1,2,3,],['a','b']) 98 | expect(result).toEqual([[1, 'a'], [2, 'b'], [3, undefined]]) 99 | 100 | describe '_.object', -> 101 | it 'should merge an array of keys with an array of values to creates an object', -> 102 | result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]) 103 | expect(result).toEqual({moe: 30, larry: 40, curly: 50}) 104 | 105 | it 'should merge arrays of [key, value] in an array into an object', -> 106 | result = _.object([['moe', 30], ['larry', 40], ['curly', 50]]) 107 | expect(result).toEqual({moe: 30, larry: 40, curly: 50}) 108 | 109 | describe '_.indexOf', -> 110 | it 'should return the first index of the provided value', -> 111 | result = _.indexOf([1, 2, 3], 2) 112 | expect(result).toEqual(1) 113 | 114 | it 'should return -1 if value cannot be found', -> 115 | result = _.indexOf(arr, "barbeque") 116 | expect(result).toEqual(-1) 117 | 118 | describe '_.intersection', -> 119 | it 'should return an array with items that are present in each array arguments', -> 120 | result = _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]) 121 | expect(result).toEqual([1, 2]) 122 | 123 | describe '_.difference', -> 124 | it 'should return values from array that are not present in other arrays', -> 125 | result = _.difference([1, 2, 3, 4, 5], [5, 2, 10]) 126 | expect(result).toEqual([1, 3, 4]) 127 | 128 | describe '_.lastIndexOf', -> 129 | it 'should return the index of the last occurrence of value in the array, or -1 if value is not present', -> 130 | result = _.lastIndexOf([1, 2, 3, 1, 2, 3], 2) 131 | expect(result).toEqual(4) 132 | 133 | describe '_.sortedIndex', -> 134 | it 'should determine where a given value will be inserted in a sorted list', -> 135 | result = _.sortedIndex([10, 20, 30, 40, 50], 35) 136 | expect(result).toEqual(3) 137 | 138 | it 'should determine where a given object will be inserted in a sorted list', -> 139 | stooges = [{name: 'moe', age: 40}, {name: 'curly', age: 60}] 140 | result = _.sortedIndex(stooges, {name: 'larry', age: 50}, 'age') 141 | expect(result).toEqual(1) 142 | 143 | it 'should accept an optional callback which transforms', -> 144 | iteratee = (num) -> 145 | if num % 2 is 0 then num + 10 else num 146 | result = _.sortedIndex([10, 20, 30, 40, 50], 35, iteratee) 147 | expect(result).toEqual(2) 148 | 149 | describe '_.range', -> 150 | it 'should create a range of values provided stop value', -> 151 | expect(_.range(10)).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]) 152 | 153 | it 'should create a range of values provided start and stop values', -> 154 | expect(_.range(1, 11)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]) 155 | 156 | it 'should create a range of values with steps', -> 157 | expect(_.range(0, 30, 5)).toEqual([0, 5, 10, 15, 20, 25]) 158 | 159 | it 'should create a range of negative values', -> 160 | expect(_.range(0, -10, -1)).toEqual([0, -1, -2, -3, -4, -5, -6, -7, -8, -9]) 161 | 162 | it 'should default to empty array', -> 163 | expect(_.range(0)).toEqual([]) 164 | -------------------------------------------------------------------------------- /spec/arraysSpec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | describe('arrays', function() { 3 | var arr; 4 | arr = null; 5 | beforeEach(function() { 6 | return arr = [5, 4, 3, 2, 1]; 7 | }); 8 | describe('_.first', function() { 9 | it('should return the first element', function() { 10 | var result; 11 | result = _.first(arr); 12 | return expect(result).toEqual(5); 13 | }); 14 | it('should return the first n elements when n is provided', function() { 15 | var result; 16 | result = _.first(arr, 3); 17 | return expect(result).toEqual([5, 4, 3]); 18 | }); 19 | return it('should return all the elements if n exceeds size', function() { 20 | var result; 21 | result = _.first(arr, 20); 22 | return expect(result).toEqual(arr); 23 | }); 24 | }); 25 | describe('_.initial', function() { 26 | it('should return all elements except the last', function() { 27 | var result; 28 | result = _.initial(arr); 29 | return expect(result).toEqual([5, 4, 3, 2]); 30 | }); 31 | it('should exclude n elements when n is provided', function() { 32 | var result; 33 | result = _.initial(arr, 2); 34 | return expect(result).toEqual([5, 4, 3]); 35 | }); 36 | return it('should return an empty array if n exceeds size', function() { 37 | var result; 38 | result = _.initial(arr, 99); 39 | return expect(result).toEqual([]); 40 | }); 41 | }); 42 | describe('_.last', function() { 43 | it('should return the last element', function() { 44 | var result; 45 | result = _.last(arr); 46 | return expect(result).toEqual(1); 47 | }); 48 | it('should accept argument n which will return last n elements', function() { 49 | var result; 50 | result = _.last(arr, 3); 51 | return expect(result).toEqual([3, 2, 1]); 52 | }); 53 | return it('should return the entire array if n exceeds size', function() { 54 | var result; 55 | result = _.last(arr, 33); 56 | return expect(result).toEqual(arr); 57 | }); 58 | }); 59 | describe('_.rest', function() { 60 | it('should return all elements except first', function() { 61 | var result; 62 | result = _.rest(arr); 63 | return expect(result).toEqual([4, 3, 2, 1]); 64 | }); 65 | it('should accept argument index which will return elements onward starting at index', function() { 66 | var result; 67 | result = _.rest(arr, 3); 68 | return expect(result).toEqual([2, 1]); 69 | }); 70 | return it('should return the empty array if index exceeds size', function() { 71 | var result; 72 | result = _.rest(arr, 33); 73 | return expect(result).toEqual([]); 74 | }); 75 | }); 76 | describe('_.compact', function() { 77 | return it('should return a new array with all falsey values removed', function() { 78 | var result; 79 | result = _.compact([0, 1, false, 2, '', 3]); 80 | return expect(result).toEqual([1, 2, 3]); 81 | }); 82 | }); 83 | describe('_.flatten', function() { 84 | it('should flatten a nested array', function() { 85 | var result; 86 | result = _.flatten([1, [2], [3, [[4]]]]); 87 | return expect(result).toEqual([1, 2, 3, 4]); 88 | }); 89 | return it('should flatten only a single level if shallow argument is provided', function() { 90 | var result; 91 | result = _.flatten([1, [2], [3, [[4]]]], true); 92 | return expect(result).toEqual([1, 2, 3, [[4]]]); 93 | }); 94 | }); 95 | describe('_.without', function() { 96 | return it('should return a copy of the array with all instances of the values passed in as arguments removed', function() { 97 | var result; 98 | result = _.without([1, 2, 1, 0, 3, 1, 4], 0, 1); 99 | return expect(result).toEqual([2, 3, 4]); 100 | }); 101 | }); 102 | describe('_.uniq', function() { 103 | it('should produce a duplicate free version of the array', function() { 104 | var result; 105 | result = _.uniq([1, 2, 1, 3, 1, 4]); 106 | return expect(result).toEqual([1, 2, 3, 4]); 107 | }); 108 | return it('should compute unique items based on transformation', function() { 109 | var result; 110 | result = _.uniq(arr, function(value) { 111 | return value % 2 === 0; 112 | }); 113 | return expect(result).toEqual([5, 4]); 114 | }); 115 | }); 116 | describe('_.union', function() { 117 | return it('should return the list of unique items in order they appear in the passed in arrays', function() { 118 | var result; 119 | result = _.union([1, 2, 3], [101, 2, 1, 10], [2, 1]); 120 | return expect(result).toEqual([1, 2, 3, 101, 10]); 121 | }); 122 | }); 123 | describe('_.zip', function() { 124 | it('should merge together arrays with corresponding positions', function() { 125 | var result; 126 | result = _.zip(['moe', 'larry', 'curly'], [30, 40, 50], [true, false, false]); 127 | return expect(result).toEqual([["moe", 30, true], ["larry", 40, false], ["curly", 50, false]]); 128 | }); 129 | return it('should fill missing values in with undefined', function() { 130 | var result; 131 | result = _.zip([1, 2, 3], ['a', 'b']); 132 | return expect(result).toEqual([[1, 'a'], [2, 'b'], [3, void 0]]); 133 | }); 134 | }); 135 | describe('_.object', function() { 136 | it('should merge an array of keys with an array of values to creates an object', function() { 137 | var result; 138 | result = _.object(['moe', 'larry', 'curly'], [30, 40, 50]); 139 | return expect(result).toEqual({ 140 | moe: 30, 141 | larry: 40, 142 | curly: 50 143 | }); 144 | }); 145 | return it('should merge arrays of [key, value] in an array into an object', function() { 146 | var result; 147 | result = _.object([['moe', 30], ['larry', 40], ['curly', 50]]); 148 | return expect(result).toEqual({ 149 | moe: 30, 150 | larry: 40, 151 | curly: 50 152 | }); 153 | }); 154 | }); 155 | describe('_.indexOf', function() { 156 | it('should return the first index of the provided value', function() { 157 | var result; 158 | result = _.indexOf([1, 2, 3], 2); 159 | return expect(result).toEqual(1); 160 | }); 161 | return it('should return -1 if value cannot be found', function() { 162 | var result; 163 | result = _.indexOf(arr, "barbeque"); 164 | return expect(result).toEqual(-1); 165 | }); 166 | }); 167 | describe('_.intersection', function() { 168 | return it('should return an array with items that are present in each array arguments', function() { 169 | var result; 170 | result = _.intersection([1, 2, 3], [101, 2, 1, 10], [2, 1]); 171 | return expect(result).toEqual([1, 2]); 172 | }); 173 | }); 174 | describe('_.difference', function() {}); 175 | it('should return values from array that are not present in other arrays', function() { 176 | var result; 177 | result = _.difference([1, 2, 3, 4, 5], [5, 2, 10]); 178 | return expect(result).toEqual([1, 3, 4]); 179 | }); 180 | describe('_.lastIndexOf', function() { 181 | return it('should return the index of the last occurrence of value in the array, or -1 if value is not present', function() { 182 | var result; 183 | result = _.lastIndexOf([1, 2, 3, 1, 2, 3], 2); 184 | return expect(result).toEqual(4); 185 | }); 186 | }); 187 | describe('_.sortedIndex', function() { 188 | it('should determine where a given value will be inserted in a sorted list', function() { 189 | var result; 190 | result = _.sortedIndex([10, 20, 30, 40, 50], 35); 191 | return expect(result).toEqual(3); 192 | }); 193 | it('should determine where a given object will be inserted in a sorted list', function() { 194 | var result, stooges; 195 | stooges = [ 196 | { 197 | name: 'moe', 198 | age: 40 199 | }, { 200 | name: 'curly', 201 | age: 60 202 | } 203 | ]; 204 | result = _.sortedIndex(stooges, { 205 | name: 'larry', 206 | age: 50 207 | }, 'age'); 208 | return expect(result).toEqual(1); 209 | }); 210 | return it('should accept an optional callback which transforms', function() { 211 | var iteratee, result; 212 | iteratee = function(num) { 213 | if (num % 2 === 0) { 214 | return num + 10; 215 | } else { 216 | return num; 217 | } 218 | }; 219 | result = _.sortedIndex([10, 20, 30, 40, 50], 35, iteratee); 220 | return expect(result).toEqual(2); 221 | }); 222 | }); 223 | return describe('_.range', function() { 224 | it('should create a range of values provided stop value', function() { 225 | return expect(_.range(10)).toEqual([0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); 226 | }); 227 | it('should create a range of values provided start and stop values', function() { 228 | return expect(_.range(1, 11)).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 9, 10]); 229 | }); 230 | it('should create a range of values with steps', function() { 231 | return expect(_.range(0, 30, 5)).toEqual([0, 5, 10, 15, 20, 25]); 232 | }); 233 | it('should create a range of negative values', function() { 234 | return expect(_.range(0, -10, -1)).toEqual([0, -1, -2, -3, -4, -5, -6, -7, -8, -9]); 235 | }); 236 | return it('should default to empty array', function() { 237 | return expect(_.range(0)).toEqual([]); 238 | }); 239 | }); 240 | }); 241 | 242 | }).call(this); 243 | -------------------------------------------------------------------------------- /spec/chainingSpec.coffee: -------------------------------------------------------------------------------- 1 | describe "chain", -> 2 | 3 | stooges = [ 4 | {name: 'curly', age: 25}, 5 | {name: 'moe', age: 21}, 6 | {name: 'larry', age: 23} 7 | ] 8 | 9 | youngest = _.chain(stooges) 10 | .sortBy((stooge) -> stooge.age) 11 | .map((stooge) -> "#{stooge.name} is #{stooge.age}") 12 | .first() 13 | 14 | it "should return a wrapped object", -> 15 | expect(typeof youngest).toEqual("object") 16 | 17 | it "calling value() should return result of method chaining", -> 18 | expect(youngest.value()).toEqual("moe is 21") 19 | 20 | 21 | -------------------------------------------------------------------------------- /spec/chainingSpec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | describe("chain", function() { 3 | var stooges, youngest; 4 | stooges = [ 5 | { 6 | name: 'curly', 7 | age: 25 8 | }, { 9 | name: 'moe', 10 | age: 21 11 | }, { 12 | name: 'larry', 13 | age: 23 14 | } 15 | ]; 16 | youngest = _.chain(stooges).sortBy(function(stooge) { 17 | return stooge.age; 18 | }).map(function(stooge) { 19 | return stooge.name + " is " + stooge.age; 20 | }).first(); 21 | it("should return a wrapped object", function() { 22 | return expect(typeof youngest).toEqual("object"); 23 | }); 24 | return it("calling value() should return result of method chaining", function() { 25 | return expect(youngest.value()).toEqual("moe is 21"); 26 | }); 27 | }); 28 | 29 | }).call(this); 30 | -------------------------------------------------------------------------------- /spec/collectionsSpec.coffee: -------------------------------------------------------------------------------- 1 | obj = 2 | a: 1 3 | b: 2 4 | c: 3 5 | 6 | describe "each", -> 7 | it "should apply the function to every value in array", -> 8 | arr = [1, 2, 3] 9 | newArr = [] 10 | _.each(arr, (element, index) -> newArr[index] = element + 1) 11 | expect(newArr[0]).toEqual(2) 12 | 13 | it "should apply the function to every value in object", -> 14 | 15 | newObj = {} 16 | _.each(obj, (value, key) -> newObj[key] = value + 1) 17 | expect(newObj['a']).toEqual(2) 18 | 19 | it "should apply the function in the context of the object passed in", -> 20 | arr = [1, 2, 3] 21 | results = {} 22 | _.each(arr, ((value, index) -> this[index] = value), results) 23 | expect(results).toEqual({0: 1, 1: 2, 2: 3}) 24 | 25 | describe "map", -> 26 | it "shoud return a new array with the provided function applied to each element of an array", -> 27 | arr = [1, 2, 3] 28 | newArr = _.map(arr, (element, index) -> element * 2) 29 | expect(newArr).toEqual([2,4,6]) 30 | 31 | it "should return an array with the provided function applied to each value of an object", -> 32 | newArr = _.map(obj, (value, key) -> obj[key] = obj[key] * 2) 33 | expect(newArr).toEqual([2,4,6]) 34 | 35 | it "should apply the function in the context of the object passed in", -> 36 | arr = [1, 2, 3] 37 | results = {} 38 | _.map(arr, ((value, index) -> this[index] = value), results) 39 | expect(results).toEqual({0: 1, 1: 2, 2: 3}) 40 | 41 | describe "reduce", -> 42 | arr = [] 43 | startingValue = 10 44 | arrayCallback = (startingValue, element, index, arr) -> 45 | startingValue += element 46 | 47 | beforeEach -> arr = [1, 2, 3] 48 | 49 | it "should reduce all elements of an array into one by applying the provided function", -> 50 | result = _.reduce(arr, arrayCallback) 51 | expect(result).toEqual(6) 52 | 53 | it "should reduce all values of an object into one by applying the provided function", -> 54 | obj = 55 | a: 1 56 | b: 2 57 | c: 3 58 | 59 | objCallback = (startingValue, value, key, obj) -> startingValue += value 60 | 61 | result = _.reduce(obj, objCallback) 62 | expect(result).toEqual(6) 63 | 64 | it "should reduce correctly when provided a starting value", -> 65 | result = _.reduce(arr, arrayCallback, startingValue) 66 | expect(result).toEqual(16) 67 | 68 | it "should apply the function in the context of the object passed in", -> 69 | context = {} 70 | contextCallback = (startingValue, element, index, arr) -> 71 | startingValue += element 72 | this.value = startingValue 73 | _.reduce(arr, contextCallback, startingValue, context) 74 | expect(context.value).toEqual(16) 75 | 76 | describe "reduceRight", -> 77 | it "should reduce values in list from right to left", -> 78 | list = [[0, 1], [2, 3], [4, 5]]; 79 | flat = _.reduceRight(list, ((a, b) -> a.concat(b)), []); 80 | expect(flat).toEqual([4, 5, 2, 3, 0, 1]) 81 | 82 | describe "find", -> 83 | callback = (num)-> num % 2 is 0 84 | 85 | it "should return the first element in an array which passes the provided predicate callback", -> 86 | arr = [1, 3, 5, 8, 10, 7, 6] 87 | result = _.find(arr, callback) 88 | expect(result).toEqual(8) 89 | 90 | it "should return the first value in an object which passes the provided predicate callback", -> 91 | result = _.find(obj, callback) 92 | expect(result).toEqual(2) 93 | 94 | it "should return undefined if predicate fails every element in array", -> 95 | arr = [1, 3, 5] 96 | result = _.find(arr, callback) 97 | expect(result).toEqual(undefined) 98 | 99 | describe "filter", -> 100 | callback = (num) -> num % 2 is 0 101 | 102 | it "should return all array elements in an array which pass the provided predicate callback", -> 103 | arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] 104 | result = _.filter(arr, callback) 105 | expect(result).toEqual([2, 4, 6, 8, 10]) 106 | 107 | it "should return all object values in an array which pass the provided predicate callback", -> 108 | obj = 109 | a: 1 110 | b: 2 111 | c: 3 112 | d: 4 113 | f: 5 114 | g: 6 115 | 116 | result = _.filter(obj, callback) 117 | expect(result).toEqual([2, 4, 6]) 118 | 119 | describe "where", -> 120 | arrayOfHomes = [ 121 | {location: "Paris Island", age: 18} 122 | {location: "29 Palms", age: 18} 123 | {location: "Camp Lejeune", age: 19} 124 | {location: "Iraq", age: 20} 125 | {location: "Camp Lejeune", age: 20} 126 | {location: "Mesa Verda", age: 22} 127 | ] 128 | 129 | objectOfHomes = 130 | a: {location: "Paris Island", age: 18} 131 | b: {location: "29 Palms", age: 18} 132 | c: {location: "Camp Lejeune", age: 19} 133 | d: {location: "Iraq", age: 20} 134 | e: {location: "Camp Lejeune", age: 20} 135 | f: {location: "Mesa Verda", age: 22} 136 | 137 | it "should returns all matching key/value pairs from array of objects", -> 138 | result = _.where(arrayOfHomes, {age: 18}) 139 | expect(result).toEqual([{location: "Paris Island", age: 18}, {location: "29 Palms", age: 18}]) 140 | 141 | it "should returns all matching key/value pairs from an object of objects", -> 142 | result = _.where(objectOfHomes, {age: 18}) 143 | expect(result).toEqual([{location: "Paris Island", age: 18}, {location: "29 Palms", age: 18}]) 144 | 145 | it "should return an empty array when there are no matches", -> 146 | result = _.where(arrayOfHomes, {age: 28}) 147 | expect(result).toEqual([]) 148 | 149 | 150 | describe "findWhere", -> 151 | arrayOfHomes = [ 152 | {location: "Paris Island", age: 18} 153 | {location: "29 Palms", age: 18} 154 | {location: "Camp Lejeune", age: 19} 155 | {location: "Iraq", age: 20} 156 | {location: "Camp Lejeune", age: 20} 157 | {location: "Mesa Verda", age: 22} 158 | ] 159 | 160 | objectOfHomes = 161 | a: {location: "Paris Island", age: 18} 162 | b: {location: "29 Palms", age: 18} 163 | c: {location: "Camp Lejeune", age: 19} 164 | d: {location: "Iraq", age: 20} 165 | e: {location: "Camp Lejeune", age: 20} 166 | f: {location: "Mesa Verda", age: 22} 167 | 168 | it "should return the first matching key/value pairs from array of objects", -> 169 | result = _.findWhere(arrayOfHomes, {age: 18}) 170 | expect(result).toEqual({location: "Paris Island", age: 18}) 171 | 172 | it "should return the first matching key/value pairs from an object of objects", -> 173 | result = _.findWhere(objectOfHomes, {age: 18}) 174 | expect(result).toEqual({location: "Paris Island", age: 18}) 175 | 176 | it "should return undefined when there are no matches", -> 177 | result = _.findWhere(arrayOfHomes, {age: 28}) 178 | expect(result).toEqual(undefined) 179 | 180 | describe "reject", -> 181 | 182 | arr = [1, 2, 3, 4, 5, 6] 183 | rejectObj = {a: 1, b: 2, c: 3, d: 4} 184 | callback = (value) -> value % 2 is 0 185 | 186 | it "should return only values from array which fail the predicate callback", -> 187 | result = _.reject(arr, callback) 188 | expect(result).toEqual([1, 3, 5]) 189 | 190 | it "should return only values from object which fail the predicate callback", -> 191 | result = _.reject(rejectObj, callback) 192 | expect(result).toEqual([1, 3]) 193 | 194 | describe "every", -> 195 | 196 | everyArr1 = [1, 2, 3, 4, 5, 6] 197 | everyArr2 = [2, 4, 6] 198 | everyObj1 = {a: 1, b: 2, c: 3, d: 4} 199 | everyObj2 = {a: 2, b: 4, c: 6} 200 | callback = (value) -> value % 2 is 0 201 | 202 | it "should return false if a single value in array fails predicate callback", -> 203 | result = _.every(everyArr1, callback) 204 | expect(result).toBe(false) 205 | 206 | it "should return true only if all values in array pass predicate callback", -> 207 | result = _.every(everyArr2, callback) 208 | expect(result).toBe(true) 209 | 210 | it "should return false if a single value in object fails predicate callback", -> 211 | result = _.every(everyObj1, callback) 212 | expect(result).toBe(false) 213 | 214 | it "should return true only if all values in object pass predicate callback", -> 215 | result = _.every(everyObj2, callback) 216 | expect(result).toBe(true) 217 | 218 | describe "some", -> 219 | 220 | someArr1 = [1, 2, 3, 4, 5, 6] 221 | someArr2 = [1, 3, 5] 222 | someObj1 = {a: 1, b: 2, c: 3, d: 4} 223 | someObj2 = {a: 1, b: 3, c: 9} 224 | callback = (value) -> value % 2 is 0 225 | 226 | it "should return true if any of the values in the array evaluate to true when passed predicate callback", -> 227 | result = _.some(someArr1, callback) 228 | expect(result).toBe(true) 229 | 230 | it "should return false if all values in array evaluate to false when passed predicate callback", -> 231 | result = _.some(someArr2, callback) 232 | expect(result).toBe(false) 233 | 234 | it "should return true if any of the values in the object evaluate to true when passed predicate callback", -> 235 | result = _.some(someObj1, callback) 236 | expect(result).toBe(true) 237 | 238 | it "should return false if all values in object evaluate to false when passed predicate callback", -> 239 | result = _.some(someObj2, callback) 240 | expect(result).toBe(false) 241 | 242 | describe "contains", -> 243 | 244 | containsArr = [1, 2, 3] 245 | containsObj = {a: 1, b: 2, c: 4} 246 | 247 | it "should return true if the value is in the array", -> 248 | result = _.contains(containsArr, 2) 249 | expect(result).toBe(true) 250 | 251 | it "should return false if the value is not in the array", -> 252 | result = _.contains(containsArr, 99) 253 | expect(result).toBe(false) 254 | 255 | it "should return true if the value is in the object", -> 256 | result = _.contains(containsObj, 2) 257 | expect(result).toBe(true) 258 | 259 | it "should return false if the value is not in the object", -> 260 | result = _.contains(containsObj, 99) 261 | expect(result).toBe(false) 262 | 263 | describe "invoke", -> 264 | 265 | it "should call sort method on each element in an array and return results in an array", -> 266 | result = _.invoke([[5, 1, 7], [3, 2, 1]], "sort"); 267 | expect(result).toEqual([[1, 5, 7], [1, 2, 3]]) 268 | 269 | it "should call sort method on each value in an object and return results in an array", -> 270 | result = _.invoke({a: [5, 1, 7], b: [3, 2, 66]}, "sort") 271 | expect(result).toEqual([[1, 5, 7], [2, 3, 66]]) 272 | 273 | it "should pass extra arguments onto method invocation", -> 274 | result = _.invoke(["lol"], "concat", "bbq") 275 | expect(result).toEqual(["lolbbq"]) 276 | 277 | describe "pluck", -> 278 | 279 | it "should extract property value from each object in array container", -> 280 | arr = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}] 281 | result = _.pluck(arr, 'name') 282 | expect(result).toEqual(["moe", "larry", "curly"]) 283 | 284 | it "should extract property value from each object in object container", -> 285 | obj = {a: {name: 'moe', age: 40}, b: {name: 'larry', age: 50}, c: {name: 'curly', age: 60}} 286 | result = _.pluck(obj, 'name') 287 | expect(result).toEqual(["moe", "larry", "curly"]) 288 | 289 | describe "max", -> 290 | 291 | it "should return the maximum value in the container when passed into a callback", -> 292 | stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; 293 | result = _.max(stooges, (stooge) -> stooge.age); 294 | expect(result).toEqual({name: 'curly', age: 60}) 295 | 296 | it "should return the maximum value in the container when not passed a callback", -> 297 | result = _.max([54, 43, 12, 455, 12]) 298 | expect(result).toEqual(455) 299 | 300 | it "should evaluate to infinity if container is empty", -> 301 | result = _.max([], ->) 302 | expect(result).toEqual(Number.POSITIVE_INFINITY) 303 | 304 | describe "min", -> 305 | 306 | it "should return the minimum value in the container when passed into a callback", -> 307 | stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; 308 | result = _.min(stooges, (stooge) -> stooge.age); 309 | expect(result).toEqual({name: 'moe', age: 40}) 310 | 311 | it "should return the minimum value in the container when not passed a callback", -> 312 | result = _.min([54, 43, 12, 455, 12]) 313 | expect(result).toEqual(12) 314 | 315 | it "should evaluate to infinity if container is empty", -> 316 | result = _.min([], ->) 317 | expect(result).toEqual(Number.POSITIVE_INFINITY) 318 | 319 | describe "sortBy", -> 320 | it "should sort arrays in ascending order", -> 321 | result = _.sortBy([1, 2, 3, 4, 5, 6], (num) -> Math.sin(num)) 322 | expect(result).toEqual([5, 4, 6, 3, 1, 2]) 323 | 324 | it "should sort objects in ascending order and return contents in array", -> 325 | result = _.sortBy({ a: {age: 5}, b: {age: 222}, c: {age: 1}}, (value) -> value.age ) 326 | expect(result).toEqual([{"age":1},{"age":5},{"age":222}]) 327 | 328 | describe "groupBy", -> 329 | it "should split a collection into sets, grouped by result of running each through the callback", -> 330 | result = _.groupBy([1.3, 2.1, 2.4], (num) -> Math.floor(num)) 331 | expect(result).toEqual({1: [1.3], 2: [2.1, 2.4]}) 332 | 333 | it "should split a collection into sets, grouped by result of a mutual property on each object", -> 334 | result = _.groupBy(['one', 'two', 'three'], 'length') 335 | expect(result).toEqual({3: ["one", "two"], 5: ["three"]}) 336 | 337 | describe "indexBy", -> 338 | it "should split a collection into objects, organized by a property value or callback", -> 339 | stooges = [{name: 'moe', age: 40}, {name: 'larry', age: 50}, {name: 'curly', age: 60}]; 340 | result = _.indexBy(stooges, 'age') 341 | expect(result).toEqual({"40": {name: 'moe', age: 40}, "50": {name: 'larry', age: 50}, "60": {name: 'curly', age: 60}}) 342 | 343 | describe "countBy", -> 344 | it "should split collection into groups and return a count for the number of values in each group.", -> 345 | result = _.countBy [1, 2, 3, 4, 5], (num) -> if num % 2 is 0 then 'even' else 'odd' 346 | expect(result).toEqual({odd: 3, even: 2}) 347 | 348 | describe "shuffle", -> 349 | it "should randomize an array of values", -> 350 | arr = [1, 2, 3, 4, 5, 6] 351 | result = _.shuffle(arr) 352 | expect(result).not.toEqual(arr) 353 | 354 | it "should randomize an object of values", -> 355 | obj = {a: [1,2,3], b: 'fefe', c: 242} 356 | result = _.shuffle(obj) 357 | expect(result).not.toEqual(obj) 358 | 359 | describe "sample", -> 360 | it "should return a random value from the array", -> 361 | arr = [1,2,3,4,5,6] 362 | result = _.sample(arr) 363 | expect(result).not.toEqual(undefined) 364 | 365 | it "should return a random value from the object", -> 366 | obj = {a: 1, b: 2, c: 3} 367 | result = _.sample(obj) 368 | expect(result).not.toEqual(undefined) 369 | 370 | it "should return n random values from the array when passed n as an argument", -> 371 | arr = [1,2,3,4,5,6] 372 | result = _.sample(arr, 3) 373 | expect(result.length).toEqual(3) 374 | 375 | describe "toArray", -> 376 | it "should create a real array from the arguments psuedo-array", -> 377 | result = (-> _.toArray(arguments).slice(1))(1, 2, 3, 4) 378 | expect(result).toEqual([2, 3, 4]) 379 | 380 | it "should create a real array from an object", -> 381 | result = _.toArray({a: 1, b: 2, c: 3}) 382 | expect(result).toEqual([1, 2, 3]) 383 | 384 | describe "size", -> 385 | it "should return the number of values in a list", -> 386 | result = _.size({one: 1, two: 2, three: 3}); 387 | expect(result).toEqual(3) 388 | 389 | describe "partition", -> 390 | it "should split array into two arrays: one whose elements all satisfy predicate and one whose elements all do not satisfy predicate.", -> 391 | result = _.partition([0, 1, 2, 3, 4, 5], (value) -> value % 2 is 1); 392 | expect(result).toEqual([[1, 3, 5], [0, 2, 4]]) 393 | -------------------------------------------------------------------------------- /spec/collectionsSpec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var obj; 3 | 4 | obj = { 5 | a: 1, 6 | b: 2, 7 | c: 3 8 | }; 9 | 10 | describe("each", function() { 11 | it("should apply the function to every value in array", function() { 12 | var arr, newArr; 13 | arr = [1, 2, 3]; 14 | newArr = []; 15 | _.each(arr, function(element, index) { 16 | return newArr[index] = element + 1; 17 | }); 18 | return expect(newArr[0]).toEqual(2); 19 | }); 20 | it("should apply the function to every value in object", function() { 21 | var newObj; 22 | newObj = {}; 23 | _.each(obj, function(value, key) { 24 | return newObj[key] = value + 1; 25 | }); 26 | return expect(newObj['a']).toEqual(2); 27 | }); 28 | return it("should apply the function in the context of the object passed in", function() { 29 | var arr, results; 30 | arr = [1, 2, 3]; 31 | results = {}; 32 | _.each(arr, (function(value, index) { 33 | return this[index] = value; 34 | }), results); 35 | return expect(results).toEqual({ 36 | 0: 1, 37 | 1: 2, 38 | 2: 3 39 | }); 40 | }); 41 | }); 42 | 43 | describe("map", function() { 44 | it("shoud return a new array with the provided function applied to each element of an array", function() { 45 | var arr, newArr; 46 | arr = [1, 2, 3]; 47 | newArr = _.map(arr, function(element, index) { 48 | return element * 2; 49 | }); 50 | return expect(newArr).toEqual([2, 4, 6]); 51 | }); 52 | it("should return an array with the provided function applied to each value of an object", function() { 53 | var newArr; 54 | newArr = _.map(obj, function(value, key) { 55 | return obj[key] = obj[key] * 2; 56 | }); 57 | return expect(newArr).toEqual([2, 4, 6]); 58 | }); 59 | return it("should apply the function in the context of the object passed in", function() { 60 | var arr, results; 61 | arr = [1, 2, 3]; 62 | results = {}; 63 | _.map(arr, (function(value, index) { 64 | return this[index] = value; 65 | }), results); 66 | return expect(results).toEqual({ 67 | 0: 1, 68 | 1: 2, 69 | 2: 3 70 | }); 71 | }); 72 | }); 73 | 74 | describe("reduce", function() { 75 | var arr, arrayCallback, startingValue; 76 | arr = []; 77 | startingValue = 10; 78 | arrayCallback = function(startingValue, element, index, arr) { 79 | return startingValue += element; 80 | }; 81 | beforeEach(function() { 82 | return arr = [1, 2, 3]; 83 | }); 84 | it("should reduce all elements of an array into one by applying the provided function", function() { 85 | var result; 86 | result = _.reduce(arr, arrayCallback); 87 | return expect(result).toEqual(6); 88 | }); 89 | it("should reduce all values of an object into one by applying the provided function", function() { 90 | var objCallback, result; 91 | obj = { 92 | a: 1, 93 | b: 2, 94 | c: 3 95 | }; 96 | objCallback = function(startingValue, value, key, obj) { 97 | return startingValue += value; 98 | }; 99 | result = _.reduce(obj, objCallback); 100 | return expect(result).toEqual(6); 101 | }); 102 | it("should reduce correctly when provided a starting value", function() { 103 | var result; 104 | result = _.reduce(arr, arrayCallback, startingValue); 105 | return expect(result).toEqual(16); 106 | }); 107 | return it("should apply the function in the context of the object passed in", function() { 108 | var context, contextCallback; 109 | context = {}; 110 | contextCallback = function(startingValue, element, index, arr) { 111 | startingValue += element; 112 | return this.value = startingValue; 113 | }; 114 | _.reduce(arr, contextCallback, startingValue, context); 115 | return expect(context.value).toEqual(16); 116 | }); 117 | }); 118 | 119 | describe("reduceRight", function() { 120 | return it("should reduce values in list from right to left", function() { 121 | var flat, list; 122 | list = [[0, 1], [2, 3], [4, 5]]; 123 | flat = _.reduceRight(list, (function(a, b) { 124 | return a.concat(b); 125 | }), []); 126 | return expect(flat).toEqual([4, 5, 2, 3, 0, 1]); 127 | }); 128 | }); 129 | 130 | describe("find", function() { 131 | var callback; 132 | callback = function(num) { 133 | return num % 2 === 0; 134 | }; 135 | it("should return the first element in an array which passes the provided predicate callback", function() { 136 | var arr, result; 137 | arr = [1, 3, 5, 8, 10, 7, 6]; 138 | result = _.find(arr, callback); 139 | return expect(result).toEqual(8); 140 | }); 141 | it("should return the first value in an object which passes the provided predicate callback", function() { 142 | var result; 143 | result = _.find(obj, callback); 144 | return expect(result).toEqual(2); 145 | }); 146 | return it("should return undefined if predicate fails every element in array", function() { 147 | var arr, result; 148 | arr = [1, 3, 5]; 149 | result = _.find(arr, callback); 150 | return expect(result).toEqual(void 0); 151 | }); 152 | }); 153 | 154 | describe("filter", function() { 155 | var callback; 156 | callback = function(num) { 157 | return num % 2 === 0; 158 | }; 159 | it("should return all array elements in an array which pass the provided predicate callback", function() { 160 | var arr, result; 161 | arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; 162 | result = _.filter(arr, callback); 163 | return expect(result).toEqual([2, 4, 6, 8, 10]); 164 | }); 165 | return it("should return all object values in an array which pass the provided predicate callback", function() { 166 | var result; 167 | obj = { 168 | a: 1, 169 | b: 2, 170 | c: 3, 171 | d: 4, 172 | f: 5, 173 | g: 6 174 | }; 175 | result = _.filter(obj, callback); 176 | return expect(result).toEqual([2, 4, 6]); 177 | }); 178 | }); 179 | 180 | describe("where", function() { 181 | var arrayOfHomes, objectOfHomes; 182 | arrayOfHomes = [ 183 | { 184 | location: "Paris Island", 185 | age: 18 186 | }, { 187 | location: "29 Palms", 188 | age: 18 189 | }, { 190 | location: "Camp Lejeune", 191 | age: 19 192 | }, { 193 | location: "Iraq", 194 | age: 20 195 | }, { 196 | location: "Camp Lejeune", 197 | age: 20 198 | }, { 199 | location: "Mesa Verda", 200 | age: 22 201 | } 202 | ]; 203 | objectOfHomes = { 204 | a: { 205 | location: "Paris Island", 206 | age: 18 207 | }, 208 | b: { 209 | location: "29 Palms", 210 | age: 18 211 | }, 212 | c: { 213 | location: "Camp Lejeune", 214 | age: 19 215 | }, 216 | d: { 217 | location: "Iraq", 218 | age: 20 219 | }, 220 | e: { 221 | location: "Camp Lejeune", 222 | age: 20 223 | }, 224 | f: { 225 | location: "Mesa Verda", 226 | age: 22 227 | } 228 | }; 229 | it("should returns all matching key/value pairs from array of objects", function() { 230 | var result; 231 | result = _.where(arrayOfHomes, { 232 | age: 18 233 | }); 234 | return expect(result).toEqual([ 235 | { 236 | location: "Paris Island", 237 | age: 18 238 | }, { 239 | location: "29 Palms", 240 | age: 18 241 | } 242 | ]); 243 | }); 244 | it("should returns all matching key/value pairs from an object of objects", function() { 245 | var result; 246 | result = _.where(objectOfHomes, { 247 | age: 18 248 | }); 249 | return expect(result).toEqual([ 250 | { 251 | location: "Paris Island", 252 | age: 18 253 | }, { 254 | location: "29 Palms", 255 | age: 18 256 | } 257 | ]); 258 | }); 259 | return it("should return an empty array when there are no matches", function() { 260 | var result; 261 | result = _.where(arrayOfHomes, { 262 | age: 28 263 | }); 264 | return expect(result).toEqual([]); 265 | }); 266 | }); 267 | 268 | describe("findWhere", function() { 269 | var arrayOfHomes, objectOfHomes; 270 | arrayOfHomes = [ 271 | { 272 | location: "Paris Island", 273 | age: 18 274 | }, { 275 | location: "29 Palms", 276 | age: 18 277 | }, { 278 | location: "Camp Lejeune", 279 | age: 19 280 | }, { 281 | location: "Iraq", 282 | age: 20 283 | }, { 284 | location: "Camp Lejeune", 285 | age: 20 286 | }, { 287 | location: "Mesa Verda", 288 | age: 22 289 | } 290 | ]; 291 | objectOfHomes = { 292 | a: { 293 | location: "Paris Island", 294 | age: 18 295 | }, 296 | b: { 297 | location: "29 Palms", 298 | age: 18 299 | }, 300 | c: { 301 | location: "Camp Lejeune", 302 | age: 19 303 | }, 304 | d: { 305 | location: "Iraq", 306 | age: 20 307 | }, 308 | e: { 309 | location: "Camp Lejeune", 310 | age: 20 311 | }, 312 | f: { 313 | location: "Mesa Verda", 314 | age: 22 315 | } 316 | }; 317 | it("should return the first matching key/value pairs from array of objects", function() { 318 | var result; 319 | result = _.findWhere(arrayOfHomes, { 320 | age: 18 321 | }); 322 | return expect(result).toEqual({ 323 | location: "Paris Island", 324 | age: 18 325 | }); 326 | }); 327 | it("should return the first matching key/value pairs from an object of objects", function() { 328 | var result; 329 | result = _.findWhere(objectOfHomes, { 330 | age: 18 331 | }); 332 | return expect(result).toEqual({ 333 | location: "Paris Island", 334 | age: 18 335 | }); 336 | }); 337 | return it("should return undefined when there are no matches", function() { 338 | var result; 339 | result = _.findWhere(arrayOfHomes, { 340 | age: 28 341 | }); 342 | return expect(result).toEqual(void 0); 343 | }); 344 | }); 345 | 346 | describe("reject", function() { 347 | var arr, callback, rejectObj; 348 | arr = [1, 2, 3, 4, 5, 6]; 349 | rejectObj = { 350 | a: 1, 351 | b: 2, 352 | c: 3, 353 | d: 4 354 | }; 355 | callback = function(value) { 356 | return value % 2 === 0; 357 | }; 358 | it("should return only values from array which fail the predicate callback", function() { 359 | var result; 360 | result = _.reject(arr, callback); 361 | return expect(result).toEqual([1, 3, 5]); 362 | }); 363 | return it("should return only values from object which fail the predicate callback", function() { 364 | var result; 365 | result = _.reject(rejectObj, callback); 366 | return expect(result).toEqual([1, 3]); 367 | }); 368 | }); 369 | 370 | describe("every", function() { 371 | var callback, everyArr1, everyArr2, everyObj1, everyObj2; 372 | everyArr1 = [1, 2, 3, 4, 5, 6]; 373 | everyArr2 = [2, 4, 6]; 374 | everyObj1 = { 375 | a: 1, 376 | b: 2, 377 | c: 3, 378 | d: 4 379 | }; 380 | everyObj2 = { 381 | a: 2, 382 | b: 4, 383 | c: 6 384 | }; 385 | callback = function(value) { 386 | return value % 2 === 0; 387 | }; 388 | it("should return false if a single value in array fails predicate callback", function() { 389 | var result; 390 | result = _.every(everyArr1, callback); 391 | return expect(result).toBe(false); 392 | }); 393 | it("should return true only if all values in array pass predicate callback", function() { 394 | var result; 395 | result = _.every(everyArr2, callback); 396 | return expect(result).toBe(true); 397 | }); 398 | it("should return false if a single value in object fails predicate callback", function() { 399 | var result; 400 | result = _.every(everyObj1, callback); 401 | return expect(result).toBe(false); 402 | }); 403 | return it("should return true only if all values in object pass predicate callback", function() { 404 | var result; 405 | result = _.every(everyObj2, callback); 406 | return expect(result).toBe(true); 407 | }); 408 | }); 409 | 410 | describe("some", function() { 411 | var callback, someArr1, someArr2, someObj1, someObj2; 412 | someArr1 = [1, 2, 3, 4, 5, 6]; 413 | someArr2 = [1, 3, 5]; 414 | someObj1 = { 415 | a: 1, 416 | b: 2, 417 | c: 3, 418 | d: 4 419 | }; 420 | someObj2 = { 421 | a: 1, 422 | b: 3, 423 | c: 9 424 | }; 425 | callback = function(value) { 426 | return value % 2 === 0; 427 | }; 428 | it("should return true if any of the values in the array evaluate to true when passed predicate callback", function() { 429 | var result; 430 | result = _.some(someArr1, callback); 431 | return expect(result).toBe(true); 432 | }); 433 | it("should return false if all values in array evaluate to false when passed predicate callback", function() { 434 | var result; 435 | result = _.some(someArr2, callback); 436 | return expect(result).toBe(false); 437 | }); 438 | it("should return true if any of the values in the object evaluate to true when passed predicate callback", function() { 439 | var result; 440 | result = _.some(someObj1, callback); 441 | return expect(result).toBe(true); 442 | }); 443 | return it("should return false if all values in object evaluate to false when passed predicate callback", function() { 444 | var result; 445 | result = _.some(someObj2, callback); 446 | return expect(result).toBe(false); 447 | }); 448 | }); 449 | 450 | describe("contains", function() { 451 | var containsArr, containsObj; 452 | containsArr = [1, 2, 3]; 453 | containsObj = { 454 | a: 1, 455 | b: 2, 456 | c: 4 457 | }; 458 | it("should return true if the value is in the array", function() { 459 | var result; 460 | result = _.contains(containsArr, 2); 461 | return expect(result).toBe(true); 462 | }); 463 | it("should return false if the value is not in the array", function() { 464 | var result; 465 | result = _.contains(containsArr, 99); 466 | return expect(result).toBe(false); 467 | }); 468 | it("should return true if the value is in the object", function() { 469 | var result; 470 | result = _.contains(containsObj, 2); 471 | return expect(result).toBe(true); 472 | }); 473 | return it("should return false if the value is not in the object", function() { 474 | var result; 475 | result = _.contains(containsObj, 99); 476 | return expect(result).toBe(false); 477 | }); 478 | }); 479 | 480 | describe("invoke", function() { 481 | it("should call sort method on each element in an array and return results in an array", function() { 482 | var result; 483 | result = _.invoke([[5, 1, 7], [3, 2, 1]], "sort"); 484 | return expect(result).toEqual([[1, 5, 7], [1, 2, 3]]); 485 | }); 486 | it("should call sort method on each value in an object and return results in an array", function() { 487 | var result; 488 | result = _.invoke({ 489 | a: [5, 1, 7], 490 | b: [3, 2, 66] 491 | }, "sort"); 492 | return expect(result).toEqual([[1, 5, 7], [2, 3, 66]]); 493 | }); 494 | return it("should pass extra arguments onto method invocation", function() { 495 | var result; 496 | result = _.invoke(["lol"], "concat", "bbq"); 497 | return expect(result).toEqual(["lolbbq"]); 498 | }); 499 | }); 500 | 501 | describe("pluck", function() { 502 | it("should extract property value from each object in array container", function() { 503 | var arr, result; 504 | arr = [ 505 | { 506 | name: 'moe', 507 | age: 40 508 | }, { 509 | name: 'larry', 510 | age: 50 511 | }, { 512 | name: 'curly', 513 | age: 60 514 | } 515 | ]; 516 | result = _.pluck(arr, 'name'); 517 | return expect(result).toEqual(["moe", "larry", "curly"]); 518 | }); 519 | return it("should extract property value from each object in object container", function() { 520 | var result; 521 | obj = { 522 | a: { 523 | name: 'moe', 524 | age: 40 525 | }, 526 | b: { 527 | name: 'larry', 528 | age: 50 529 | }, 530 | c: { 531 | name: 'curly', 532 | age: 60 533 | } 534 | }; 535 | result = _.pluck(obj, 'name'); 536 | return expect(result).toEqual(["moe", "larry", "curly"]); 537 | }); 538 | }); 539 | 540 | describe("max", function() { 541 | it("should return the maximum value in the container when passed into a callback", function() { 542 | var result, stooges; 543 | stooges = [ 544 | { 545 | name: 'moe', 546 | age: 40 547 | }, { 548 | name: 'larry', 549 | age: 50 550 | }, { 551 | name: 'curly', 552 | age: 60 553 | } 554 | ]; 555 | result = _.max(stooges, function(stooge) { 556 | return stooge.age; 557 | }); 558 | return expect(result).toEqual({ 559 | name: 'curly', 560 | age: 60 561 | }); 562 | }); 563 | it("should return the maximum value in the container when not passed a callback", function() { 564 | var result; 565 | result = _.max([54, 43, 12, 455, 12]); 566 | return expect(result).toEqual(455); 567 | }); 568 | return it("should evaluate to infinity if container is empty", function() { 569 | var result; 570 | result = _.max([], function() {}); 571 | return expect(result).toEqual(Number.POSITIVE_INFINITY); 572 | }); 573 | }); 574 | 575 | describe("min", function() { 576 | it("should return the minimum value in the container when passed into a callback", function() { 577 | var result, stooges; 578 | stooges = [ 579 | { 580 | name: 'moe', 581 | age: 40 582 | }, { 583 | name: 'larry', 584 | age: 50 585 | }, { 586 | name: 'curly', 587 | age: 60 588 | } 589 | ]; 590 | result = _.min(stooges, function(stooge) { 591 | return stooge.age; 592 | }); 593 | return expect(result).toEqual({ 594 | name: 'moe', 595 | age: 40 596 | }); 597 | }); 598 | it("should return the minimum value in the container when not passed a callback", function() { 599 | var result; 600 | result = _.min([54, 43, 12, 455, 12]); 601 | return expect(result).toEqual(12); 602 | }); 603 | return it("should evaluate to infinity if container is empty", function() { 604 | var result; 605 | result = _.min([], function() {}); 606 | return expect(result).toEqual(Number.POSITIVE_INFINITY); 607 | }); 608 | }); 609 | 610 | describe("sortBy", function() { 611 | it("should sort arrays in ascending order", function() { 612 | var result; 613 | result = _.sortBy([1, 2, 3, 4, 5, 6], function(num) { 614 | return Math.sin(num); 615 | }); 616 | return expect(result).toEqual([5, 4, 6, 3, 1, 2]); 617 | }); 618 | return it("should sort objects in ascending order and return contents in array", function() { 619 | var result; 620 | result = _.sortBy({ 621 | a: { 622 | age: 5 623 | }, 624 | b: { 625 | age: 222 626 | }, 627 | c: { 628 | age: 1 629 | } 630 | }, function(value) { 631 | return value.age; 632 | }); 633 | return expect(result).toEqual([ 634 | { 635 | "age": 1 636 | }, { 637 | "age": 5 638 | }, { 639 | "age": 222 640 | } 641 | ]); 642 | }); 643 | }); 644 | 645 | describe("groupBy", function() { 646 | it("should split a collection into sets, grouped by result of running each through the callback", function() { 647 | var result; 648 | result = _.groupBy([1.3, 2.1, 2.4], function(num) { 649 | return Math.floor(num); 650 | }); 651 | return expect(result).toEqual({ 652 | 1: [1.3], 653 | 2: [2.1, 2.4] 654 | }); 655 | }); 656 | return it("should split a collection into sets, grouped by result of a mutual property on each object", function() { 657 | var result; 658 | result = _.groupBy(['one', 'two', 'three'], 'length'); 659 | return expect(result).toEqual({ 660 | 3: ["one", "two"], 661 | 5: ["three"] 662 | }); 663 | }); 664 | }); 665 | 666 | describe("indexBy", function() { 667 | return it("should split a collection into objects, organized by a property value or callback", function() { 668 | var result, stooges; 669 | stooges = [ 670 | { 671 | name: 'moe', 672 | age: 40 673 | }, { 674 | name: 'larry', 675 | age: 50 676 | }, { 677 | name: 'curly', 678 | age: 60 679 | } 680 | ]; 681 | result = _.indexBy(stooges, 'age'); 682 | return expect(result).toEqual({ 683 | "40": { 684 | name: 'moe', 685 | age: 40 686 | }, 687 | "50": { 688 | name: 'larry', 689 | age: 50 690 | }, 691 | "60": { 692 | name: 'curly', 693 | age: 60 694 | } 695 | }); 696 | }); 697 | }); 698 | 699 | describe("countBy", function() { 700 | return it("should split collection into groups and return a count for the number of values in each group.", function() { 701 | var result; 702 | result = _.countBy([1, 2, 3, 4, 5], function(num) { 703 | if (num % 2 === 0) { 704 | return 'even'; 705 | } else { 706 | return 'odd'; 707 | } 708 | }); 709 | return expect(result).toEqual({ 710 | odd: 3, 711 | even: 2 712 | }); 713 | }); 714 | }); 715 | 716 | describe("shuffle", function() { 717 | it("should randomize an array of values", function() { 718 | var arr, result; 719 | arr = [1, 2, 3, 4, 5, 6]; 720 | result = _.shuffle(arr); 721 | return expect(result).not.toEqual(arr); 722 | }); 723 | return it("should randomize an object of values", function() { 724 | var result; 725 | obj = { 726 | a: [1, 2, 3], 727 | b: 'fefe', 728 | c: 242 729 | }; 730 | result = _.shuffle(obj); 731 | return expect(result).not.toEqual(obj); 732 | }); 733 | }); 734 | 735 | describe("sample", function() { 736 | it("should return a random value from the array", function() { 737 | var arr, result; 738 | arr = [1, 2, 3, 4, 5, 6]; 739 | result = _.sample(arr); 740 | return expect(result).not.toEqual(void 0); 741 | }); 742 | it("should return a random value from the object", function() { 743 | var result; 744 | obj = { 745 | a: 1, 746 | b: 2, 747 | c: 3 748 | }; 749 | result = _.sample(obj); 750 | return expect(result).not.toEqual(void 0); 751 | }); 752 | return it("should return n random values from the array when passed n as an argument", function() { 753 | var arr, result; 754 | arr = [1, 2, 3, 4, 5, 6]; 755 | result = _.sample(arr, 3); 756 | return expect(result.length).toEqual(3); 757 | }); 758 | }); 759 | 760 | describe("toArray", function() { 761 | it("should create a real array from the arguments psuedo-array", function() { 762 | var result; 763 | result = (function() { 764 | return _.toArray(arguments).slice(1); 765 | })(1, 2, 3, 4); 766 | return expect(result).toEqual([2, 3, 4]); 767 | }); 768 | return it("should create a real array from an object", function() { 769 | var result; 770 | result = _.toArray({ 771 | a: 1, 772 | b: 2, 773 | c: 3 774 | }); 775 | return expect(result).toEqual([1, 2, 3]); 776 | }); 777 | }); 778 | 779 | describe("size", function() { 780 | return it("should return the number of values in a list", function() { 781 | var result; 782 | result = _.size({ 783 | one: 1, 784 | two: 2, 785 | three: 3 786 | }); 787 | return expect(result).toEqual(3); 788 | }); 789 | }); 790 | 791 | describe("partition", function() { 792 | return it("should split array into two arrays: one whose elements all satisfy predicate and one whose elements all do not satisfy predicate.", function() { 793 | var result; 794 | result = _.partition([0, 1, 2, 3, 4, 5], function(value) { 795 | return value % 2 === 1; 796 | }); 797 | return expect(result).toEqual([[1, 3, 5], [0, 2, 4]]); 798 | }); 799 | }); 800 | 801 | }).call(this); 802 | -------------------------------------------------------------------------------- /spec/functionsSpec.coffee: -------------------------------------------------------------------------------- 1 | describe 'functions', -> 2 | describe '_.bind', -> 3 | it 'should bind a function to an object', -> 4 | fn = -> "Hello #{@name}" 5 | result = _.bind(fn, {name: "world"}) 6 | expect(result()).toEqual("Hello world") 7 | 8 | it 'should partially apply single argument to function', -> 9 | fn = (greeting) -> "#{greeting} #{@name}" 10 | result = _.bind(fn, {name: 'moe'}, 'hi') 11 | expect(result()).toEqual('hi moe') 12 | 13 | it 'should partially apply multiple arguments to function', -> 14 | fn = (a, b, c) -> a + b + c 15 | result = _.bind(fn, {}, 1, 2) 16 | expect(result(1)).toEqual(4) 17 | 18 | describe '_.bindAll', -> 19 | it 'should bind multiple functions to an object at once', -> 20 | buttonView = 21 | label : 'underscore' 22 | onClick: -> "Clicked on #{@label}" 23 | onHover: -> "Hovered on #{@label}" 24 | _.bindAll(buttonView, 'onClick', 'onHover') 25 | expect(buttonView.onHover()).toEqual("Hovered on underscore") 26 | expect(buttonView.onClick()).toEqual("Clicked on underscore") 27 | 28 | describe '_.partial', -> 29 | it 'should prime functions with argument prior to their invocation', -> 30 | add = (a, b) -> a + b 31 | add5 = _.partial(add, 5) 32 | result = add5(10) 33 | expect(result).toEqual(15) 34 | 35 | it 'should accept \'_\' as an argument to denote an argument which should be filled at execution time', -> 36 | add = (a, b) -> a + b 37 | add5 = _.partial(add, '_', 5) 38 | result = add5(10) 39 | expect(result).toEqual(15) 40 | 41 | describe '_.memoize', -> 42 | it 'should return a new working version of the function', -> 43 | add = (a, b) -> a + b 44 | add = _.memoize(add) 45 | result = add(1,5) 46 | expect(result).toEqual(6) 47 | 48 | it 'should cache the results of a function call and return the cached results when the same arguments are inputted', -> 49 | fn = _.memoize(-> Math.random()) 50 | result = fn() 51 | expect(result).toEqual(fn()) 52 | 53 | describe '_.once', -> 54 | it 'should return a version of the function that only executes once', -> 55 | fn = _.once(-> Math.random()) 56 | expect(fn()).not.toEqual(fn()) 57 | 58 | describe '_.after', -> 59 | it 'should return a version of the function that only execute once it is called count times', -> 60 | fn = _.after(2, (-> "works")) 61 | expect(fn()).toEqual(undefined) 62 | expect(fn()).toEqual("works") 63 | 64 | describe '_.before', -> 65 | it 'should return a version of the function that is only callable count times. After count calls it should return the value of the last successful call', -> 66 | fn = _.before(3, ((input) -> input)) 67 | expect(fn("works")).toEqual("works") 68 | expect(fn("does not work")).toEqual("does not work") 69 | expect(fn("works")).toEqual("does not work") 70 | 71 | describe '_.wrap', -> 72 | it 'should return a version of the function which has a wrapper applied to it. This allows the wrapper to execute code before and after the function runs, adjust the arguments, and execute it conditionally.', -> 73 | hello = (name) -> "hello: #{name}" 74 | hello = _.wrap(hello, (func) -> "before, #{func('moe')}, after") 75 | expect(hello()).toEqual("before, hello: moe, after") 76 | 77 | describe '_.negate', -> 78 | it 'should return a new negated version of the predicate function', -> 79 | isFalsy = _.negate(Boolean) 80 | result = _.find([-2, -1, 0, 1, 2], isFalsy) 81 | expect(result).toEqual(0) 82 | 83 | describe '_.compose', -> 84 | it 'should return a composition of all the functions passed in. Each function consumes the return value of the last', -> 85 | greet = (name) -> "hi #{name}" 86 | exclaim = (message) -> message.toUpperCase() 87 | result = _.compose(greet, exclaim)('tony') 88 | expect(result).toEqual('HI TONY') 89 | -------------------------------------------------------------------------------- /spec/functionsSpec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | describe('functions', function() { 3 | describe('_.bind', function() { 4 | it('should bind a function to an object', function() { 5 | var fn, result; 6 | fn = function() { 7 | return "Hello " + this.name; 8 | }; 9 | result = _.bind(fn, { 10 | name: "world" 11 | }); 12 | return expect(result()).toEqual("Hello world"); 13 | }); 14 | it('should partially apply single argument to function', function() { 15 | var fn, result; 16 | fn = function(greeting) { 17 | return greeting + " " + this.name; 18 | }; 19 | result = _.bind(fn, { 20 | name: 'moe' 21 | }, 'hi'); 22 | return expect(result()).toEqual('hi moe'); 23 | }); 24 | return it('should partially apply multiple arguments to function', function() { 25 | var fn, result; 26 | fn = function(a, b, c) { 27 | return a + b + c; 28 | }; 29 | result = _.bind(fn, {}, 1, 2); 30 | return expect(result(1)).toEqual(4); 31 | }); 32 | }); 33 | describe('_.bindAll', function() { 34 | return it('should bind multiple functions to an object at once', function() { 35 | var buttonView; 36 | buttonView = { 37 | label: 'underscore', 38 | onClick: function() { 39 | return "Clicked on " + this.label; 40 | }, 41 | onHover: function() { 42 | return "Hovered on " + this.label; 43 | } 44 | }; 45 | _.bindAll(buttonView, 'onClick', 'onHover'); 46 | expect(buttonView.onHover()).toEqual("Hovered on underscore"); 47 | return expect(buttonView.onClick()).toEqual("Clicked on underscore"); 48 | }); 49 | }); 50 | describe('_.partial', function() { 51 | it('should prime functions with argument prior to their invocation', function() { 52 | var add, add5, result; 53 | add = function(a, b) { 54 | return a + b; 55 | }; 56 | add5 = _.partial(add, 5); 57 | result = add5(10); 58 | return expect(result).toEqual(15); 59 | }); 60 | return it('should accept \'_\' as an argument to denote an argument which should be filled at execution time', function() { 61 | var add, add5, result; 62 | add = function(a, b) { 63 | return a + b; 64 | }; 65 | add5 = _.partial(add, '_', 5); 66 | result = add5(10); 67 | return expect(result).toEqual(15); 68 | }); 69 | }); 70 | describe('_.memoize', function() { 71 | it('should return a new working version of the function', function() { 72 | var add, result; 73 | add = function(a, b) { 74 | return a + b; 75 | }; 76 | add = _.memoize(add); 77 | result = add(1, 5); 78 | return expect(result).toEqual(6); 79 | }); 80 | return it('should cache the results of a function call and return the cached results when the same arguments are inputted', function() { 81 | var fn, result; 82 | fn = _.memoize(function() { 83 | return Math.random(); 84 | }); 85 | result = fn(); 86 | return expect(result).toEqual(fn()); 87 | }); 88 | }); 89 | describe('_.once', function() { 90 | return it('should return a version of the function that only executes once', function() { 91 | var fn; 92 | fn = _.once(function() { 93 | return Math.random(); 94 | }); 95 | return expect(fn()).not.toEqual(fn()); 96 | }); 97 | }); 98 | describe('_.after', function() { 99 | return it('should return a version of the function that only execute once it is called count times', function() { 100 | var fn; 101 | fn = _.after(2, (function() { 102 | return "works"; 103 | })); 104 | expect(fn()).toEqual(void 0); 105 | return expect(fn()).toEqual("works"); 106 | }); 107 | }); 108 | describe('_.before', function() { 109 | return it('should return a version of the function that is only callable count times. After count calls it should return the value of the last successful call', function() { 110 | var fn; 111 | fn = _.before(3, (function(input) { 112 | return input; 113 | })); 114 | expect(fn("works")).toEqual("works"); 115 | expect(fn("does not work")).toEqual("does not work"); 116 | return expect(fn("works")).toEqual("does not work"); 117 | }); 118 | }); 119 | describe('_.wrap', function() { 120 | return it('should return a version of the function which has a wrapper applied to it. This allows the wrapper to execute code before and after the function runs, adjust the arguments, and execute it conditionally.', function() { 121 | var hello; 122 | hello = function(name) { 123 | return "hello: " + name; 124 | }; 125 | hello = _.wrap(hello, function(func) { 126 | return "before, " + (func('moe')) + ", after"; 127 | }); 128 | return expect(hello()).toEqual("before, hello: moe, after"); 129 | }); 130 | }); 131 | describe('_.negate', function() { 132 | return it('should return a new negated version of the predicate function', function() { 133 | var isFalsy, result; 134 | isFalsy = _.negate(Boolean); 135 | result = _.find([-2, -1, 0, 1, 2], isFalsy); 136 | return expect(result).toEqual(0); 137 | }); 138 | }); 139 | return describe('_.compose', function() { 140 | return it('should return a composition of all the functions passed in. Each function consumes the return value of the last', function() { 141 | var exclaim, greet, result; 142 | greet = function(name) { 143 | return "hi " + name; 144 | }; 145 | exclaim = function(message) { 146 | return message.toUpperCase(); 147 | }; 148 | result = _.compose(greet, exclaim)('tony'); 149 | return expect(result).toEqual('HI TONY'); 150 | }); 151 | }); 152 | }); 153 | 154 | }).call(this); 155 | -------------------------------------------------------------------------------- /spec/objectsSpec.coffee: -------------------------------------------------------------------------------- 1 | describe 'objects', -> 2 | describe '_.keys', -> 3 | it 'should return all of the names of the object\'s properties', -> 4 | results = _.keys({one: 1, two: 2, three: 3}) 5 | expect(results).toEqual(['one', 'two', 'three']) 6 | 7 | describe '_.values', -> 8 | it 'should return all of the values of the object\'s properties', -> 9 | results = _.values({one: 1, two: 2, three: 3}) 10 | expect(results).toEqual([1, 2, 3]) 11 | 12 | describe '_.pairs', -> 13 | it 'should convert an object into a list of [key, value] pairs', -> 14 | results = _.pairs({one: 1, two: 2, three: 3}) 15 | expect(results).toEqual([["one", 1], ["two", 2], ["three", 3]]) 16 | 17 | describe '_.invert', -> 18 | it 'should return an object where the keys and values have been swapped', -> 19 | results = _.invert({Moe: "Moses", Larry: "Louis", Curly: "Jerome"}) 20 | expect(results).toEqual({Moses: "Moe", Louis: "Larry", Jerome: "Curly"}) 21 | 22 | describe '_.functions', -> 23 | it 'should return a sorted list of the names of every method in an object', -> 24 | results = _.functions(_) 25 | expect(results.length).not.toEqual(0) 26 | 27 | describe '_.extend', -> 28 | it 'should copy all of the properties in the source objects over to the destination object', -> 29 | results = _.extend({name: 'moe'}, {age: 50}) 30 | expect(results).toEqual({name: 'moe', age: 50}) 31 | 32 | describe '_.isFunction', -> 33 | it 'should return true if object is a function', -> 34 | expect(_.isFunction(alert)).toBe(true) 35 | 36 | describe '_.pick', -> 37 | it 'should return a copy of the object, filtered to only have values for the whitelisted keys', -> 38 | result= _.pick({name: 'moe', age: 50, userid: 'moe1'}, 'name', 'age') 39 | expect(result).toEqual({name: 'moe', age: 50}) 40 | 41 | it 'should return a copy of the object, filtered to only have values which pass the predicate', -> 42 | result = _.pick({name: 'moe', age: 50, userid: 'moe1'}, (value, key, object) -> typeof value is 'number') 43 | expect(result).toEqual({age: 50}) 44 | 45 | describe '_.isElement', -> 46 | it 'should return true if object is a DOM element', -> 47 | results = _.isElement(document.getElementsByTagName('body')[0]) 48 | expect(results).toBe(true) 49 | 50 | it 'should return false if not DOM node', -> 51 | expect(_.isElement('test')).toBe(false) 52 | expect(_.isElement([])).toBe(false) 53 | expect(_.isElement(32)).toBe(false) 54 | expect(_.isElement({})).toBe(false) 55 | 56 | describe '_.isArray', -> 57 | it 'should return false if object is not an Array', -> 58 | results = (-> _.isArray arguments)() 59 | expect(results).toBe(false) 60 | 61 | it 'should return true if object is an Array', -> 62 | expect(_.isArray([1, 2, 3])).toBe(true) 63 | 64 | describe '_.isObject', -> 65 | it 'should return true if passed a function', -> 66 | result = _.isObject(->) 67 | expect(result).toBe(true) 68 | 69 | it 'should return true if passed an array', -> 70 | result = _.isObject([1, 2, 3]) 71 | expect(result).toBe(true) 72 | 73 | it 'should return true if passed an object', -> 74 | result = _.isObject({a: 1}) 75 | expect(result).toBe(true) 76 | 77 | it 'should return false if passed primitive value', -> 78 | result = _.isObject(2) 79 | expect(result).toBe(false) 80 | 81 | it 'should return true if object is an Arguments object', -> 82 | result = _.isArgument(((a, b, c)-> arguments)(1, 2, 3)) 83 | expect(result).toBe(true) 84 | 85 | it 'should return false if object is not an Arguments object', -> 86 | result = _.isArgument([1, 2, 3]) 87 | expect(result).toBe(false) 88 | 89 | describe '_.omit', -> 90 | it 'should return a copy of the object filtered to omit the blacklisted keys passed as strings', -> 91 | result = _.omit({name: 'moe', age: 50, userid: 'moe1'}, 'userid') 92 | expect(result).toEqual({name: 'moe', age: 50}) 93 | 94 | it 'should return a copy of the object filtered to omit the blacklisted keys passed as array', -> 95 | result = _.omit({name: 'moe', age: 50, userid: 'moe1'}, ['userid']) 96 | expect(result).toEqual({name: 'moe', age: 50}) 97 | 98 | it 'should return a copy of the object filtered to omit the values which pass the predicate', -> 99 | result = _.omit({a: 1, b: 2, c: 3, d: 4, e: 5, f: 6}, (value, key) -> value % 2 is 0) 100 | expect(result).toEqual({ a: 1, c: 3, e: 5 }) 101 | 102 | describe '_.defaults', -> 103 | it 'should fill in undefined properties in object with the first value present in the list of defaults object', -> 104 | iceCream = {flavor: "chocolate"} 105 | result = _.defaults(iceCream, {flavor: "vanilla", sprinkles: "lots"}) 106 | expect(result).toEqual({flavor: "chocolate", sprinkles: "lots"}) 107 | 108 | describe '_.clone', -> 109 | it 'should create a shallow-copied clone of the object', -> 110 | result = _.clone({name: 'moe'}) 111 | expect(result).toEqual({name: 'moe'}) 112 | 113 | describe '_.has', -> 114 | it 'should return a boolean indicating whether an object has the specified key', -> 115 | result = _.has({a: 1, b: 2, c: 3}, "b") 116 | expect(result).toBe(true) 117 | 118 | describe '_.moe', -> 119 | it 'should return a function that will itself return the key property of any passed-in object', -> 120 | moe = {name: 'moe'} 121 | result = _.property('name')(moe) 122 | expect(result).toEqual('moe') 123 | -------------------------------------------------------------------------------- /spec/objectsSpec.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | describe('objects', function() { 3 | describe('_.keys', function() { 4 | return it('should return all of the names of the object\'s properties', function() { 5 | var results; 6 | results = _.keys({ 7 | one: 1, 8 | two: 2, 9 | three: 3 10 | }); 11 | return expect(results).toEqual(['one', 'two', 'three']); 12 | }); 13 | }); 14 | describe('_.values', function() { 15 | return it('should return all of the values of the object\'s properties', function() { 16 | var results; 17 | results = _.values({ 18 | one: 1, 19 | two: 2, 20 | three: 3 21 | }); 22 | return expect(results).toEqual([1, 2, 3]); 23 | }); 24 | }); 25 | describe('_.pairs', function() { 26 | return it('should convert an object into a list of [key, value] pairs', function() { 27 | var results; 28 | results = _.pairs({ 29 | one: 1, 30 | two: 2, 31 | three: 3 32 | }); 33 | return expect(results).toEqual([["one", 1], ["two", 2], ["three", 3]]); 34 | }); 35 | }); 36 | describe('_.invert', function() { 37 | return it('should return an object where the keys and values have been swapped', function() { 38 | var results; 39 | results = _.invert({ 40 | Moe: "Moses", 41 | Larry: "Louis", 42 | Curly: "Jerome" 43 | }); 44 | return expect(results).toEqual({ 45 | Moses: "Moe", 46 | Louis: "Larry", 47 | Jerome: "Curly" 48 | }); 49 | }); 50 | }); 51 | describe('_.functions', function() { 52 | return it('should return a sorted list of the names of every method in an object', function() { 53 | var results; 54 | results = _.functions(_); 55 | return expect(results.length).not.toEqual(0); 56 | }); 57 | }); 58 | describe('_.extend', function() { 59 | return it('should copy all of the properties in the source objects over to the destination object', function() { 60 | var results; 61 | results = _.extend({ 62 | name: 'moe' 63 | }, { 64 | age: 50 65 | }); 66 | return expect(results).toEqual({ 67 | name: 'moe', 68 | age: 50 69 | }); 70 | }); 71 | }); 72 | describe('_.isFunction', function() { 73 | return it('should return true if object is a function', function() { 74 | return expect(_.isFunction(alert)).toBe(true); 75 | }); 76 | }); 77 | describe('_.pick', function() { 78 | it('should return a copy of the object, filtered to only have values for the whitelisted keys', function() { 79 | var result; 80 | result = _.pick({ 81 | name: 'moe', 82 | age: 50, 83 | userid: 'moe1' 84 | }, 'name', 'age'); 85 | return expect(result).toEqual({ 86 | name: 'moe', 87 | age: 50 88 | }); 89 | }); 90 | return it('should return a copy of the object, filtered to only have values which pass the predicate', function() { 91 | var result; 92 | result = _.pick({ 93 | name: 'moe', 94 | age: 50, 95 | userid: 'moe1' 96 | }, function(value, key, object) { 97 | return typeof value === 'number'; 98 | }); 99 | return expect(result).toEqual({ 100 | age: 50 101 | }); 102 | }); 103 | }); 104 | describe('_.isElement', function() { 105 | it('should return true if object is a DOM element', function() { 106 | var results; 107 | results = _.isElement(document.getElementsByTagName('body')[0]); 108 | return expect(results).toBe(true); 109 | }); 110 | return it('should return false if not DOM node', function() { 111 | expect(_.isElement('test')).toBe(false); 112 | expect(_.isElement([])).toBe(false); 113 | expect(_.isElement(32)).toBe(false); 114 | return expect(_.isElement({})).toBe(false); 115 | }); 116 | }); 117 | describe('_.isArray', function() { 118 | it('should return false if object is not an Array', function() { 119 | var results; 120 | results = (function() { 121 | return _.isArray(arguments); 122 | })(); 123 | return expect(results).toBe(false); 124 | }); 125 | return it('should return true if object is an Array', function() { 126 | return expect(_.isArray([1, 2, 3])).toBe(true); 127 | }); 128 | }); 129 | describe('_.isObject', function() { 130 | it('should return true if passed a function', function() { 131 | var result; 132 | result = _.isObject(function() {}); 133 | return expect(result).toBe(true); 134 | }); 135 | it('should return true if passed an array', function() { 136 | var result; 137 | result = _.isObject([1, 2, 3]); 138 | return expect(result).toBe(true); 139 | }); 140 | it('should return true if passed an object', function() { 141 | var result; 142 | result = _.isObject({ 143 | a: 1 144 | }); 145 | return expect(result).toBe(true); 146 | }); 147 | it('should return false if passed primitive value', function() { 148 | var result; 149 | result = _.isObject(2); 150 | return expect(result).toBe(false); 151 | }); 152 | it('should return true if object is an Arguments object', function() { 153 | var result; 154 | result = _.isArgument((function(a, b, c) { 155 | return arguments; 156 | })(1, 2, 3)); 157 | return expect(result).toBe(true); 158 | }); 159 | return it('should return false if object is not an Arguments object', function() { 160 | var result; 161 | result = _.isArgument([1, 2, 3]); 162 | return expect(result).toBe(false); 163 | }); 164 | }); 165 | describe('_.omit', function() { 166 | it('should return a copy of the object filtered to omit the blacklisted keys passed as strings', function() { 167 | var result; 168 | result = _.omit({ 169 | name: 'moe', 170 | age: 50, 171 | userid: 'moe1' 172 | }, 'userid'); 173 | return expect(result).toEqual({ 174 | name: 'moe', 175 | age: 50 176 | }); 177 | }); 178 | it('should return a copy of the object filtered to omit the blacklisted keys passed as array', function() { 179 | var result; 180 | result = _.omit({ 181 | name: 'moe', 182 | age: 50, 183 | userid: 'moe1' 184 | }, ['userid']); 185 | return expect(result).toEqual({ 186 | name: 'moe', 187 | age: 50 188 | }); 189 | }); 190 | return it('should return a copy of the object filtered to omit the values which pass the predicate', function() { 191 | var result; 192 | result = _.omit({ 193 | a: 1, 194 | b: 2, 195 | c: 3, 196 | d: 4, 197 | e: 5, 198 | f: 6 199 | }, function(value, key) { 200 | return value % 2 === 0; 201 | }); 202 | return expect(result).toEqual({ 203 | a: 1, 204 | c: 3, 205 | e: 5 206 | }); 207 | }); 208 | }); 209 | describe('_.defaults', function() { 210 | return it('should fill in undefined properties in object with the first value present in the list of defaults object', function() { 211 | var iceCream, result; 212 | iceCream = { 213 | flavor: "chocolate" 214 | }; 215 | result = _.defaults(iceCream, { 216 | flavor: "vanilla", 217 | sprinkles: "lots" 218 | }); 219 | return expect(result).toEqual({ 220 | flavor: "chocolate", 221 | sprinkles: "lots" 222 | }); 223 | }); 224 | }); 225 | describe('_.clone', function() { 226 | return it('should create a shallow-copied clone of the object', function() { 227 | var result; 228 | result = _.clone({ 229 | name: 'moe' 230 | }); 231 | return expect(result).toEqual({ 232 | name: 'moe' 233 | }); 234 | }); 235 | }); 236 | describe('_.has', function() { 237 | return it('should return a boolean indicating whether an object has the specified key', function() { 238 | var result; 239 | result = _.has({ 240 | a: 1, 241 | b: 2, 242 | c: 3 243 | }, "b"); 244 | return expect(result).toBe(true); 245 | }); 246 | }); 247 | return describe('_.moe', function() { 248 | return it('should return a function that will itself return the key property of any passed-in object', function() { 249 | var moe, result; 250 | moe = { 251 | name: 'moe' 252 | }; 253 | result = _.property('name')(moe); 254 | return expect(result).toEqual('moe'); 255 | }); 256 | }); 257 | }); 258 | 259 | }).call(this); 260 | -------------------------------------------------------------------------------- /spec/utilitiesSpec.coffee: -------------------------------------------------------------------------------- 1 | describe 'utilities', -> 2 | describe 'identity', -> 3 | it 'should take value which returns itself', -> 4 | expect(_.identity(5)).toEqual(5) 5 | 6 | describe 'constant', -> 7 | it 'should create a function that returns the same value that is used as the argument of _.constant', -> 8 | fn = _.constant(5) 9 | expect(fn()).toEqual(5) 10 | 11 | describe 'noop', -> 12 | it 'should return undefined', -> 13 | expect(_.noop()).toEqual(undefined) 14 | 15 | describe 'times', -> 16 | it 'should invoke the given iteratee function n times', -> 17 | result = _.times(5, _.identity) 18 | expect(result).toEqual([1, 2, 3, 4, 5]) 19 | 20 | describe 'random', -> 21 | it 'should return NaN if no arguments are provided', -> 22 | expect(_.random()).toEqual(NaN) 23 | 24 | it 'should return a random integer between min and max', -> 25 | expect(_.random(1, 1000)).not.toEqual(_.random(1, 1000)) 26 | 27 | describe 'mixin', -> 28 | it 'should extend functions to underscore object', -> 29 | fn = (str) -> 30 | str.charAt(0).toUpperCase() + str.substring(1) 31 | _.mixin({capitalize: fn}) 32 | result = _.capitalize("lol it works") 33 | expect(result).toEqual("Lol it works") 34 | 35 | describe 'uniqueId', -> 36 | it 'should generate a globally-unique id', -> 37 | _.uniqueId('bbq') 38 | _.uniqueId('bbq') 39 | expect(_.uniqueId('bbq')).toEqual('bbq3') 40 | 41 | describe 'escape', -> 42 | it 'should escape a string for insertion into HTML, replacing &, <, >, ", `, and \'', -> 43 | expect(_.escape('<"lol">')).toEqual('<"lol">') 44 | 45 | describe 'unescape', -> 46 | it 'should function as the opposite of escape, replaces &, <, >, ", ` and ' with their unescaped counterparts.', -> 47 | expect(_.unescape('<"lol">')).toEqual('<"lol">') 48 | 49 | 50 | -------------------------------------------------------------------------------- /spec/utilitiesSpec.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.9.3 2 | (function() { 3 | describe('utilities', function() { 4 | describe('identity', function() { 5 | return it('should take value which returns itself', function() { 6 | return expect(_.identity(5)).toEqual(5); 7 | }); 8 | }); 9 | describe('constant', function() { 10 | return it('should create a function that returns the same value that is used as the argument of _.constant', function() { 11 | var fn; 12 | fn = _.constant(5); 13 | return expect(fn()).toEqual(5); 14 | }); 15 | }); 16 | describe('noop', function() { 17 | return it('should return undefined', function() { 18 | return expect(_.noop()).toEqual(void 0); 19 | }); 20 | }); 21 | describe('times', function() { 22 | return it('should invoke the given iteratee function n times', function() { 23 | var result; 24 | result = _.times(5, _.identity); 25 | return expect(result).toEqual([1, 2, 3, 4, 5]); 26 | }); 27 | }); 28 | describe('random', function() { 29 | it('should return NaN if no arguments are provided', function() { 30 | return expect(_.random()).toEqual(NaN); 31 | }); 32 | return it('should return a random integer between min and max', function() { 33 | return expect(_.random(1, 1000)).not.toEqual(_.random(1, 1000)); 34 | }); 35 | }); 36 | describe('mixin', function() { 37 | return it('should extend functions to underscore object', function() { 38 | var fn, result; 39 | fn = function(str) { 40 | return str.charAt(0).toUpperCase() + str.substring(1); 41 | }; 42 | _.mixin({ 43 | capitalize: fn 44 | }); 45 | result = _.capitalize("lol it works"); 46 | return expect(result).toEqual("Lol it works"); 47 | }); 48 | }); 49 | describe('uniqueId', function() { 50 | return it('should generate a globally-unique id', function() { 51 | _.uniqueId('bbq'); 52 | _.uniqueId('bbq'); 53 | return expect(_.uniqueId('bbq')).toEqual('bbq3'); 54 | }); 55 | }); 56 | describe('escape', function() { 57 | return it('should escape a string for insertion into HTML, replacing &, <, >, ", `, and \'', function() { 58 | return expect(_.escape('<"lol">')).toEqual('<"lol">'); 59 | }); 60 | }); 61 | return describe('unescape', function() { 62 | return it('should function as the opposite of escape, replaces &, <, >, ", ` and ' with their unescaped counterparts.', function() { 63 | return expect(_.unescape('<"lol">')).toEqual('<"lol">'); 64 | }); 65 | }); 66 | }); 67 | 68 | }).call(this); 69 | -------------------------------------------------------------------------------- /src/arrays.coffee: -------------------------------------------------------------------------------- 1 | _.first = _.head = _.take = (array, n = 0) -> 2 | if n is 0 then return array[0] 3 | if n >= _.size(array) then return array 4 | array[...n] 5 | 6 | _.initial = (array, n = 0) -> 7 | if n is 0 then return array[..-2] 8 | array[... -n] 9 | 10 | _.last = (array, n = 0) -> 11 | size = _.size array 12 | if n is 0 then return array[size - 1] 13 | if n >= size then return array 14 | array[n - 1..] 15 | 16 | _.rest = _.tail = _.drop = (array, index = 1) -> 17 | if index >= _.size array then return [] 18 | array[index..] 19 | 20 | _.compact = (array) -> 21 | _.filter array, (value) -> 22 | not not value 23 | 24 | flatten = (array, shallow, results, pushNextItem = true) -> 25 | for item in array 26 | isArray = Array.isArray item 27 | if isArray is true and pushNextItem is false then results.push item 28 | else if isArray is true and shallow is false then flatten item, shallow, results 29 | else if isArray is true and shallow is true then flatten item, shallow, results, false 30 | else results.push item 31 | 32 | _.flatten = (array, shallow = false) -> 33 | results = [] 34 | flatten(array, shallow, results) 35 | results 36 | 37 | _.without = (array, values...) -> 38 | _.reject array, (value) -> 39 | value in values 40 | 41 | _.uniq = _.unique = (array, iteratee = (value) -> value) -> 42 | results = [] 43 | _.filter array, (value) -> 44 | unless _.contains(results, iteratee value) 45 | results.push iteratee value 46 | 47 | _.union = (arrays...) -> 48 | _.uniq _.flatten arrays 49 | 50 | _.zip = (arrays...) -> 51 | longestArray = _.sortBy(arrays, (array) -> -array.length)[0] 52 | _.map longestArray, (value, index) -> 53 | _.map arrays, (array) -> 54 | array[index] 55 | 56 | log = (value) -> 57 | console.log(JSON.stringify(value)) 58 | 59 | format = (arrays) -> 60 | if arrays.length is 2 61 | arrays = _.zip(arrays[0], arrays[1]) 62 | else 63 | arrays = arrays[0] 64 | 65 | _.object = (arrays...) -> 66 | arrays = format arrays 67 | result = {} 68 | _.each arrays, (array) -> 69 | result[array[0]] = array[1] 70 | result 71 | 72 | _.indexOf = (array, value) -> 73 | (_.first _.compact _.map array, (item, index) -> 74 | if item is value then return index) or -1 75 | 76 | _.intersection = (arrays...) -> 77 | _.compact _.map arrays[0], (item) -> 78 | item if _.every arrays, (array) -> item in array 79 | 80 | _.difference = (array, others...) -> 81 | others = _.flatten(others) 82 | _.reject array, (value) -> 83 | value in others 84 | 85 | _.lastIndexOf = (array, value, fromIndex = 0) -> 86 | (_.last _.compact _.map array, (item, index) -> 87 | if fromIndex <= index and item is value then return index) or -1 88 | 89 | _.transform = (value, iteratee) -> 90 | if typeof iteratee is 'string' 91 | value[iteratee] 92 | else if typeof iteratee is 'undefined' 93 | value 94 | else 95 | iteratee.call this, value 96 | 97 | _.sortedIndex = (array, value, iteratee) -> 98 | value = _.transform(value, iteratee) 99 | _.first _.compact _.map array, (item, index) -> 100 | if _.transform(item, iteratee) >= value then return index 101 | 102 | _.range = (start, stop, step = 1) -> 103 | stop = stop or start 104 | if start is stop then start = 0 105 | (i for i in [start...stop] by step) 106 | -------------------------------------------------------------------------------- /src/arrays.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var flatten, format, log, 3 | slice = [].slice, 4 | indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 5 | 6 | _.first = _.head = _.take = function(array, n) { 7 | if (n == null) { 8 | n = 0; 9 | } 10 | if (n === 0) { 11 | return array[0]; 12 | } 13 | if (n >= _.size(array)) { 14 | return array; 15 | } 16 | return array.slice(0, n); 17 | }; 18 | 19 | _.initial = function(array, n) { 20 | if (n == null) { 21 | n = 0; 22 | } 23 | if (n === 0) { 24 | return array.slice(0, -1); 25 | } 26 | return array.slice(0, -n); 27 | }; 28 | 29 | _.last = function(array, n) { 30 | var size; 31 | if (n == null) { 32 | n = 0; 33 | } 34 | size = _.size(array); 35 | if (n === 0) { 36 | return array[size - 1]; 37 | } 38 | if (n >= size) { 39 | return array; 40 | } 41 | return array.slice(n - 1); 42 | }; 43 | 44 | _.rest = _.tail = _.drop = function(array, index) { 45 | if (index == null) { 46 | index = 1; 47 | } 48 | if (index >= _.size(array)) { 49 | return []; 50 | } 51 | return array.slice(index); 52 | }; 53 | 54 | _.compact = function(array) { 55 | return _.filter(array, function(value) { 56 | return !!value; 57 | }); 58 | }; 59 | 60 | flatten = function(array, shallow, results, pushNextItem) { 61 | var isArray, item, j, len, results1; 62 | if (pushNextItem == null) { 63 | pushNextItem = true; 64 | } 65 | results1 = []; 66 | for (j = 0, len = array.length; j < len; j++) { 67 | item = array[j]; 68 | isArray = Array.isArray(item); 69 | if (isArray === true && pushNextItem === false) { 70 | results1.push(results.push(item)); 71 | } else if (isArray === true && shallow === false) { 72 | results1.push(flatten(item, shallow, results)); 73 | } else if (isArray === true && shallow === true) { 74 | results1.push(flatten(item, shallow, results, false)); 75 | } else { 76 | results1.push(results.push(item)); 77 | } 78 | } 79 | return results1; 80 | }; 81 | 82 | _.flatten = function(array, shallow) { 83 | var results; 84 | if (shallow == null) { 85 | shallow = false; 86 | } 87 | results = []; 88 | flatten(array, shallow, results); 89 | return results; 90 | }; 91 | 92 | _.without = function() { 93 | var array, values; 94 | array = arguments[0], values = 2 <= arguments.length ? slice.call(arguments, 1) : []; 95 | return _.reject(array, function(value) { 96 | return indexOf.call(values, value) >= 0; 97 | }); 98 | }; 99 | 100 | _.uniq = _.unique = function(array, iteratee) { 101 | var results; 102 | if (iteratee == null) { 103 | iteratee = function(value) { 104 | return value; 105 | }; 106 | } 107 | results = []; 108 | return _.filter(array, function(value) { 109 | if (!_.contains(results, iteratee(value))) { 110 | return results.push(iteratee(value)); 111 | } 112 | }); 113 | }; 114 | 115 | _.union = function() { 116 | var arrays; 117 | arrays = 1 <= arguments.length ? slice.call(arguments, 0) : []; 118 | return _.uniq(_.flatten(arrays)); 119 | }; 120 | 121 | _.zip = function() { 122 | var arrays, longestArray; 123 | arrays = 1 <= arguments.length ? slice.call(arguments, 0) : []; 124 | longestArray = _.sortBy(arrays, function(array) { 125 | return -array.length; 126 | })[0]; 127 | return _.map(longestArray, function(value, index) { 128 | return _.map(arrays, function(array) { 129 | return array[index]; 130 | }); 131 | }); 132 | }; 133 | 134 | log = function(value) { 135 | return console.log(JSON.stringify(value)); 136 | }; 137 | 138 | format = function(arrays) { 139 | if (arrays.length === 2) { 140 | return arrays = _.zip(arrays[0], arrays[1]); 141 | } else { 142 | return arrays = arrays[0]; 143 | } 144 | }; 145 | 146 | _.object = function() { 147 | var arrays, result; 148 | arrays = 1 <= arguments.length ? slice.call(arguments, 0) : []; 149 | arrays = format(arrays); 150 | result = {}; 151 | _.each(arrays, function(array) { 152 | return result[array[0]] = array[1]; 153 | }); 154 | return result; 155 | }; 156 | 157 | _.indexOf = function(array, value) { 158 | return (_.first(_.compact(_.map(array, function(item, index) { 159 | if (item === value) { 160 | return index; 161 | } 162 | })))) || -1; 163 | }; 164 | 165 | _.intersection = function() { 166 | var arrays; 167 | arrays = 1 <= arguments.length ? slice.call(arguments, 0) : []; 168 | return _.compact(_.map(arrays[0], function(item) { 169 | if (_.every(arrays, function(array) { 170 | return indexOf.call(array, item) >= 0; 171 | })) { 172 | return item; 173 | } 174 | })); 175 | }; 176 | 177 | _.difference = function() { 178 | var array, others; 179 | array = arguments[0], others = 2 <= arguments.length ? slice.call(arguments, 1) : []; 180 | others = _.flatten(others); 181 | return _.reject(array, function(value) { 182 | return indexOf.call(others, value) >= 0; 183 | }); 184 | }; 185 | 186 | _.lastIndexOf = function(array, value, fromIndex) { 187 | if (fromIndex == null) { 188 | fromIndex = 0; 189 | } 190 | return (_.last(_.compact(_.map(array, function(item, index) { 191 | if (fromIndex <= index && item === value) { 192 | return index; 193 | } 194 | })))) || -1; 195 | }; 196 | 197 | _.transform = function(value, iteratee) { 198 | if (typeof iteratee === 'string') { 199 | return value[iteratee]; 200 | } else if (typeof iteratee === 'undefined') { 201 | return value; 202 | } else { 203 | return iteratee.call(this, value); 204 | } 205 | }; 206 | 207 | _.sortedIndex = function(array, value, iteratee) { 208 | value = _.transform(value, iteratee); 209 | return _.first(_.compact(_.map(array, function(item, index) { 210 | if (_.transform(item, iteratee) >= value) { 211 | return index; 212 | } 213 | }))); 214 | }; 215 | 216 | _.range = function(start, stop, step) { 217 | var i, j, ref, ref1, ref2, results1; 218 | if (step == null) { 219 | step = 1; 220 | } 221 | stop = stop || start; 222 | if (start === stop) { 223 | start = 0; 224 | } 225 | results1 = []; 226 | for (i = j = ref = start, ref1 = stop, ref2 = step; ref2 > 0 ? j < ref1 : j > ref1; i = j += ref2) { 227 | results1.push(i); 228 | } 229 | return results1; 230 | }; 231 | 232 | }).call(this); 233 | -------------------------------------------------------------------------------- /src/collections.coffee: -------------------------------------------------------------------------------- 1 | window._ = {} 2 | _.each = _.forEach = (list, callback, context = @) -> 3 | if Array.isArray list 4 | callback.call(context, item, index, list) for item, index in list 5 | else 6 | callback.call(context, value, key, list) for own key, value of list 7 | 8 | 9 | _.map = _.collect = (list, callback, context = @) -> 10 | callback = callback or (value) -> value 11 | if Array.isArray list 12 | (callback.call(context, item, index, list) for item, index in list) 13 | else 14 | (callback.call(context, value, key, list) for own key, value of list) 15 | 16 | _.reduce = _.inject = _.foldl = (list, callback, startingValue = 0, context = @) -> 17 | iteratee = (element, index, list) -> 18 | startingValue = callback.call(context, startingValue, element, index, list) 19 | _.each list, iteratee, context 20 | startingValue 21 | 22 | _.reduceRight = _.foldr = (list, callback, startingValue = 0, context = @) -> 23 | _.reduce(list.reverse(), callback, startingValue, context) 24 | 25 | _.find = _.detect = (list, callback, context = @) -> 26 | result = undefined 27 | _.each list, (value, index, list) -> 28 | result = value if result is undefined and callback.call(context, value) is true 29 | result 30 | 31 | _.filter = _.select = (list, callback, context = @) -> 32 | results = [] 33 | _.each list, (value, index, list) -> 34 | if callback.call(context, value) then results.push(value) 35 | results 36 | 37 | _.where = (list, properties) -> 38 | results = [] 39 | _.each list, (value, index, list) -> 40 | if checkObjectForProperties(value, properties) 41 | results.push(value) 42 | results 43 | 44 | checkObjectForProperties = (object, properties) -> 45 | for key of properties 46 | unless checkObjectForProperty(key, properties[key], object) 47 | return false 48 | true 49 | 50 | checkObjectForProperty = (key, value, object) -> 51 | for otherKey of object 52 | if otherKey is key and value is object[key] 53 | return true 54 | false 55 | 56 | _.findWhere = (list, properties) -> 57 | _.where(list, properties)[0] 58 | 59 | 60 | _.reject = (list, callback, context = @) -> 61 | _.filter list, (value) -> 62 | !callback.call(context, value) 63 | 64 | _.every = _.all = (list, callback, context = @) -> 65 | status = true 66 | _.each list, (value) -> 67 | unless callback.call(context, value) 68 | status = false 69 | status 70 | 71 | _.some = _.any = (list, callback, context = @) -> 72 | _.filter(list, callback, context).length isnt 0 73 | 74 | _.contains = _.include = (list, value) -> 75 | _.some list, (element) -> element is value 76 | 77 | _.invoke = (list, methodName) -> 78 | args = [].slice.call(arguments, 2) 79 | _.map list, (value) -> 80 | value[methodName].apply(value, args) 81 | 82 | _.pluck = (list, key) -> 83 | _.map(list, (obj) -> obj[key]) 84 | 85 | _.maxOrMin = (list, callback, context, equality) -> 86 | result = undefined 87 | m = undefined 88 | _.each list, (value) -> 89 | if callback 90 | count = callback.call(context, value) 91 | else 92 | count = value 93 | m = m or count 94 | result = result or value 95 | if equality(m, count) 96 | result = value 97 | result or Number.POSITIVE_INFINITY 98 | 99 | _.max = (list, callback, context = @) -> 100 | _.maxOrMin list, 101 | callback, 102 | context, 103 | (m, count) -> 104 | count > m 105 | 106 | _.min = (list, callback, context = @) -> 107 | _.maxOrMin list, 108 | callback, 109 | context, 110 | (m, count) -> 111 | count < m 112 | 113 | _.sortBy = (list, iteratee, context = @) -> 114 | _.map _.map(list, ((value) -> 115 | {key: iteratee(value), value: value}), context).sort((a,b) -> 116 | a.key > b.key), 117 | (obj) -> obj.value, 118 | context 119 | 120 | _.organizeBy = (list, iteratee)-> 121 | getKey = (value, iteratee) -> 122 | if typeof iteratee is "string" 123 | value[iteratee] 124 | else 125 | iteratee(value) 126 | 127 | _.map list, (value) -> 128 | key: getKey(value, iteratee) 129 | value: value 130 | 131 | _.groupBy = (list, iteratee, context = @) -> 132 | result = {} 133 | _.each _.organizeBy(list, iteratee, context), (obj) -> 134 | if result[obj.key] is undefined 135 | result[obj.key] = [] 136 | result[obj.key].push(obj.value) 137 | result 138 | 139 | _.indexBy = (list, iteratee, context = @) -> 140 | result = {} 141 | _.each _.organizeBy(list, iteratee, context), (obj) -> 142 | result[obj.key] = obj.value 143 | result 144 | 145 | _.countBy = (list, iteratee, context = @) -> 146 | result = {} 147 | _.each _.organizeBy(list, iteratee, context), (obj) -> 148 | if result[obj.key] is undefined 149 | result[obj.key] = 0 150 | result[obj.key] += 1 151 | result 152 | 153 | _.objectValuesToArray = (list) -> 154 | if not Array.isArray(list) 155 | list = _.map list, 156 | (value) -> value 157 | else 158 | list 159 | 160 | _.randomIndex = (size) -> 161 | Math.floor(Math.random() * size) 162 | 163 | _.shuffle = (list) -> 164 | list = _.objectValuesToArray(list) 165 | size = list.length 166 | 167 | popRandomElementFrom = (list, index) -> 168 | item = list[index] 169 | list[index] = list[size] 170 | size -= 1 171 | item 172 | 173 | _.map [1..size], -> 174 | popRandomElementFrom list, 175 | _.randomIndex(list) 176 | 177 | _.sample = (list, n = 1) -> 178 | list = _.objectValuesToArray(list) 179 | _.map [1..n], -> 180 | list[_.randomIndex(list.length)] 181 | 182 | _.toArray = (list) -> 183 | _.map list, (value) -> 184 | value 185 | 186 | _.size = (list) -> 187 | _.toArray(list).length 188 | 189 | _.partition = (array, callback) -> 190 | [_.filter(array, callback), _.reject(array, callback)] 191 | -------------------------------------------------------------------------------- /src/collections.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var checkObjectForProperties, checkObjectForProperty, 3 | hasProp = {}.hasOwnProperty; 4 | 5 | window._ = {}; 6 | 7 | _.each = _.forEach = function(list, callback, context) { 8 | var i, index, item, key, len, results1, results2, value; 9 | if (context == null) { 10 | context = this; 11 | } 12 | if (Array.isArray(list)) { 13 | results1 = []; 14 | for (index = i = 0, len = list.length; i < len; index = ++i) { 15 | item = list[index]; 16 | results1.push(callback.call(context, item, index, list)); 17 | } 18 | return results1; 19 | } else { 20 | results2 = []; 21 | for (key in list) { 22 | if (!hasProp.call(list, key)) continue; 23 | value = list[key]; 24 | results2.push(callback.call(context, value, key, list)); 25 | } 26 | return results2; 27 | } 28 | }; 29 | 30 | _.map = _.collect = function(list, callback, context) { 31 | var i, index, item, key, len, results1, results2, value; 32 | if (context == null) { 33 | context = this; 34 | } 35 | callback = callback || function(value) { 36 | return value; 37 | }; 38 | if (Array.isArray(list)) { 39 | results1 = []; 40 | for (index = i = 0, len = list.length; i < len; index = ++i) { 41 | item = list[index]; 42 | results1.push(callback.call(context, item, index, list)); 43 | } 44 | return results1; 45 | } else { 46 | results2 = []; 47 | for (key in list) { 48 | if (!hasProp.call(list, key)) continue; 49 | value = list[key]; 50 | results2.push(callback.call(context, value, key, list)); 51 | } 52 | return results2; 53 | } 54 | }; 55 | 56 | _.reduce = _.inject = _.foldl = function(list, callback, startingValue, context) { 57 | var iteratee; 58 | if (startingValue == null) { 59 | startingValue = 0; 60 | } 61 | if (context == null) { 62 | context = this; 63 | } 64 | iteratee = function(element, index, list) { 65 | return startingValue = callback.call(context, startingValue, element, index, list); 66 | }; 67 | _.each(list, iteratee, context); 68 | return startingValue; 69 | }; 70 | 71 | _.reduceRight = _.foldr = function(list, callback, startingValue, context) { 72 | if (startingValue == null) { 73 | startingValue = 0; 74 | } 75 | if (context == null) { 76 | context = this; 77 | } 78 | return _.reduce(list.reverse(), callback, startingValue, context); 79 | }; 80 | 81 | _.find = _.detect = function(list, callback, context) { 82 | var result; 83 | if (context == null) { 84 | context = this; 85 | } 86 | result = void 0; 87 | _.each(list, function(value, index, list) { 88 | if (result === void 0 && callback.call(context, value) === true) { 89 | return result = value; 90 | } 91 | }); 92 | return result; 93 | }; 94 | 95 | _.filter = _.select = function(list, callback, context) { 96 | var results; 97 | if (context == null) { 98 | context = this; 99 | } 100 | results = []; 101 | _.each(list, function(value, index, list) { 102 | if (callback.call(context, value)) { 103 | return results.push(value); 104 | } 105 | }); 106 | return results; 107 | }; 108 | 109 | _.where = function(list, properties) { 110 | var results; 111 | results = []; 112 | _.each(list, function(value, index, list) { 113 | if (checkObjectForProperties(value, properties)) { 114 | return results.push(value); 115 | } 116 | }); 117 | return results; 118 | }; 119 | 120 | checkObjectForProperties = function(object, properties) { 121 | var key; 122 | for (key in properties) { 123 | if (!checkObjectForProperty(key, properties[key], object)) { 124 | return false; 125 | } 126 | } 127 | return true; 128 | }; 129 | 130 | checkObjectForProperty = function(key, value, object) { 131 | var otherKey; 132 | for (otherKey in object) { 133 | if (otherKey === key && value === object[key]) { 134 | return true; 135 | } 136 | } 137 | return false; 138 | }; 139 | 140 | _.findWhere = function(list, properties) { 141 | return _.where(list, properties)[0]; 142 | }; 143 | 144 | _.reject = function(list, callback, context) { 145 | if (context == null) { 146 | context = this; 147 | } 148 | return _.filter(list, function(value) { 149 | return !callback.call(context, value); 150 | }); 151 | }; 152 | 153 | _.every = _.all = function(list, callback, context) { 154 | var status; 155 | if (context == null) { 156 | context = this; 157 | } 158 | status = true; 159 | _.each(list, function(value) { 160 | if (!callback.call(context, value)) { 161 | return status = false; 162 | } 163 | }); 164 | return status; 165 | }; 166 | 167 | _.some = _.any = function(list, callback, context) { 168 | if (context == null) { 169 | context = this; 170 | } 171 | return _.filter(list, callback, context).length !== 0; 172 | }; 173 | 174 | _.contains = _.include = function(list, value) { 175 | return _.some(list, function(element) { 176 | return element === value; 177 | }); 178 | }; 179 | 180 | _.invoke = function(list, methodName) { 181 | var args; 182 | args = [].slice.call(arguments, 2); 183 | return _.map(list, function(value) { 184 | return value[methodName].apply(value, args); 185 | }); 186 | }; 187 | 188 | _.pluck = function(list, key) { 189 | return _.map(list, function(obj) { 190 | return obj[key]; 191 | }); 192 | }; 193 | 194 | _.maxOrMin = function(list, callback, context, equality) { 195 | var m, result; 196 | result = void 0; 197 | m = void 0; 198 | _.each(list, function(value) { 199 | var count; 200 | if (callback) { 201 | count = callback.call(context, value); 202 | } else { 203 | count = value; 204 | } 205 | m = m || count; 206 | result = result || value; 207 | if (equality(m, count)) { 208 | return result = value; 209 | } 210 | }); 211 | return result || Number.POSITIVE_INFINITY; 212 | }; 213 | 214 | _.max = function(list, callback, context) { 215 | if (context == null) { 216 | context = this; 217 | } 218 | return _.maxOrMin(list, callback, context, function(m, count) { 219 | return count > m; 220 | }); 221 | }; 222 | 223 | _.min = function(list, callback, context) { 224 | if (context == null) { 225 | context = this; 226 | } 227 | return _.maxOrMin(list, callback, context, function(m, count) { 228 | return count < m; 229 | }); 230 | }; 231 | 232 | _.sortBy = function(list, iteratee, context) { 233 | if (context == null) { 234 | context = this; 235 | } 236 | return _.map(_.map(list, (function(value) { 237 | return { 238 | key: iteratee(value), 239 | value: value 240 | }; 241 | }), context).sort(function(a, b) { 242 | return a.key > b.key; 243 | }), function(obj) { 244 | return obj.value; 245 | }, context); 246 | }; 247 | 248 | _.organizeBy = function(list, iteratee) { 249 | var getKey; 250 | getKey = function(value, iteratee) { 251 | if (typeof iteratee === "string") { 252 | return value[iteratee]; 253 | } else { 254 | return iteratee(value); 255 | } 256 | }; 257 | return _.map(list, function(value) { 258 | return { 259 | key: getKey(value, iteratee), 260 | value: value 261 | }; 262 | }); 263 | }; 264 | 265 | _.groupBy = function(list, iteratee, context) { 266 | var result; 267 | if (context == null) { 268 | context = this; 269 | } 270 | result = {}; 271 | _.each(_.organizeBy(list, iteratee, context), function(obj) { 272 | if (result[obj.key] === void 0) { 273 | result[obj.key] = []; 274 | } 275 | return result[obj.key].push(obj.value); 276 | }); 277 | return result; 278 | }; 279 | 280 | _.indexBy = function(list, iteratee, context) { 281 | var result; 282 | if (context == null) { 283 | context = this; 284 | } 285 | result = {}; 286 | _.each(_.organizeBy(list, iteratee, context), function(obj) { 287 | return result[obj.key] = obj.value; 288 | }); 289 | return result; 290 | }; 291 | 292 | _.countBy = function(list, iteratee, context) { 293 | var result; 294 | if (context == null) { 295 | context = this; 296 | } 297 | result = {}; 298 | _.each(_.organizeBy(list, iteratee, context), function(obj) { 299 | if (result[obj.key] === void 0) { 300 | result[obj.key] = 0; 301 | } 302 | return result[obj.key] += 1; 303 | }); 304 | return result; 305 | }; 306 | 307 | _.objectValuesToArray = function(list) { 308 | if (!Array.isArray(list)) { 309 | return list = _.map(list, function(value) { 310 | return value; 311 | }); 312 | } else { 313 | return list; 314 | } 315 | }; 316 | 317 | _.randomIndex = function(size) { 318 | return Math.floor(Math.random() * size); 319 | }; 320 | 321 | _.shuffle = function(list) { 322 | var i, popRandomElementFrom, results1, size; 323 | list = _.objectValuesToArray(list); 324 | size = list.length; 325 | popRandomElementFrom = function(list, index) { 326 | var item; 327 | item = list[index]; 328 | list[index] = list[size]; 329 | size -= 1; 330 | return item; 331 | }; 332 | return _.map((function() { 333 | results1 = []; 334 | for (var i = 1; 1 <= size ? i <= size : i >= size; 1 <= size ? i++ : i--){ results1.push(i); } 335 | return results1; 336 | }).apply(this), function() { 337 | return popRandomElementFrom(list, _.randomIndex(list)); 338 | }); 339 | }; 340 | 341 | _.sample = function(list, n) { 342 | var i, results1; 343 | if (n == null) { 344 | n = 1; 345 | } 346 | list = _.objectValuesToArray(list); 347 | return _.map((function() { 348 | results1 = []; 349 | for (var i = 1; 1 <= n ? i <= n : i >= n; 1 <= n ? i++ : i--){ results1.push(i); } 350 | return results1; 351 | }).apply(this), function() { 352 | return list[_.randomIndex(list.length)]; 353 | }); 354 | }; 355 | 356 | _.toArray = function(list) { 357 | return _.map(list, function(value) { 358 | return value; 359 | }); 360 | }; 361 | 362 | _.size = function(list) { 363 | return _.toArray(list).length; 364 | }; 365 | 366 | _.partition = function(array, callback) { 367 | return [_.filter(array, callback), _.reject(array, callback)]; 368 | }; 369 | 370 | }).call(this); 371 | -------------------------------------------------------------------------------- /src/functions.coffee: -------------------------------------------------------------------------------- 1 | _.bind = (fn, context, partial...) -> 2 | return (full...) -> 3 | args = partial.concat(full) 4 | fn.apply(context, args) 5 | 6 | _.bindAll = (object, functions...) -> 7 | _.each functions, (fn) -> 8 | _.bind(fn, object) 9 | object 10 | 11 | fillInArguments = (partial, full) -> 12 | _.each partial, (arg, index) -> 13 | if arg is "_" then partial[index] = full.pop() 14 | partial.concat(full) 15 | 16 | _.partial = (fn, partial...) -> 17 | return (full...) -> 18 | args = fillInArguments(partial, full) 19 | fn.apply(this, args) 20 | 21 | _.memoize = (fn) -> 22 | cache = {} 23 | return (args...) -> 24 | cache[args[0]] or cache[args[0]] = fn.apply(this, args) 25 | 26 | _.delay = (fn, wait, args...) -> 27 | setTimeout((-> fn.apply(fn, args)), wait) 28 | 29 | _.defer = (fn, args...) -> 30 | _.delay(fn, 1, args) 31 | 32 | _.thorttle = (fn, wait) -> 33 | blocking = false 34 | (args...) -> 35 | unless blocking 36 | fn.apply(fn, args) 37 | blocking = true 38 | _.delay((-> blocking = false), wait) 39 | 40 | _.debounce = (fn, wait) -> 41 | blocking = false 42 | id = undefined 43 | (args...) -> 44 | unless blocking 45 | fn.apply(fn, args) 46 | blocking = true 47 | id = _.delay((-> blocking = false), wait) 48 | else 49 | clearTimeout(id) 50 | id = _.delay((-> blocking = false), wait) 51 | 52 | _.once = (fn) -> 53 | called = false 54 | (args...) -> 55 | unless called 56 | called = true 57 | fn.apply(fn, args) 58 | 59 | _.after = (count, fn) -> 60 | (args...) -> 61 | if --count < 1 62 | fn.apply(fn, args) 63 | 64 | _.before = (count, fn) -> 65 | result = undefined 66 | (args...) -> 67 | if 0 < --count 68 | result = fn.apply(fn, args) 69 | else 70 | result 71 | 72 | _.wrap = (fn, wrapper) -> 73 | (args...) -> 74 | args.unshift(fn) 75 | wrapper.apply(wrapper, args) 76 | 77 | _.negate = (predicate) -> 78 | (args...) -> 79 | not predicate.apply(predicate, args) 80 | 81 | _.compose = (functions...) -> 82 | (args...) -> 83 | _.each functions, (fn) -> 84 | args = [fn.apply(fn, args)] 85 | args[0] 86 | -------------------------------------------------------------------------------- /src/functions.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var fillInArguments, 3 | slice = [].slice; 4 | 5 | _.bind = function() { 6 | var context, fn, partial; 7 | fn = arguments[0], context = arguments[1], partial = 3 <= arguments.length ? slice.call(arguments, 2) : []; 8 | return function() { 9 | var args, full; 10 | full = 1 <= arguments.length ? slice.call(arguments, 0) : []; 11 | args = partial.concat(full); 12 | return fn.apply(context, args); 13 | }; 14 | }; 15 | 16 | _.bindAll = function() { 17 | var functions, object; 18 | object = arguments[0], functions = 2 <= arguments.length ? slice.call(arguments, 1) : []; 19 | _.each(functions, function(fn) { 20 | return _.bind(fn, object); 21 | }); 22 | return object; 23 | }; 24 | 25 | fillInArguments = function(partial, full) { 26 | _.each(partial, function(arg, index) { 27 | if (arg === "_") { 28 | return partial[index] = full.pop(); 29 | } 30 | }); 31 | return partial.concat(full); 32 | }; 33 | 34 | _.partial = function() { 35 | var fn, partial; 36 | fn = arguments[0], partial = 2 <= arguments.length ? slice.call(arguments, 1) : []; 37 | return function() { 38 | var args, full; 39 | full = 1 <= arguments.length ? slice.call(arguments, 0) : []; 40 | args = fillInArguments(partial, full); 41 | return fn.apply(this, args); 42 | }; 43 | }; 44 | 45 | _.memoize = function(fn) { 46 | var cache; 47 | cache = {}; 48 | return function() { 49 | var args; 50 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 51 | return cache[args[0]] || (cache[args[0]] = fn.apply(this, args)); 52 | }; 53 | }; 54 | 55 | _.delay = function() { 56 | var args, fn, wait; 57 | fn = arguments[0], wait = arguments[1], args = 3 <= arguments.length ? slice.call(arguments, 2) : []; 58 | return setTimeout((function() { 59 | return fn.apply(fn, args); 60 | }), wait); 61 | }; 62 | 63 | _.defer = function() { 64 | var args, fn; 65 | fn = arguments[0], args = 2 <= arguments.length ? slice.call(arguments, 1) : []; 66 | return _.delay(fn, 1, args); 67 | }; 68 | 69 | _.thorttle = function(fn, wait) { 70 | var blocking; 71 | blocking = false; 72 | return function() { 73 | var args; 74 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 75 | if (!blocking) { 76 | fn.apply(fn, args); 77 | blocking = true; 78 | return _.delay((function() { 79 | return blocking = false; 80 | }), wait); 81 | } 82 | }; 83 | }; 84 | 85 | _.debounce = function(fn, wait) { 86 | var blocking, id; 87 | blocking = false; 88 | id = void 0; 89 | return function() { 90 | var args; 91 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 92 | if (!blocking) { 93 | fn.apply(fn, args); 94 | blocking = true; 95 | return id = _.delay((function() { 96 | return blocking = false; 97 | }), wait); 98 | } else { 99 | clearTimeout(id); 100 | return id = _.delay((function() { 101 | return blocking = false; 102 | }), wait); 103 | } 104 | }; 105 | }; 106 | 107 | _.once = function(fn) { 108 | var called; 109 | called = false; 110 | return function() { 111 | var args; 112 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 113 | if (!called) { 114 | called = true; 115 | return fn.apply(fn, args); 116 | } 117 | }; 118 | }; 119 | 120 | _.after = function(count, fn) { 121 | return function() { 122 | var args; 123 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 124 | if (--count < 1) { 125 | return fn.apply(fn, args); 126 | } 127 | }; 128 | }; 129 | 130 | _.before = function(count, fn) { 131 | var result; 132 | result = void 0; 133 | return function() { 134 | var args; 135 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 136 | if (0 < --count) { 137 | return result = fn.apply(fn, args); 138 | } else { 139 | return result; 140 | } 141 | }; 142 | }; 143 | 144 | _.wrap = function(fn, wrapper) { 145 | return function() { 146 | var args; 147 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 148 | args.unshift(fn); 149 | return wrapper.apply(wrapper, args); 150 | }; 151 | }; 152 | 153 | _.negate = function(predicate) { 154 | return function() { 155 | var args; 156 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 157 | return !predicate.apply(predicate, args); 158 | }; 159 | }; 160 | 161 | _.compose = function() { 162 | var functions; 163 | functions = 1 <= arguments.length ? slice.call(arguments, 0) : []; 164 | return function() { 165 | var args; 166 | args = 1 <= arguments.length ? slice.call(arguments, 0) : []; 167 | _.each(functions, function(fn) { 168 | return args = [fn.apply(fn, args)]; 169 | }); 170 | return args[0]; 171 | }; 172 | }; 173 | 174 | }).call(this); 175 | -------------------------------------------------------------------------------- /src/objects.coffee: -------------------------------------------------------------------------------- 1 | _.keys = (obj) -> 2 | _.map obj, (value, key) -> key 3 | 4 | _.values = (obj) -> 5 | _.map obj, (value) -> value 6 | 7 | _.pairs = (obj) -> 8 | _.map obj, (value, key) -> [key, value] 9 | 10 | _.invert = (obj) -> 11 | _.each obj, (value, key) -> 12 | obj[value] = key 13 | delete obj[key] 14 | obj 15 | 16 | _.functions = _.methods = (obj) -> 17 | _.compact _.map obj, (value, key) -> 18 | if typeof value is 'function' then key 19 | 20 | _.extend = (destination, sources...) -> 21 | _.each sources, (obj) -> 22 | _.each obj, (value, key) -> 23 | destination[key] = value 24 | destination 25 | 26 | _.isFunction = (object) -> 27 | typeof object is 'function' 28 | 29 | _.isElement = (obj) -> 30 | not not (obj and obj.nodeType is 1) 31 | 32 | _.isArray = (obj) -> 33 | Array.isArray(obj) 34 | 35 | _.isObject = (value) -> 36 | typeof value is 'function' or typeof value is 'object' 37 | 38 | _.isArgument = (obj) -> 39 | obj.toString() is "[object Arguments]" 40 | 41 | _.isNumber = (value) -> 42 | typeof value is 'number' or typeof value is 'NaN' 43 | 44 | _.isString = (value) -> 45 | typeof value is 'string' 46 | 47 | _.isBoolean = (value) -> 48 | typeof value is 'boolean' 49 | 50 | _.isDate = (value) -> 51 | value instanceof Date 52 | 53 | _.isRegExp = (value) -> 54 | value instanceof RegExp 55 | 56 | _.isNaN = (value) -> 57 | Number.isNaN(value) 58 | 59 | _.isUndefined = (value) -> 60 | value is undefined 61 | 62 | _.isNull = (value) -> 63 | value is null 64 | 65 | _.isFinite = (value) -> 66 | isFinite(value) and not isNaN(parseFloat(value)) 67 | 68 | filterObject = (whiteList, obj, keys...) -> 69 | keys = _.flatten(keys, true) 70 | fn = keys[0] 71 | result = {} 72 | _.each obj, (value, key) -> 73 | containsValue = _.isFunction(fn) and fn(value) or key in keys 74 | if whiteList and containsValue or not whiteList and not containsValue 75 | result[key] = value 76 | result 77 | 78 | _.pick = (obj, keys...) -> 79 | filterObject(true, obj, _.flatten(keys, true)) 80 | 81 | _.omit = (obj, keys...) -> 82 | filterObject(false, obj, _.flatten(keys, true)) 83 | 84 | _.defaults = (object, defaults...) -> 85 | _.each defaults, (obj) -> 86 | _.each obj, (value, key) -> 87 | unless object.hasOwnProperty(key) 88 | object[key] = value 89 | object 90 | 91 | _.clone = (obj) -> 92 | result = {} 93 | console.log("WORKS") 94 | _.each obj, (value, key) -> 95 | result[key] = value 96 | result 97 | 98 | _.has = (obj, key) -> 99 | Object.prototype.hasOwnProperty.call(obj, key) 100 | 101 | _.property = (key) -> 102 | (obj) -> 103 | obj[key] 104 | -------------------------------------------------------------------------------- /src/objects.js: -------------------------------------------------------------------------------- 1 | (function() { 2 | var filterObject, 3 | slice = [].slice, 4 | indexOf = [].indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (i in this && this[i] === item) return i; } return -1; }; 5 | 6 | _.keys = function(obj) { 7 | return _.map(obj, function(value, key) { 8 | return key; 9 | }); 10 | }; 11 | 12 | _.values = function(obj) { 13 | return _.map(obj, function(value) { 14 | return value; 15 | }); 16 | }; 17 | 18 | _.pairs = function(obj) { 19 | return _.map(obj, function(value, key) { 20 | return [key, value]; 21 | }); 22 | }; 23 | 24 | _.invert = function(obj) { 25 | _.each(obj, function(value, key) { 26 | obj[value] = key; 27 | return delete obj[key]; 28 | }); 29 | return obj; 30 | }; 31 | 32 | _.functions = _.methods = function(obj) { 33 | return _.compact(_.map(obj, function(value, key) { 34 | if (typeof value === 'function') { 35 | return key; 36 | } 37 | })); 38 | }; 39 | 40 | _.extend = function() { 41 | var destination, sources; 42 | destination = arguments[0], sources = 2 <= arguments.length ? slice.call(arguments, 1) : []; 43 | _.each(sources, function(obj) { 44 | return _.each(obj, function(value, key) { 45 | return destination[key] = value; 46 | }); 47 | }); 48 | return destination; 49 | }; 50 | 51 | _.isFunction = function(object) { 52 | return typeof object === 'function'; 53 | }; 54 | 55 | _.isElement = function(obj) { 56 | return !!(obj && obj.nodeType === 1); 57 | }; 58 | 59 | _.isArray = function(obj) { 60 | return Array.isArray(obj); 61 | }; 62 | 63 | _.isObject = function(value) { 64 | return typeof value === 'function' || typeof value === 'object'; 65 | }; 66 | 67 | _.isArgument = function(obj) { 68 | return obj.toString() === "[object Arguments]"; 69 | }; 70 | 71 | _.isNumber = function(value) { 72 | return typeof value === 'number' || typeof value === 'NaN'; 73 | }; 74 | 75 | _.isString = function(value) { 76 | return typeof value === 'string'; 77 | }; 78 | 79 | _.isBoolean = function(value) { 80 | return typeof value === 'boolean'; 81 | }; 82 | 83 | _.isDate = function(value) { 84 | return value instanceof Date; 85 | }; 86 | 87 | _.isRegExp = function(value) { 88 | return value instanceof RegExp; 89 | }; 90 | 91 | _.isNaN = function(value) { 92 | return Number.isNaN(value); 93 | }; 94 | 95 | _.isUndefined = function(value) { 96 | return value === void 0; 97 | }; 98 | 99 | _.isNull = function(value) { 100 | return value === null; 101 | }; 102 | 103 | _.isFinite = function(value) { 104 | return isFinite(value) && !isNaN(parseFloat(value)); 105 | }; 106 | 107 | filterObject = function() { 108 | var fn, keys, obj, result, whiteList; 109 | whiteList = arguments[0], obj = arguments[1], keys = 3 <= arguments.length ? slice.call(arguments, 2) : []; 110 | keys = _.flatten(keys, true); 111 | fn = keys[0]; 112 | result = {}; 113 | _.each(obj, function(value, key) { 114 | var containsValue; 115 | containsValue = _.isFunction(fn) && fn(value) || indexOf.call(keys, key) >= 0; 116 | if (whiteList && containsValue || !whiteList && !containsValue) { 117 | return result[key] = value; 118 | } 119 | }); 120 | return result; 121 | }; 122 | 123 | _.pick = function() { 124 | var keys, obj; 125 | obj = arguments[0], keys = 2 <= arguments.length ? slice.call(arguments, 1) : []; 126 | return filterObject(true, obj, _.flatten(keys, true)); 127 | }; 128 | 129 | _.omit = function() { 130 | var keys, obj; 131 | obj = arguments[0], keys = 2 <= arguments.length ? slice.call(arguments, 1) : []; 132 | return filterObject(false, obj, _.flatten(keys, true)); 133 | }; 134 | 135 | _.defaults = function() { 136 | var defaults, object; 137 | object = arguments[0], defaults = 2 <= arguments.length ? slice.call(arguments, 1) : []; 138 | _.each(defaults, function(obj) { 139 | return _.each(obj, function(value, key) { 140 | if (!object.hasOwnProperty(key)) { 141 | return object[key] = value; 142 | } 143 | }); 144 | }); 145 | return object; 146 | }; 147 | 148 | _.clone = function(obj) { 149 | var result; 150 | result = {}; 151 | console.log("WORKS"); 152 | _.each(obj, function(value, key) { 153 | return result[key] = value; 154 | }); 155 | return result; 156 | }; 157 | 158 | _.has = function(obj, key) { 159 | return Object.prototype.hasOwnProperty.call(obj, key); 160 | }; 161 | 162 | _.property = function(key) { 163 | return function(obj) { 164 | return obj[key]; 165 | }; 166 | }; 167 | 168 | }).call(this); 169 | -------------------------------------------------------------------------------- /src/utilities.coffee: -------------------------------------------------------------------------------- 1 | 2 | _.identity = (value) -> value 3 | 4 | _.constant = (value) -> 5 | -> value 6 | 7 | _.noop = -> undefined 8 | 9 | _.times = (n, iteratee, context) -> 10 | iteratee.call(context, i) for i in [1..n] 11 | 12 | _.random = (min, max) -> 13 | if min is undefined 14 | return NaN 15 | if max is undefined 16 | max = min 17 | min = 0 18 | min + Math.floor(Math.random() * (max - min + 1)) 19 | 20 | _.mixin = (fns) -> 21 | for name of fns 22 | _[name] = fns[name] 23 | 24 | _.storage = {} 25 | 26 | _.uniqueId = (name) -> 27 | _.storage[name] = _.storage[name] or 0 28 | name + ++_.storage[name] 29 | 30 | _.escapeChar = {} 31 | _.escapeChar['&'] = '&' 32 | _.escapeChar['<'] = '<' 33 | _.escapeChar['>'] = '>' 34 | _.escapeChar['"'] = '"' 35 | _.escapeChar['\''] = ''' 36 | _.escapeChar['`'] = '`' 37 | 38 | _.escape = (str) -> 39 | newStr = '' 40 | for i in str 41 | newStr += _.escapeChar[i] or i 42 | newStr 43 | 44 | _.escapeChar['&'] = '&' 45 | _.escapeChar['<'] = '<' 46 | _.escapeChar['>'] = '>' 47 | _.escapeChar['"'] = '"' 48 | _.escapeChar['''] = '\'' 49 | _.escapeChar['`'] = '`' 50 | 51 | _.unescape = (str) -> 52 | newStr = '' 53 | i = 0 54 | while i < str.length 55 | escapeChar = _.escapeChar[str.substring(i, i + 5)] 56 | if escapeChar 57 | newStr += escapeChar 58 | i += 4 59 | else 60 | newStr += str[i] 61 | i++ 62 | newStr 63 | -------------------------------------------------------------------------------- /src/utilities.js: -------------------------------------------------------------------------------- 1 | // Generated by CoffeeScript 1.9.3 2 | (function() { 3 | _.identity = function(value) { 4 | return value; 5 | }; 6 | 7 | _.constant = function(value) { 8 | return function() { 9 | return value; 10 | }; 11 | }; 12 | 13 | _.noop = function() { 14 | return void 0; 15 | }; 16 | 17 | _.times = function(n, iteratee, context) { 18 | var i, j, ref, results; 19 | results = []; 20 | for (i = j = 1, ref = n; 1 <= ref ? j <= ref : j >= ref; i = 1 <= ref ? ++j : --j) { 21 | results.push(iteratee.call(context, i)); 22 | } 23 | return results; 24 | }; 25 | 26 | _.random = function(min, max) { 27 | if (min === void 0) { 28 | return NaN; 29 | } 30 | if (max === void 0) { 31 | max = min; 32 | min = 0; 33 | } 34 | return min + Math.floor(Math.random() * (max - min + 1)); 35 | }; 36 | 37 | _.mixin = function(fns) { 38 | var name, results; 39 | results = []; 40 | for (name in fns) { 41 | results.push(_[name] = fns[name]); 42 | } 43 | return results; 44 | }; 45 | 46 | _.storage = {}; 47 | 48 | _.uniqueId = function(name) { 49 | _.storage[name] = _.storage[name] || 0; 50 | return name + ++_.storage[name]; 51 | }; 52 | 53 | _.escapeChar = {}; 54 | 55 | _.escapeChar['&'] = '&'; 56 | 57 | _.escapeChar['<'] = '<'; 58 | 59 | _.escapeChar['>'] = '>'; 60 | 61 | _.escapeChar['"'] = '"'; 62 | 63 | _.escapeChar['\''] = '''; 64 | 65 | _.escapeChar['`'] = '`'; 66 | 67 | _.escape = function(str) { 68 | var i, j, len, newStr; 69 | newStr = ''; 70 | for (j = 0, len = str.length; j < len; j++) { 71 | i = str[j]; 72 | newStr += _.escapeChar[i] || i; 73 | } 74 | return newStr; 75 | }; 76 | 77 | _.escapeChar['&'] = '&'; 78 | 79 | _.escapeChar['<'] = '<'; 80 | 81 | _.escapeChar['>'] = '>'; 82 | 83 | _.escapeChar['"'] = '"'; 84 | 85 | _.escapeChar['''] = '\''; 86 | 87 | _.escapeChar['`'] = '`'; 88 | 89 | _.unescape = function(str) { 90 | var escapeChar, i, newStr; 91 | newStr = ''; 92 | i = 0; 93 | while (i < str.length) { 94 | escapeChar = _.escapeChar[str.substring(i, i + 5)]; 95 | if (escapeChar) { 96 | newStr += escapeChar; 97 | i += 4; 98 | } else { 99 | newStr += str[i]; 100 | } 101 | i++; 102 | } 103 | return newStr; 104 | }; 105 | 106 | }).call(this); 107 | --------------------------------------------------------------------------------