├── .coveralls.yaml ├── .editorconfig ├── .gitignore ├── .jshintignore ├── .jshintrc ├── .npmignore ├── .travis.yml ├── CHANGELOG.md ├── LICENSE.txt ├── README.md ├── and.js ├── apply.js ├── assign.js ├── bind-all.js ├── clone.js ├── compose.js ├── converge.js ├── curry.js ├── defaults.js ├── del.js ├── env-is.js ├── equals.js ├── exists.js ├── find-index.js ├── find.js ├── flip.js ├── group-by.js ├── has-keypaths.js ├── has-properties.js ├── includes.js ├── index-by.js ├── index.js ├── instance-of.js ├── is-boolean.js ├── is-empty.js ├── is-function.js ├── is-integer.js ├── is-number.js ├── is-object.js ├── is-regexp.js ├── is-string.js ├── keys-in.js ├── last.js ├── lens.js ├── noop.js ├── not.js ├── omit.js ├── or.js ├── package.json ├── pass-all.js ├── pass-any.js ├── pick.js ├── pluck.js ├── put.js ├── set.js ├── test ├── test-and.js ├── test-apply.js ├── test-assign.js ├── test-bind-all.js ├── test-clone.js ├── test-compose.js ├── test-converge.js ├── test-curry.js ├── test-defaults.js ├── test-del.js ├── test-env-is.js ├── test-equals.js ├── test-exists.js ├── test-find-index.js ├── test-find.js ├── test-flip.js ├── test-group-by.js ├── test-has-keypaths.js ├── test-has-properties.js ├── test-includes.js ├── test-index-by.js ├── test-instance-of.js ├── test-is-boolean.js ├── test-is-empty.js ├── test-is-function.js ├── test-is-integer.js ├── test-is-number.js ├── test-is-object.js ├── test-is-regexp.js ├── test-is-string.js ├── test-keys-in.js ├── test-last.js ├── test-lens.js ├── test-noop.js ├── test-not.js ├── test-omit.js ├── test-or.js ├── test-pass-all.js ├── test-pass-any.js ├── test-pick.js ├── test-pluck.js ├── test-put.js ├── test-set.js ├── test-values.js └── test-xor.js ├── values.js └── xor.js /.coveralls.yaml: -------------------------------------------------------------------------------- 1 | service_name: travis-pro 2 | repo_token: 97MqNLghsyq3P05ARr8loUQEgTpjRNnTg -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # editorconfig.org 2 | root = true 3 | 4 | [*] 5 | end_of_line = lf 6 | charset = utf-8 7 | insert_final_newline = true 8 | trim_trailing_whitespace = true 9 | indent_style = space 10 | indent_size = 2 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | out 3 | jsdoc.conf 4 | -------------------------------------------------------------------------------- /.jshintignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | es6/ 3 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "node": true, 3 | "strict": false, 4 | "undef": true, 5 | "unused": true 6 | } 7 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | test/ 2 | .travis.yml 3 | .jshintrc 4 | .jshintignore 5 | .coveralls.yaml 6 | .editorconfig 7 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - "0.10" 4 | - "0.12" 5 | sudo: false 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Change Log 2 | All notable changes to this project will be documented in this file. 3 | This project adheres to [Semantic Versioning](http://semver.org/). 4 | 5 | ## [0.18.0] - 2015-05-09 6 | ### Added 7 | - [`indexBy`](https://github.com/tjmehta/101#indexBy) module 8 | 9 | ## [0.17.0] - 2015-05-07 10 | ### Added 11 | - [`bindAll`](https://github.com/tjmehta/101#bindAll) module 12 | - [`keysIn`](https://github.com/tjmehta/101#keysIn) module 13 | - This CHANGELOG file 14 | 15 | [0.17.0]: https://github.com/tjmehta/101/compare/v0.16.1...v0.17.0 16 | -------------------------------------------------------------------------------- /LICENSE.txt: -------------------------------------------------------------------------------- 1 | (The MIT License) 2 | 3 | Copyright (c) 2014 Tejesh Mehta 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and 6 | associated documentation files (the 'Software'), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to 9 | the following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included in all copies or substantial 12 | portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 16 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 17 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 18 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 19 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ![101](http://i.imgur.com/MFrmMt6.png) 2 | === 3 | [![NPM](https://nodei.co/npm/101.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/101/) 4 | 5 | [![Build Status](https://travis-ci.org/tjmehta/101.svg?branch=master)](https://travis-ci.org/tjmehta/101) 6 | [![Coverage Status](https://coveralls.io/repos/tjmehta/101/badge.png)](https://coveralls.io/r/tjmehta/101) 7 | [![Dependency Status](https://david-dm.org/tjmehta/101.svg)](https://david-dm.org/tjmehta/101) 8 | [![devDependency Status](https://david-dm.org/tjmehta/101/dev-status.svg)](https://david-dm.org/tjmehta/101#info=devDependencies) 9 | 10 | # Why another JS util library? 11 | ### 1) 101 will be maintained to minimize overlap with vanilla JS. 12 | * 101 utils are made to work well with vanilla JS methods. 13 | * 101 will only duplicate vanilla JS to provide Functional Programming paradigms, or if 14 | the method is not available in a widely supported JS version (currently ES5). 15 | * Other libraries often duplicate a lot of ES5: forEach, map, reduce, filter, sort, and more. 16 | 17 | ### 2) No need for custom builds. 18 | * With 101, import naturally, and what you use will be bundled. 19 | * Each util method is a module that can be required `require('101/')`. 20 | * Currently CommonJS (node, browserify, webpack, etc) is supported, I will add other module system support on request. 21 | * Other libraries can be large, and require manually creating custom builds when optimizing for size. 22 | 23 | ### Why not release each as individual modules? 24 | I usually agree with this philosophy; however, while in practice, adherence to the module-pattern 25 | can become quite annoying for micro-modules (like those in 101): 26 | * Micro-modules existance throughout a project can change very frequently, because of this one may find 27 | themselves constantly updating their package.json (repeatedly adding and removing the same micro-modules). 28 | * Unbundling micro-modules can lead to projects with hundreds of dependencies which can be tedious to maintain. 29 | 30 | 31 | 32 | # Installation 33 | 34 | `npm install 101` 35 | 36 | # Usage 37 | 38 | ## assign (aka extend) 39 | 40 | Just like ES6's `Object.assign`. Extend an object with any number of objects (returns original). 41 | 42 | ```js 43 | var assign = require('101/assign'); 44 | 45 | var target = { foo: 1 }; 46 | var source1 = { bar: 1 }; 47 | var source2 = { baz: 1 }; 48 | assign(target, source1) // { foo: 1, bar: 1, baz: 1 } target extended with source objects 49 | assign(target, source1, source2) // { foo: 1, bar: 1, baz: 1 } target extended with source objects 50 | ``` 51 | 52 | ## and 53 | 54 | Functional version of `&&`. Works great with `array.reduce`. 55 | 56 | ```js 57 | var and = require('101/and'); 58 | 59 | and(true, false); // false 60 | and(true, true); // true 61 | and(true, "foo"); // "foo" 62 | ``` 63 | 64 | ## apply 65 | 66 | Functional version of `function.apply`. 67 | Supports partial functionality (great with array functions). 68 | 69 | ```js 70 | var apply = require('101/apply'); 71 | [sum].map(apply(null, [1, 2, 3])); // [6] = [sum(1,2,3)] = [1+2+3] 72 | function sum () { /* sums all arguments */ } 73 | apply({ prop: 'val' })(function () { return this.prop; }); // 'val' 74 | ``` 75 | 76 | ## bindAll 77 | 78 | Bind methods in an object. 79 | You can pass an array containing the name of the methods to bind as second 80 | argument or leave it empty to bind all the available methods. 81 | 82 | ```js 83 | var bindAll = require('101/bind-all'); 84 | var obj = { 85 | init: function() { 86 | this.on(this.handler); 87 | }, 88 | on: function(handler) { 89 | return handler(); 90 | }, 91 | handler: function() { 92 | console.log(this.msg); 93 | }, 94 | msg: 'Hello World' 95 | } 96 | 97 | obj.init(); // undefined 98 | 99 | bindAll(obj); 100 | obj.init(); // "Hello World" 101 | 102 | bindAll(obj, ['handler']); 103 | obj.init(); // "Hello World" 104 | ``` 105 | 106 | ## clone 107 | 108 | It's [clone](https://www.npmjs.org/package/clone) (Only exporting this bc it is used internal to 101) 109 | 110 | ```js 111 | var clone = require('101/clone'); 112 | var obj = { 113 | foo: 1, 114 | bar: 2 115 | }; 116 | 117 | clone(obj); // { foo: 1, bar: 2 } 118 | ``` 119 | 120 | ## compose 121 | 122 | Functional composition method. Works great with `array.reduce`. 123 | 124 | ```js 125 | var compose = require('101/compose'); 126 | 127 | compose(isNaN, parseInt)('nope'); // isNaN(parseInt('nope')) // true 128 | ``` 129 | 130 | ## converge 131 | 132 | Converges an array of functions into one. Works great with `compose`. 133 | 134 | ```js 135 | var converge = require('101/converge'); 136 | 137 | converge(mul, [add, sub])(6, 2); // mul(add(6, 2), sub(6, 2)) // (6+2) * (6-2) = 36 138 | 139 | [ {a: true, b: false} 140 | , {a: false, b: false} 141 | , {a: true, b: true} 142 | ].filter(converge(and , [pluck("a") , pluck("b")])); // [{a: true, b: true}] 143 | 144 | [f, converge(g, [h, i]), j].reduce(compose); // f(g(h(j), i(j))) 145 | ``` 146 | 147 | ## curry 148 | 149 | Returns a curried function. 150 | 151 | ```js 152 | var curry = require('101/curry'); 153 | 154 | function add(a, b) { return a + b; } 155 | 156 | var curriedAdd = curry(add); 157 | var add2 = curriedAdd(2); 158 | 159 | add2(6); // 8 160 | add2(8); // 10 161 | 162 | function join() { return Array.prototype.slice.call(arguments).join(''); } 163 | 164 | curry(join, 3)(1)(0)(1); // "101" 165 | ``` 166 | 167 | ## defaults 168 | 169 | Fill non-existing object values with defaults. Use it to set defaults on options. Works with 170 | supplying default values in sub-objects as well. Supports partial functionality (great with array 171 | functions). Mutates first argument and returns mutated argument. 172 | 173 | ```js 174 | var defaults = require('101/defaults'); 175 | var opts = { foo: 0, bar: 1 }; 176 | var defs = { foo: 1, bar: 2, qux: 2 }; 177 | 178 | defaults(opts, defs); // returns mutated `opts` { foo: 0, bar: 1, qux: 2 } 179 | [opts].map(defaults(defs)); // [ { foo: 0, bar: 1, qux: 2 } ] 180 | 181 | var opts = { 182 | foo: { 183 | one: 1, 184 | two: 2 185 | } 186 | }; 187 | var defs = { 188 | foo: { 189 | two: 20, 190 | three: 30 191 | } 192 | }; 193 | defaults(opts, defs); // { foo: { one: 1, two: 2, three: 30 } } 194 | ``` 195 | 196 | ## del 197 | 198 | Functional version of delete obj[key] which returns the same obj without the deleted key. 199 | Supports partial functionality (great with array functions, like map). 200 | 201 | ```js 202 | var del = require('101/del'); 203 | var obj = { 204 | foo: 1, 205 | bar: 2 206 | }; 207 | 208 | del(obj, 'foo'); // { bar: 2 } 209 | 210 | // use it with array.map 211 | [obj, obj, obj].map(del('foo')); // [{ bar: 2 }, {same}, {same}] 212 | 213 | // supports keypaths by default 214 | var obj = { 215 | foo: { 216 | moo: 1, 217 | boo: 2 218 | }, 219 | bar: 3 220 | }; 221 | 222 | del(obj, 'foo.moo'); // { foo: { boo: 2 }, bar:3 } 223 | 224 | // pass an array of keys to be deleted 225 | del(obj, ['foo.moo', 'bar']) // { foo: { boo: 2 } } 226 | ``` 227 | 228 | ## envIs 229 | 230 | Functional version of `str === process.env.NODE_ENV`. 231 | Or's multiple environments. 232 | 233 | ```js 234 | var envIs = require('101/env-is'); 235 | // process.env.NODE_ENV = development 236 | envIs('development'); // true 237 | envIs('production'); // false 238 | envIs('staging', 'production'); // false 239 | envIs('development', 'production'); // true 240 | ``` 241 | 242 | ## equals 243 | 244 | Functional implementation of Object.is with polyfill for browsers without implementations of Object.is 245 | Supports partial functionality (great with array functions). 246 | 247 | ```js 248 | var equals = require('101/equals'); 249 | 250 | equals(1, 1); // true 251 | [1,2,3].some(equals(1)); // true 252 | equals(1, '1'); // false 253 | ``` 254 | 255 | ## exists 256 | 257 | Simple exists function. 258 | 259 | ```js 260 | var exists = require('101/exists'); 261 | 262 | exists('foo'); // true 263 | exists(null); // false 264 | exists(undefined); // false 265 | ``` 266 | 267 | ## find 268 | 269 | Just like ES6's `array.find`. 270 | 271 | Finds the first value in the list that passes the given function (predicate) and returns it. 272 | If list is not provided find will return a partial-function which accepts a list as the first argument. 273 | 274 | ```js 275 | var find = require('101/find'); 276 | var hasProps = require('101/has-properties'); 277 | var arr = [{ a: 1, b: 1 }, { b: 1 }, { c: 1 }]; 278 | 279 | var item = find(arr, hasProps({ a:1 })); 280 | // returns { a: 1, b: 1 } 281 | // returns null if not found 282 | 283 | // partial-function 284 | var partial = find(hasProps({ a: 1 })); 285 | var item = partial(arr); 286 | // returns { a: 1, b: 1 } 287 | // returns null if not found 288 | ``` 289 | 290 | ## findIndex 291 | 292 | Just like ES6's `array.findIndex`. 293 | 294 | Finds the first value in the list that passes the given function (predicate) and returns it's index. 295 | If list is not provided findIndex will return a partial-function which accepts a list as the first argument. 296 | 297 | ```js 298 | var findIndex = require('101/find-index'); 299 | var arr = [1, 2, 3]; 300 | 301 | var index = findIndex(arr, function (val, i, arr) { 302 | return val === 2; 303 | }); 304 | // returns 1 305 | // returns -1 if not found 306 | ``` 307 | 308 | ## flip 309 | 310 | Returns a function with flipped arguments 311 | 312 | ```js 313 | var flip = require('101/flip'); 314 | var curry = require('101/curry'); 315 | var hasKeypaths = require('101/has-keypaths'); 316 | 317 | var hasFooBar = curry(flip(hasKeypaths))(['foo.bar']); 318 | 319 | hasFooBar({ foo: { bar : true } }); // true 320 | 321 | 322 | function prefix(pre, str) { 323 | return pre + str; 324 | } 325 | 326 | flip(prefix)('hello', '_'); // "_hello" 327 | ``` 328 | 329 | ## groupBy 330 | Hashes an array into groups based on the value of a provided common key. 331 | Works nicely with `pluck` and `reduce`. 332 | 333 | ```js 334 | var groupBy = require('101/group-by'); 335 | var arr = [ 336 | {id: 1, foo: 'bar'}, 337 | {id: 2, foo: 'qux'}, 338 | {id: 3, foo: 'qux'} 339 | ]; 340 | 341 | groupBy(arr, 'foo') 342 | /* 343 | { 344 | bar: [ 345 | {id: 1, foo: 'bar'} 346 | ], 347 | qux: [ 348 | {id: 2, foo: 'qux'}, 349 | {id: 3, foo: 'qux'} 350 | ] 351 | } 352 | */ 353 | // always provide initial value when using with reduce! 354 | arr.reduce(groupBy('foo'), {}) // assumes pluck if passed string 355 | arr.reduce(groupBy(pluck('foo')), {}) // also accepts function 356 | /* 357 | { 358 | bar: [ 359 | {id: 1, foo: 'bar'} 360 | ], 361 | qux: [ 362 | {id: 2, foo: 'qux'}, 363 | {id: 3, foo: 'qux'} 364 | ] 365 | } 366 | */ 367 | ``` 368 | 369 | ## hasKeypaths 370 | 371 | Determines whether the keypaths exist and have the specified values. 372 | Supports partial functionality (great with array functions, and 101/find). 373 | 374 | ```js 375 | var hasKeypaths = require('101/has-keypaths'); 376 | var obj = { 377 | foo: { 378 | bar: { 379 | qux: 1 380 | } 381 | } 382 | }; 383 | 384 | hasKeypaths(obj, ['foo.bar.qux']); // true 385 | hasKeypaths(obj, { 'foo.bar.qux': 1 }); // true 386 | hasKeypaths(obj, ['foo.qux']); // false 387 | hasKeypaths(obj, { 'foo.bar': 2 }); // false 388 | hasKeypaths(obj, { 'foo.bar': 1, 'nope': 1 }); // false 389 | 390 | // optional 'deep' arg, defaults to true 391 | var barObj = { bar: 1 }; 392 | hasKeypaths(obj, { 'foo.bar': barObj }); // true 393 | hasKeypaths(obj, { 'foo.bar': barObj }, true); // true 394 | hasKeypaths(obj, { 'foo.bar': barObj }, false); // false 395 | hasKeypaths(obj, { 'foo.bar': obj.foo }, false); // true 396 | hasKeypaths(obj, ['foo.bar'], false); // true, uses [hasOwnProperty vs in](http://stackoverflow.com/questions/13632999/if-key-in-object-or-ifobject-hasownpropertykey) 397 | 398 | // use it with find, findIndex, or filter! 399 | var arr = [obj, { b: 1 }, { c: 1 }]; 400 | find(arr, hasKeypaths({ 'foo.bar.qux':1 })); // { foo: { bar: { qux: 1 } } } 401 | find(arr, hasKeypaths(['foo.bar.qux'])); // { foo: { bar: { qux: 1 } } } 402 | 403 | // use it to verify options object has required properties 404 | var opts = { 405 | host: 'localhost', 406 | port: '3333', 407 | user: { 408 | id: 5 409 | } 410 | }; 411 | hasKeypaths(opts, ['host', 'port', 'user.id']); // true 412 | 413 | ``` 414 | 415 | ## hasProperties 416 | 417 | Determines whether the keys exist and, if specified, has the values. 418 | Supports partial functionality (great with array functions, and 101/find). 419 | NOTE: I am considering deprecating this method, bc it is so similar to has-keypaths. 420 | 421 | ```js 422 | var hasProps = require('101/has-properties'); 423 | var obj = { 424 | qux: 1 425 | }; 426 | obj['foo.bar'] = 1 427 | 428 | hasProps(obj, ['foo', 'qux']); // true 429 | hasProps(obj, { qux: 1 }) // true 430 | 431 | // optional 'deep' arg, defaults to true 432 | var barObj = { bar: 1 }; 433 | hasProps(obj, { 'foo.bar': barObj }); // true 434 | hasProps(obj, { 'foo.bar': barObj }, true); // true 435 | hasProps(obj, { 'foo.bar': barObj }, false); // false 436 | hasProps(obj, ['foo.bar'], false); // true, uses [hasOwnProperty vs in](http://stackoverflow.com/questions/13632999/if-key-in-object-or-ifobject-hasownpropertykey) 437 | // use it with find, findIndex, or filter! 438 | var arr = [{ a: 1, b: 1 }, { b: 1 }, { c: 1 }]; 439 | find(arr, hasProps({ a:1 })); // { a: 1, b: 1 } 440 | find(arr, hasProps(['a'])); // { a: 1, b: 1 } 441 | ``` 442 | 443 | ## includes 444 | 445 | Polyfill of ES7 proposed Array.prototype.includes. Will default to Array.prototype.includes if 446 | present. 447 | 448 | ```js 449 | var includes = require('101/includes'); 450 | var haystack = ['a', 'b', 'c', 'd', 'e']; 451 | includes(haystack, 'c'); // true 452 | 453 | // optional 3rd argument, searchFrom. Begin searching the target array from a specified index. 454 | includes(haystack, 'c', 3); // false 455 | includes(haystack, 'c', 0); // true 456 | 457 | // partial argument functionality 458 | var i = includes(haystack); 459 | i('c') // true 460 | i('g') // false 461 | 462 | // example composition usage: 463 | var not = require('101/not'); 464 | var notIn = not(includes); 465 | [1, 2, 3, 4, 5].filter(notIn([1, 2, 3])); // [4, 5] 466 | ``` 467 | 468 | ## indexBy 469 | Hashes an array of objects based on the value of a provided common key. 470 | Works nicely with `pluck` and `reduce`. 471 | 472 | ```js 473 | var arr = [ 474 | {foo: 'bar'}, 475 | {foo: 'qux'} 476 | ]; 477 | 478 | arr.reduce(indexBy('foo'), {}) // assumes pluck if passed string 479 | arr.reduce(indexBy(pluck('foo')), {}) // also accepts function 480 | // {bar: {foo: 'bar'}, qux: {foo: 'qux'}} 481 | // always provide initial value when using with reduce! 482 | arr.reduce(indexBy(pluck('foo')), {}) // {bar: {foo: 'bar'}, qux: {foo: 'qux'}} 483 | ``` 484 | 485 | ## instanceOf 486 | 487 | Functional version of JavaScript's instanceof. 488 | Supports partial functionality (great with array functions). 489 | 490 | ```js 491 | var instanceOf = require('101/instance-of'); 492 | 493 | ['foo', 'bar', 1].map(instanceOf('string')); // [true, true, false] 494 | ``` 495 | 496 | ## isBoolean 497 | 498 | Functional version of `typeof val === 'boolean'`. 499 | Supports partial functionality (great with array functions). 500 | 501 | ```js 502 | var isBoolean = require('101/is-boolean'); 503 | 504 | [true, false, 1].map(isBoolean); // [true, true, false] 505 | ``` 506 | 507 | ## isEmpty 508 | 509 | Functional version of val empty object, array or object 510 | 511 | ```js 512 | var isEmpty = require('101/is-empty'); 513 | 514 | isEmpty([]); // true 515 | isEmpty({}); // true 516 | isEmpty(""); // true 517 | isEmpty(" "); // false 518 | ``` 519 | 520 | ## isFunction 521 | 522 | Functional version of `typeof val === 'function'` 523 | 524 | ```js 525 | var isFunction = require('101/is-function'); 526 | 527 | [parseInt, function () {}, 'foo'].map(isFunction); // [true, true, false] 528 | ``` 529 | 530 | ## isInteger 531 | 532 | Check if a value is an instance of an integer. 533 | 534 | ```js 535 | var isInteger = require('101/is-Integer'); 536 | 537 | isInteger(101); // true 538 | isInteger(101.01); // false 539 | ``` 540 | 541 | ## isNumber 542 | 543 | Functional version of val typeof 'number'. 544 | 545 | ```js 546 | var isNumber = require('101/is-number'); 547 | 548 | ['foo', NaN, 1].map(isNumber); // [false, false, true] 549 | ``` 550 | 551 | ## isObject 552 | 553 | Functional *strict* version of val typeof 'object' (and not array or regexp) 554 | 555 | ```js 556 | var isObject = require('101/is-object'); 557 | 558 | [{}, { foo: 1 }, 100].map(isObject); // [true, true, false] 559 | ``` 560 | 561 | ## isRegExp 562 | 563 | Check if a value is an instance of RegExp 564 | 565 | ```js 566 | var isRegExp = require('101/is-regexp'); 567 | 568 | [new RegExp('.*'), /.*/, {}, 1].map(isRegExp); // [true, true, false, false] 569 | ``` 570 | 571 | ## isString 572 | 573 | Functional version of val typeof 'string' 574 | 575 | ```js 576 | var isString = require('101/is-string'); 577 | 578 | ['foo', 'bar', 1].map(isString); // [true, true, false] 579 | ``` 580 | 581 | ## keysIn 582 | 583 | Return an array containing all the keys of an object. 584 | It differs from the native `Object.keys` by including also the `prototype` keys. 585 | 586 | ```js 587 | var keysIn = require('101/keys-in'); 588 | var User = function() { 589 | this.msg = 'Hello World'; 590 | } 591 | User.prototype.isLoggedIn = function() { /* example function */ } 592 | 593 | var user = new User(); 594 | keysIn(user); // ['msg', 'isLoggedIn'] 595 | ``` 596 | 597 | ## last 598 | 599 | Returns the last value of a list 600 | 601 | ```js 602 | var last = require('101/last'); 603 | 604 | last([1, 2, 3]); // 3 605 | last('hello'); // 'o' 606 | ``` 607 | 608 | ## lens 609 | 610 | Create a lens to access a data structure. When passed a property key as a string, it returns a function `fn(obj)` that acts as a getter for that. It also exposes `.set(value, obj)` and `.mod(fn, obj)`. 611 | 612 | ```js 613 | var fooLens = lens('foo'); 614 | var toUpper = function(str) { return str.toUpperCase(); }; 615 | var obj = { 616 | foo: 'foo', 617 | bar: 'bar' 618 | }; 619 | 620 | fooLens(obj); // => 'foo' 621 | fooLens.set('moo', obj); // => { foo: 'moo', bar: 'bar' } 622 | fooLens.mod(toUpper, obj); // => { foo: 'MOO', bar: 'bar' } 623 | ``` 624 | 625 | You may also provide getter and setter functions. 626 | 627 | ```js 628 | var arr = ['foo', 'bar']; 629 | var first = lens( 630 | function(arr) { return arr[0]; }, 631 | function(val, arr) { var clone = arr.slice(); clone[0] = val; return clone; } 632 | ); 633 | 634 | first(arr); // => 'foo' 635 | first.set('moo')(arr); // => ['moo', 'bar'] 636 | first.mod(toUpper)(arr); // => ['FOO', 'bar'] 637 | ``` 638 | 639 | ## noop 640 | 641 | No-op function 642 | 643 | ```js 644 | require('101/noop'); // function () {} 645 | ``` 646 | 647 | ## not 648 | 649 | Functional version of `!`. 650 | 651 | ```js 652 | var not = require('101/not'); 653 | 654 | not(isString)('hey'); // false 655 | not(isString)(100); // true 656 | ``` 657 | 658 | ## omit 659 | 660 | Immutable version of `delete obj.key`. Returns a new object without the specified keys. 661 | Supports partial functionality (great with array functions, like map). 662 | 663 | ```js 664 | var omit = require('101/omit'); 665 | var obj = { 666 | foo: 1, 667 | bar: 2 668 | }; 669 | 670 | omit(obj, 'foo'); // { bar: 1 } 671 | omit(obj, ['foo']); // { bar: 1 } 672 | omit(obj, ['foo', 'bar']); // { } 673 | 674 | // use it with array.map 675 | [obj, obj, obj].map(omit('foo')); // [{ bar: 1 }, { bar: 1 }, { bar: 1 }]; 676 | ``` 677 | 678 | ## or 679 | 680 | Functional version of `||`. 681 | Works great with `array.reduce`. 682 | 683 | ```js 684 | var or = require('101/or'); 685 | 686 | or(true, true); // true 687 | or(true, false); // true 688 | or(false, false); // false 689 | or("foo", false); // "foo" 690 | ``` 691 | 692 | ## passAll 693 | 694 | Muxes arguments across many functions and `&&`'s the results. 695 | Supports partial functionality (great with array functions, like map). 696 | 697 | ```js 698 | var passAll = require('101/pass-all'); 699 | 700 | ['', 'foo', 'bar', 100].map(passAll(isString, isTruthy)); // [false, true, true, false] 701 | ``` 702 | 703 | ## passAny 704 | 705 | Muxes arguments across many functions and `||`'s the results. 706 | Supports partial functionality (great with array functions, like map). 707 | 708 | ```js 709 | var passAny = require('101/pass-any'); 710 | 711 | ['', 'foo', 'bar', 100].map(passAny(isString, isNumber)); // [true, true, true, true] 712 | ``` 713 | 714 | ## pick 715 | 716 | Returns a new object with the specified keys (with key values from obj). 717 | Supports regular expressions and partial functionality (great with array functions, like map). 718 | 719 | ```js 720 | var pick = require('101/pick'); 721 | var obj = { 722 | foo: 1, 723 | bar: 2, 724 | qwk: { 725 | wrk: 1 726 | }, 727 | 'qwk.wrk': 2 728 | }; 729 | 730 | pick(obj, 'foo'); // { foo: 1 } 731 | pick(obj, RegExp('oo$')); // { foo: 1 } 732 | pick(obj, ['foo']); // { foo: 1 } 733 | pick(obj, ['foo', 'bar']); // { foo: 1, bar: 2 } 734 | 735 | // use it with array.map 736 | [obj, obj, obj].map(pick('foo')); // [{ foo: 1 }, { foo: 1 }, { foo: 1 }]; 737 | 738 | // supports keypaths 739 | pick(obj, 'qwk.wrk'); // { qwk: { wrk: 1 } } 740 | pick(obj, '["qwk.wrk"]'); // { 'qwk.wrk': 2 } } 741 | ``` 742 | 743 | ## pluck 744 | 745 | Functional version of obj[key], returns the value of the key from obj. 746 | Supports partial functionality (great with array functions, like map). 747 | 748 | ```js 749 | var pluck = require('101/pluck'); 750 | var obj = { 751 | foo: 1, 752 | bar: 2 753 | }; 754 | 755 | pluck(obj, 'foo'); // 1 756 | 757 | // use it with array.map 758 | [obj, obj, obj].map(pluck('foo')); // [1, 1, 1] 759 | 760 | // supports keypaths by default 761 | var obj = { 762 | foo: { 763 | bar: 1 764 | }, 765 | 'foo.bar': 2 766 | }; 767 | 768 | pluck(obj, 'foo.bar'); // 1, supports keypaths by default 769 | pluck(obj, 'foo.bar', false); // 2, pass false to not use keypaths 770 | ``` 771 | 772 | ## put 773 | 774 | Immutable version of `obj[key] = val`. Returns a clone of the obj with the value put at the key. 775 | Supports partial functionality (great with array functions, like map). 776 | 777 | ```js 778 | var put = require('101/put'); 779 | var obj = { 780 | foo: 1, 781 | bar: 2 782 | }; 783 | 784 | put(obj, 'baz', 3); // { foo: 1, bar:2, baz: 3 } 785 | obj; // { foo: 1, bar: 2 } (not modified) 786 | 787 | // use it with array.map 788 | [obj, obj, obj].map(put('foo', 100)); // [{ foo: 100, bar: 2 }, {copy}, {copy}] 789 | obj; // { foo: 1, bar: 2 } (not modified) 790 | 791 | // supports keypaths by default 792 | var obj = { 793 | bar: 2 794 | }; 795 | 796 | put(obj, 'foo.qux', 100); // { foo: { qux: 100 }, bar: 2 } 797 | put(obj, { 798 | 'foo.qux': 100 799 | 'yolo': 1 800 | }); // { foo: { qux: 100 }, bar: 2, yolo: 1 } 801 | obj; // { foo: 1, bar: 2 } (not modified) 802 | ``` 803 | 804 | ## set 805 | 806 | Functional version of obj[key] = val, returns the same obj with the key and value set. 807 | Supports partial functionality (great with array functions, like map). 808 | 809 | ```js 810 | var set = require('101/set'); 811 | var obj = { 812 | foo: 1, 813 | bar: 2 814 | }; 815 | 816 | set(obj, 'foo'); // 1 817 | 818 | // use it with array.map 819 | [obj, obj, obj].map(set('foo', 100)); // [{ foo: 100, bar: 2 }, {same}, {same}] 820 | 821 | // supports keypaths by default 822 | var obj = { 823 | bar: 2 824 | }; 825 | 826 | set(obj, 'foo.qux', 100); // { foo: { qux: 100 }, bar: 2 } 827 | set(obj, { 828 | 'foo.qux': 100 829 | 'yolo': 1 830 | }); // { foo: { qux: 100 }, bar: 2, yolo: 1 } 831 | ``` 832 | 833 | ## values 834 | 835 | Returns Array containing the values of the properties of an object 836 | 837 | ```js 838 | var values = require('101/values'); 839 | var obj { 840 | foo: 'apple', 841 | bar: 'orange' 842 | }; 843 | 844 | var objValues = values(obj); 845 | objValues // ['apple', 'orange'] 846 | ``` 847 | 848 | ## xor 849 | 850 | Exclusive or 851 | Works great with `array.reduce`. 852 | 853 | ```js 854 | var xor = require('101/xor'); 855 | 856 | xor(true, true); // false 857 | xor(true, false); // true 858 | xor(false, true); // true 859 | xor(false, false); // false 860 | ``` 861 | 862 | ## License 863 | 864 | MIT 865 | -------------------------------------------------------------------------------- /and.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/and 3 | */ 4 | 5 | /** 6 | * Functional version of && 7 | * @function module:101/and 8 | * @param {*} a - any value 9 | * @param {*} b - any value 10 | * @return {*} a && b 11 | */ 12 | module.exports = and; 13 | 14 | function and (a, b) { 15 | return a && b; 16 | } 17 | -------------------------------------------------------------------------------- /apply.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/apply 3 | */ 4 | 5 | /** 6 | * Functional version of function.apply 7 | * @function module:101/apply 8 | * @param {*} thisArg - Context applied to fn 9 | * @param {array} args - Arguments applied to fn 10 | * @return {function} function which accepts a function, fn, and applies thisArg, and args to it. Returns fn.apply(thisArg, args). 11 | */ 12 | module.exports = apply; 13 | 14 | function apply (thisArg, args) { 15 | return function (fn) { 16 | return fn.apply(thisArg, args); 17 | }; 18 | } -------------------------------------------------------------------------------- /assign.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/assign 3 | */ 4 | 5 | /** 6 | * Copies enumerable and own properties from a source object(s) to a target object, aka extend. 7 | * https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign 8 | * I added functionality to support assign as a partial function 9 | * @function module:101/assign 10 | * @param {object} [target] - object which source objects are extending (being assigned to) 11 | * @param {object} sources... - objects whose properties are being assigned to the source object 12 | * @return {object} source with extended properties 13 | */ 14 | module.exports = assign; 15 | 16 | function assign (target, firstSource) { 17 | if (arguments.length === 1) { 18 | firstSource = arguments[0]; 19 | return function (target) { 20 | return assign(target, firstSource); 21 | }; 22 | } 23 | if (target === undefined || target === null) 24 | throw new TypeError('Cannot convert first argument to object'); 25 | var to = Object(target); 26 | for (var i = 1; i < arguments.length; i++) { 27 | var nextSource = arguments[i]; 28 | if (nextSource === undefined || nextSource === null) continue; 29 | var keysArray = Object.keys(Object(nextSource)); 30 | for (var nextIndex = 0, len = keysArray.length; nextIndex < len; nextIndex++) { 31 | var nextKey = keysArray[nextIndex]; 32 | Object.getOwnPropertyDescriptor(nextSource, nextKey); 33 | // I changed the following line to get 100% test coverage. 34 | // if (desc !== undefined && desc.enumerable) to[nextKey] = nextSource[nextKey]; 35 | // I was unable to find a scenario where desc was undefined or that desc.enumerable was false: 36 | // 1) Object.defineProperty does not accept undefined as a desc 37 | // 2) Object.keys does not return non-enumerable keys. 38 | // Let me know if this is a cross browser thing. 39 | to[nextKey] = nextSource[nextKey]; 40 | } 41 | } 42 | return to; 43 | } -------------------------------------------------------------------------------- /bind-all.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/bind-all 3 | */ 4 | 5 | var isFunction = require('./is-function'); 6 | var keysIn = require('./keys-in'); 7 | /** 8 | * Bind a passed object methods. 9 | * If methods name to bing are not specified, all the object methods are binded 10 | * @function module:101/bind-all 11 | * 12 | * @param {object} object - object to bind 13 | * @param {array|string} [methods] - array or space-separated string containing the names of the methods to bind 14 | * @return {object} the binded object 15 | */ 16 | module.exports = bindAll; 17 | 18 | function bindAll (object, methods) { 19 | if (methods && !Array.isArray(methods)) { 20 | throw new TypeError('The second argument must be an array'); 21 | } 22 | 23 | var keys = methods || keysIn(object); 24 | 25 | // Bind all the specified methods 26 | keys.forEach(function(key) { 27 | var target = object[key]; 28 | // skip for non-functions and when the target does not exist 29 | if (!target || !isFunction(target)) { return; } 30 | 31 | object[key] = target.bind(object); 32 | }); 33 | 34 | return object; 35 | } 36 | -------------------------------------------------------------------------------- /clone.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/clone 3 | */ 4 | 5 | /** Just exporting https://www.npmjs.org/package/clone */ 6 | // Only bc 101 uses it internally and it is a nice util 7 | module.exports = require('clone'); 8 | -------------------------------------------------------------------------------- /compose.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/compose 3 | */ 4 | 5 | /** 6 | * [compose description] 7 | * @function module:101/compose 8 | * @param {function} f 9 | * @param {function} g 10 | * @return {function} 11 | */ 12 | module.exports = compose; 13 | 14 | function compose(f,g) { 15 | return function composed(/* args */) { 16 | var args = Array.prototype.slice.call(arguments); 17 | 18 | return f(g.apply(null, args)); 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /converge.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/converge 3 | */ 4 | 5 | /** 6 | * Converges an array of functions into one 7 | * @function module:101/converge 8 | * @param {function} f 9 | * @param {Array} array of functions 10 | * @return {function} 11 | */ 12 | module.exports = converge; 13 | 14 | function converge(f, funcs) { 15 | 16 | return function converged(/* args */) { 17 | var args = Array.prototype.slice.call(arguments); 18 | 19 | return f.apply(null, funcs.map(function(g) { 20 | return g.apply(null, args); 21 | })); 22 | }; 23 | } 24 | -------------------------------------------------------------------------------- /curry.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/curry 3 | */ 4 | 5 | var slice = Array.prototype.slice; 6 | 7 | /** 8 | * Returns a curried function 9 | * @function module:101/curry 10 | * @param {function} f - function to be curried 11 | * @param {integer} [n] - how many arguments to curry 12 | * @return {function} 13 | */ 14 | module.exports = curry; 15 | 16 | function curry(f, n) { 17 | var length = n || f.length; 18 | return _curry(f, length, []); 19 | } 20 | 21 | function _curry(f, n, args) { 22 | 23 | return function(/* args */) { 24 | var curryArgs = args.concat(slice.call(arguments)); 25 | 26 | if (curryArgs.length >= n) { 27 | return f.apply(null, curryArgs.slice(0, n)); 28 | } else { 29 | return _curry(f, n, curryArgs); 30 | } 31 | }; 32 | } 33 | -------------------------------------------------------------------------------- /defaults.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/defaults 3 | */ 4 | 5 | var isObject = require('./is-object'); 6 | var isBoolean = require('./is-boolean'); 7 | var exists = require('./exists'); 8 | 9 | /** 10 | * Mixes in properties from source into target when 11 | * the property is not a property of `target` 12 | * @param {Object} [target] Mix into 13 | * @param {Object} source The defaults description 14 | * @return {Object} THe resulting target 15 | */ 16 | module.exports = defaults; 17 | 18 | function defaults (target, source, deep) { 19 | if (arguments.length === 1) { 20 | source = target; 21 | return function (target) { 22 | return defaults(target, source); 23 | }; 24 | } else if (isBoolean(source)) { 25 | deep = source; 26 | source = target; 27 | return function (target) { 28 | return defaults(target, source, deep); 29 | }; 30 | } 31 | target = target || {}; 32 | deep = deep || false; 33 | if (!source) { 34 | return target; 35 | } 36 | return reduceObject(target, source, deep); 37 | } 38 | 39 | function reduceObject (target, source, deep) { 40 | return Object.keys(source).reduce(function (target, key) { 41 | if (isObject(target[key]) && isObject(source[key]) && deep) { 42 | reduceObject(target[key], source[key]); 43 | return target; 44 | } 45 | target[key] = exists(target[key]) ? target[key] : source[key]; 46 | return target; 47 | }, target); 48 | } 49 | -------------------------------------------------------------------------------- /del.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/del 3 | */ 4 | 5 | var keypather = require('keypather')(); 6 | var passAny = require('./pass-any'); 7 | var isString = require('./is-string'); 8 | var isNumber = require('./is-number'); 9 | var isObject = require('./is-object'); 10 | 11 | /** 12 | * Functional version of delete obj[key]. 13 | * When only a key is specified del returns a partial-function which accepts obj. 14 | * @function module:101/del 15 | * @param {*} [obj] - object on which the values will be del 16 | * @param {string} key - key of the value being del on obj 17 | * @return {*|function} The same obj without the deleted key or Partial-function del (which accepts obj) and returns the same obj without the deleted key. 18 | */ 19 | module.exports = del; 20 | 21 | function del (obj, key) { 22 | if (arguments.length === 1) { 23 | // (key) 24 | key = obj; 25 | return function (obj) { 26 | return _del(obj, key); 27 | }; 28 | } 29 | else { 30 | return _del(obj, key); 31 | } 32 | } 33 | 34 | function _del (obj, key) { 35 | var keys; 36 | var numberOrString = passAny(isString, isNumber); 37 | if (isObject(obj) && numberOrString(key)) { 38 | // (obj, key) 39 | keypather.del(obj, key); 40 | return obj; 41 | } 42 | else if (isObject(obj) && Array.isArray(key)) { 43 | // (obj, keys) 44 | keys = key; 45 | 46 | for (var i = 0; i < keys.length; i++) { 47 | keypather.del(obj, keys[i]); 48 | } 49 | return obj; 50 | } 51 | else { 52 | throw new TypeError('Invalid arguments: expected str, val or val, obj'); 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /env-is.js: -------------------------------------------------------------------------------- 1 | var equals = require('./equals'); 2 | 3 | /** 4 | * @module 101/env-is 5 | */ 6 | 7 | /** 8 | * Functional version of str === process.env.NODE_ENV. Or's multiple environments. 9 | * @function module:101/env-is 10 | * @param {*} array - Array of environments to check 11 | * @return {boolean} Any of the supplied arguments exists in process.env.NODE_ENV 12 | */ 13 | module.exports = envIs; 14 | 15 | function envIs () { 16 | var args = Array.prototype.slice.call(arguments); 17 | return args.some(equals(process.env.NODE_ENV)); 18 | } -------------------------------------------------------------------------------- /equals.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/equals 3 | */ 4 | 5 | /** 6 | * Functional implementation of Object.is with polyfill for browsers without implementations of Object.is 7 | * @function module:101/equals 8 | * @param {*} a - any value 9 | * @param {*} b - any value 10 | * @return {boolean} Object.is(a, b) 11 | */ 12 | module.exports = function (a, b) { 13 | if (arguments.length === 1) { 14 | return equals.bind(null, a); 15 | } 16 | else { 17 | return equals(a, b); 18 | } 19 | }; 20 | 21 | function equals (v1, v2) { 22 | if (Object.is) { 23 | return Object.is(v1, v2); 24 | } 25 | else { 26 | // ES6 Object.is polyfill 27 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is 28 | if (v1 === 0 && v2 === 0) { 29 | return 1 / v1 === 1 / v2; 30 | } 31 | if (v1 !== v1) { 32 | return v2 !== v2; 33 | } 34 | return v1 === v2; 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /exists.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module {function} 101/exists 3 | * @type {function} 4 | */ 5 | 6 | /** 7 | * Returns false for null and undefined, true for everything else. 8 | * @function module:101/exists 9 | * @param val {*} - value to be existance checked 10 | * @return {boolean} whether the value exists or not 11 | */ 12 | module.exports = exists; 13 | 14 | function exists (val) { 15 | return val !== undefined && val !== null; 16 | } -------------------------------------------------------------------------------- /find-index.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/find-index 3 | */ 4 | 5 | var isFunction = require('./is-function'); 6 | var exists = require('./exists'); 7 | 8 | /** 9 | * Finds the first value in the list that passes the given function (predicate) and returns it's index. 10 | * If list is not provided findIndex will return a partial-function which accepts a list as the first argument. 11 | * @function module:101/find-index 12 | * 13 | * @param {array|string} list - list to be searched 14 | * @param {function} predicate - executed on each item in the list and returns true when the item is found 15 | * @return {number} - index of first item which passes predicate 16 | * 17 | * @param {function} predicate - executed on each item in the list and returns true when the item is found 18 | * @return {function} - partial function (accepts list and returns index of first item that passes predicate) 19 | */ 20 | module.exports = function (list, predicate) { 21 | if (exists(list && list.length) && !isFunction(list)) { 22 | return findIndex(list, predicate); 23 | } 24 | else if (isFunction(list)) { 25 | predicate = list; 26 | return function (list) { 27 | return findIndex(list, predicate); 28 | }; 29 | } 30 | else { 31 | throw new TypeError('first argument must be a list (have length) or function'); 32 | } 33 | }; 34 | 35 | function findIndex (list, predicate) { 36 | if (!exists(list && list.length)) { 37 | throw new TypeError('list must have length property'); 38 | } 39 | if (!isFunction(predicate)) { 40 | throw new TypeError('predicate must be a function'); 41 | } 42 | 43 | var index = -1; 44 | list = Array.prototype.slice.call(list); // cast as array to use some. 45 | list.some(function (val, i) { 46 | if (predicate(val, i, list)) { 47 | index = i; 48 | return true; 49 | } 50 | }); 51 | 52 | return index; 53 | } 54 | -------------------------------------------------------------------------------- /find.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/find 3 | */ 4 | 5 | var isFunction = require('./is-function'); 6 | var exists = require('./exists'); 7 | var findIndex = require('./find-index'); 8 | 9 | /** 10 | * Finds the first value in the list that passes the given function (predicate) and returns it's index. 11 | * If list is not provided find will return a partial-function which accepts a list as the first argument. 12 | * @function module:101/find 13 | * 14 | * @param {array|string} list - list to be searched 15 | * @param {function} predicate - executed on each item in the list and returns true when the item is found 16 | * @return {*} - first element which passes predicate 17 | * 18 | * @param {function} predicate - executed on each item in the list and returns true when the item is found 19 | * @return {function} - partial function (accepts list and returns first element that passes predicate) 20 | */ 21 | module.exports = find; 22 | 23 | function find (list, predicate) { 24 | if (exists(list && list.length) && !isFunction(list)) { 25 | var index = findIndex(list, predicate); 26 | return ~index ? list[index] : null; 27 | } 28 | else if (isFunction(list)) { 29 | predicate = list; 30 | return function (list) { 31 | if (!exists(list && list.length)) { 32 | throw new TypeError('list must have length property'); 33 | } 34 | var index = findIndex(list, predicate); 35 | return ~index ? list[index] : null; 36 | }; 37 | } 38 | else { 39 | throw new TypeError('first argument must be a list (have length) or function'); 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /flip.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/flip 3 | */ 4 | 5 | /** 6 | * Returns a function with flipped arguments 7 | * @function module:101/flip 8 | * @param {function} f - function to be flipped 9 | * @return {function} 10 | */ 11 | module.exports = flip; 12 | 13 | function flip(f) { 14 | return function() { 15 | var args = Array.prototype.slice.call(arguments); 16 | return f.apply(this, args.reverse()); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /group-by.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/index-by 3 | */ 4 | 5 | var isString = require('./is-string'); 6 | var isFunction = require('./is-function'); 7 | var pluck = require('./pluck'); 8 | 9 | /** 10 | * Hashes an array into groups based on the value of a provided common key. 11 | * @function module:101/index-by 12 | * @param {array|function|string} arr|indexer - array of objects to be indexed 13 | * @param {string|function} indexer - the common keypath or function which accepts an object and returns an index key 14 | * @return {obj|function} indexed|indexByPartial An object whose keys are the values of their common key and values are the original values. 15 | * Or a partial function which applies the passed indexer to each object. 16 | */ 17 | module.exports = function(arrOrIndexer, indexer) { 18 | var arr; 19 | if (Array.isArray(arrOrIndexer)) { 20 | arr = arrOrIndexer; 21 | return arr.reduce(indexBy(indexer), {}); 22 | } 23 | else { 24 | indexer = arrOrIndexer; 25 | if (!isString(indexer) && !isFunction(indexer)) { 26 | throw new TypeError('indexer must be a string or function'); 27 | } 28 | return indexBy(indexer); 29 | } 30 | } 31 | 32 | function indexBy (indexer) { 33 | if (isString(indexer)) { 34 | indexer = pluck(indexer); 35 | } 36 | return function(prev, cur, index, arr) { 37 | var key = indexer(cur) 38 | prev[key] = prev[key] || [] 39 | prev[key].push(cur); 40 | return prev; 41 | }; 42 | } -------------------------------------------------------------------------------- /has-keypaths.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/has-keypaths 3 | */ 4 | 5 | var eql = require('deep-eql'); 6 | var keypather = require('keypather')(); 7 | var isObject = require('./is-object'); 8 | var isBoolean = require('./is-boolean'); 9 | var isArray = Array.isArray; 10 | 11 | /** 12 | * Determines whether the keypaths exist and have the specified values. 13 | * If obj is not provided findIndex will return a partial-function which accepts a obj as the first argument. 14 | * @function module:101/has-keypaths 15 | * @param {object} [obj] - the object whose properties being checked 16 | * @param {object|array} keypaths - keypaths and values (object) or keypath strings expected to exist on the object (array) 17 | * @param {boolean} [deep] - deep equals when values are specified (objects are recursed), 18 | * deep keypath existance (prototype) when only keys are specified 19 | * @return {boolean|function} Has keypaths or Partial-function function hasKeypaths (which accepts obj) 20 | */ 21 | module.exports = function (obj, keypaths, deep) { 22 | if (arguments.length === 1) { 23 | keypaths = obj; 24 | return function (obj) { 25 | return hasKeypaths(obj, keypaths, deep); 26 | }; 27 | } 28 | else { 29 | return hasKeypaths(obj, keypaths, deep); 30 | } 31 | }; 32 | 33 | function hasKeypaths (obj, keypaths, deep) { 34 | var has = false; 35 | deep = !isBoolean(deep) ? true : deep; 36 | if (isObject(keypaths)) { 37 | has = Object.keys(keypaths).every(function (keypath) { 38 | return deep ? 39 | eql(keypather.get(obj, keypath), keypaths[keypath]) : 40 | keypather.get(obj, keypath) === keypaths[keypath]; 41 | }); 42 | } 43 | else if (isArray(keypaths)) { 44 | has = keypaths.every(function (keypath) { 45 | return deep ? 46 | keypather.in(obj, keypath) : 47 | keypather.has(obj, keypath); 48 | }); 49 | } 50 | 51 | return has; 52 | } -------------------------------------------------------------------------------- /has-properties.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/has-properties 3 | */ 4 | 5 | var eql = require('deep-eql'); 6 | var isObject = require('./is-object'); 7 | var isBoolean = require('./is-boolean'); 8 | var isArray = Array.isArray; 9 | 10 | /** 11 | * Determines whether the keys exist and, if specified, has the values. 12 | * If obj is not provided findIndex will return a partial function which accepts a obj as the first argument. 13 | * @function module:101/has-properties 14 | * @param {object} [obj] - the object whose properties being checked 15 | * @param {object|array} properties - keys and values (object) or keys expected to exist on the object (array) 16 | * @param {boolean} [deep] - deep equals when values are specified (objects are recursed), 17 | * deep key existance (prototype) when only keys are specified 18 | * @return {boolean|function} Has keypaths or Partial-function hasProperties (which accepts obj) 19 | */ 20 | module.exports = function (obj, props, deep) { // deep defaults to true 21 | if (isBoolean(props)) { 22 | deep = props; 23 | props = null; 24 | } 25 | if (arguments.length === 1 || arguments.length === 2 && !props) { 26 | props = obj; 27 | return function (obj) { 28 | return hasProperties(obj, props, deep); 29 | }; 30 | } 31 | else { 32 | return hasProperties(obj, props, deep); 33 | } 34 | }; 35 | 36 | function hasProperties (obj, props, deep) { 37 | var has = false; 38 | deep = !isBoolean(deep) ? true : deep; 39 | if (isObject(props)) { 40 | has = Object.keys(props).every(function (key) { 41 | return deep ? 42 | eql(obj[key], props[key]) : 43 | obj[key] === props[key]; 44 | }); 45 | } 46 | else if (isArray(props)) { 47 | has = props.every(function (key) { 48 | return deep ? 49 | (key in obj) : 50 | obj.hasOwnProperty(key); 51 | }); 52 | } 53 | 54 | return has; 55 | } -------------------------------------------------------------------------------- /includes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Assert if a given array contains a value 3 | * @module 101/includes 4 | */ 5 | 'use strict'; 6 | 7 | var isNumber = require('./is-number'); 8 | 9 | /** 10 | * @param {Array} array 11 | * @param {*} searchElement 12 | * @param {Number} fromIndex 13 | * @return Boolean 14 | */ 15 | module.exports = function (array, searchElement, fromIndex) { 16 | if (arguments.length === 1) { 17 | return includes.bind(null, array); 18 | } else { 19 | return includes(array, searchElement, fromIndex); 20 | } 21 | }; 22 | 23 | function includes (array, searchElement, fromIndex) { 24 | if (!isNumber(fromIndex)) { 25 | fromIndex = 0; 26 | } 27 | if (Array.prototype.includes) { 28 | return Array.prototype.includes.call(array, searchElement, fromIndex); 29 | } else { 30 | // ES7 Array.prototype.includes polyfill (modified) 31 | // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/includes#Browser_compatibility 32 | var O = Object(array); 33 | var len = parseInt(O.length) || 0; 34 | if (len === 0) { 35 | return false; 36 | } 37 | var n = fromIndex; 38 | var k; 39 | if (n >= 0) { 40 | k = n; 41 | } else { 42 | k = len + n; 43 | if (k < 0) {k = 0;} 44 | } 45 | var currentElement; 46 | while (k < len) { 47 | currentElement = O[k]; 48 | if (searchElement === currentElement || 49 | (searchElement !== searchElement && currentElement !== currentElement)) { 50 | return true; 51 | } 52 | k++; 53 | } 54 | return false; 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /index-by.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/index-by 3 | */ 4 | 5 | var isString = require('./is-string'); 6 | var isFunction = require('./is-function'); 7 | var pluck = require('./pluck'); 8 | 9 | /** 10 | * Hashes an array based on the value of a provided common key. 11 | * @function module:101/index-by 12 | * @param {array|function|string} arr|indexer - array of objects to be indexed 13 | * @param {string|function} indexer - the common keypath or function which accepts an object and returns an index key 14 | * @return {obj|function} indexed|indexByPartial An object whose keys are the values of their common key and values are the original values. 15 | * Or a partial function which applies the passed indexer to each object. 16 | */ 17 | module.exports = function(arrOrIndexer, indexer) { 18 | var arr; 19 | if (Array.isArray(arrOrIndexer)) { 20 | arr = arrOrIndexer; 21 | return arr.reduce(indexBy(indexer), {}); 22 | } 23 | else { 24 | indexer = arrOrIndexer; 25 | if (!isString(indexer) && !isFunction(indexer)) { 26 | throw new TypeError('indexer must be a string or function'); 27 | } 28 | return indexBy(indexer); 29 | } 30 | } 31 | 32 | function indexBy (indexer) { 33 | if (isString(indexer)) { 34 | indexer = pluck(indexer); 35 | } 36 | return function(prev, cur, index, arr) { 37 | prev[indexer(cur)] = cur; 38 | return prev; 39 | }; 40 | } -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | throw new Error('you should require a method of 101, just like require("101/")'); 2 | exports = module.exports = function(){}; 3 | -------------------------------------------------------------------------------- /instance-of.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/instance-of 3 | */ 4 | 5 | /** 6 | * Functional version of JavaScript's instanceof, returns a 7 | * partial function which expects a value argument and returns 8 | * true if the value is an instance of the Class (false if not). 9 | * @function module:101/instance-of 10 | * @param {function} Class - Class of which the value should be 11 | * @return {function} Partial-function instanceOfClass (which accepts any value and returns if the value is an instance of the specified class) 12 | */ 13 | 14 | // (function)(val) 15 | module.exports = instanceOf; 16 | 17 | function instanceOf (Class) { 18 | return function (val) { 19 | return val instanceof Class; 20 | }; 21 | } -------------------------------------------------------------------------------- /is-boolean.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-boolean 3 | */ 4 | 5 | /** 6 | * Functional version of val typeof 'boolean' 7 | * @function module:101/is-boolean 8 | * @param {*} val - value checked to be a boolean 9 | * @return {boolean} Whether the value is a boolean or not 10 | */ 11 | module.exports = isBoolean; 12 | 13 | function isBoolean (val) { 14 | return typeof val === 'boolean'; 15 | } -------------------------------------------------------------------------------- /is-empty.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-empty 3 | */ 4 | 5 | var isString = require('./is-string'); 6 | var isObject = require('./is-object'); 7 | var isArray = Array.isArray; 8 | 9 | /** 10 | * Functional version of val empty object, array or object 11 | * @function module:101/is-empty 12 | * @param {string|array|object} val - value checked to be a empty 13 | * @return {boolean} Whether the value is an empty or not 14 | */ 15 | module.exports = isEmpty; 16 | 17 | function isEmpty (val) { 18 | if (isString(val) || isArray(val)) { 19 | return val.length === 0; 20 | } 21 | else if (isObject(val)) { 22 | for (var name in val) { 23 | return false; 24 | } 25 | return true; 26 | } 27 | else { 28 | throw new TypeError('Val must be a string, array or object'); 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /is-function.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-function 3 | */ 4 | 5 | /** 6 | * Functional version of val typeof 'function' 7 | * @function module:101/is-function 8 | * @param {*} val - value checked to be a function 9 | * @return {boolean} Whether the value is a function or not 10 | */ 11 | module.exports = isFunction; 12 | 13 | function isFunction (v) { 14 | return typeof v === 'function'; 15 | } -------------------------------------------------------------------------------- /is-integer.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-integer 3 | */ 4 | 5 | /** 6 | * Returns true if n is an integer. 7 | * @function module:101/is-integer 8 | * @param {*} val - value checked to be a string 9 | * @return {boolean} Whether the value is an integer or not 10 | */ 11 | 12 | module.exports = isInteger; 13 | 14 | function isInteger (val) { 15 | return typeof val === 'number' && isFinite(val) && Math.floor(val) === val; 16 | } 17 | -------------------------------------------------------------------------------- /is-number.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-number 3 | */ 4 | 5 | /** 6 | * Functional version of val typeof 'number' 7 | * @function module:101/is-number 8 | * @param {*} val - value checked to be a string 9 | * @return {boolean} Whether the value is an string or not 10 | */ 11 | module.exports = isNumber; 12 | 13 | function isNumber (val) { 14 | return (typeof val === 'number' || val instanceof Number) && !isNaN(val) 15 | } 16 | -------------------------------------------------------------------------------- /is-object.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Functional version of a strict object check (Arrays and RegExps are not objects) 3 | * @module 101/is-object 4 | */ 5 | 6 | /** 7 | * @function module:101/is-object 8 | * @param {*} val - value checked to be an object 9 | * @return {boolean} Whether the value is an object or not 10 | */ 11 | var exists = require('./exists'); 12 | 13 | module.exports = isObject; 14 | 15 | function isObject (val) { 16 | return typeof val === 'object' && 17 | exists(val) && 18 | !Array.isArray(val) && 19 | !(val instanceof RegExp) && 20 | !(val instanceof String) && 21 | !(val instanceof Number); 22 | } -------------------------------------------------------------------------------- /is-regexp.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-regexp 3 | */ 4 | 5 | /** 6 | * Check if a value is an instance of RegExp 7 | * @function module:101/is-regexp 8 | * @param {*} val - value checked to be an instance of RegExp 9 | * @return {boolean} Whether the value is an object or not 10 | */ 11 | 12 | module.exports = function isRegExp (val) { 13 | return Object.prototype.toString.call(val) == '[object RegExp]'; 14 | }; 15 | 16 | -------------------------------------------------------------------------------- /is-string.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/is-string 3 | */ 4 | 5 | /** 6 | * Functional version of val typeof 'string' 7 | * @function module:101/is-string 8 | * @param {*} val - value checked to be a string 9 | * @return {boolean} Whether the value is an string or not 10 | */ 11 | module.exports = isString; 12 | 13 | function isString (val) { 14 | return typeof val === 'string' || val instanceof String; 15 | } 16 | -------------------------------------------------------------------------------- /keys-in.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/keys-in 3 | */ 4 | 5 | /** 6 | * Get all the keys compositing an object, including the `Object.prototype` 7 | * @function module:101/keys-in 8 | * 9 | * @param {object} object - the object from which to extract the keys 10 | * @return {array} array of keys 11 | */ 12 | module.exports = keysIn; 13 | 14 | function keysIn(object) { 15 | if (!object) { return []; } 16 | 17 | var keys = []; 18 | for (var key in object) { 19 | keys.push(key); 20 | } 21 | 22 | return keys; 23 | } 24 | -------------------------------------------------------------------------------- /last.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/last 3 | */ 4 | 5 | var isObject = require('./is-object'); 6 | var exists = require('./exists'); 7 | var isFunction = require('./is-function'); 8 | 9 | /** 10 | * Returns the last value of the item. 11 | * @function module:101/last 12 | * @param {array|string|object} item - item whose last value is returned 13 | * @return {*} Last value of an array. Last char of a string. Last value of an object. Last char of item.toString() for everything else. 14 | */ 15 | module.exports = last; 16 | 17 | function last (item) { 18 | var val; 19 | if (exists(item && item.length) && !isFunction(item)) { 20 | val = item[item.length - 1]; 21 | } 22 | else { 23 | val = (item && item.toString) ? last(item.toString()) : undefined; 24 | } 25 | return val; 26 | } -------------------------------------------------------------------------------- /lens.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/lens 3 | */ 4 | 5 | var get = require('./pluck'); 6 | var put = require('./put'); 7 | var curry = require('./curry'); 8 | var clone = require('./clone'); 9 | 10 | /** 11 | * Returns a lens 12 | * @function module:101/lens 13 | * @param {string|function} key|getter - key or getter function 14 | * @param {function} [setter] - setter function 15 | * @return {function} lens 16 | */ 17 | module.exports = lens; 18 | 19 | function lens(getter, setter) { 20 | var _lens, key; 21 | 22 | if (arguments.length === 1) { 23 | // (key) 24 | key = getter; 25 | return lens(get(key), _setter(key)); 26 | } else { 27 | // (getter, setter) 28 | _lens = getter; 29 | } 30 | 31 | _lens.set = curry(setter, 2); 32 | _lens.mod = curry(function(mod, obj) { 33 | return _lens.set(mod(_lens(obj)), clone(obj)); 34 | }); 35 | return _lens; 36 | } 37 | 38 | function _setter(key) { 39 | return function(value, obj) { 40 | return put(obj, key, value); 41 | }; 42 | } 43 | -------------------------------------------------------------------------------- /noop.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/noop 3 | */ 4 | 5 | /** 6 | * Does nothing - no operation 7 | */ 8 | module.exports = function () {}; -------------------------------------------------------------------------------- /not.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/not 3 | */ 4 | 5 | var isFunction = require('./is-function'); 6 | 7 | /** 8 | * Functional version of ! 9 | * @function module:101/not 10 | * @param {*} val - value to inverse 11 | * @return {function} - function whose arguments and context are applied to fn and result is inversed 12 | */ 13 | module.exports = not; 14 | 15 | function not (val) { 16 | if (isFunction(val)) { 17 | return function (/* args */) { 18 | return not(val.apply(this, arguments)); 19 | }; 20 | } 21 | else { 22 | return !val; 23 | } 24 | } -------------------------------------------------------------------------------- /omit.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/omit 3 | */ 4 | 5 | var isObject = require('./is-object'); 6 | var pick = require('./pick') 7 | var keypather = require('keypather')() 8 | 9 | /** 10 | * Returns a new object without the specified keys. 11 | * When only keys are specified omit returns a partial-function which accepts obj. 12 | * @function module:101/omit 13 | * @param {object} [obj] - object whose keys are omited 14 | * @param {string|array} keys... - keys which will be dropped from obj (can be specifieds as args (strings and/or arrays) 15 | * @return {object|function} Object without the specified keys from the original obj or Partial-function omit (which accepts obj) and returns an object 16 | */ 17 | module.exports = function () { 18 | var args = Array.prototype.slice.call(arguments); 19 | if (isObject(args[0])) { 20 | var obj = args.shift(); 21 | return omit(obj, args); 22 | } 23 | else { 24 | return function (obj) { 25 | return omit(obj, args); 26 | }; 27 | } 28 | }; 29 | 30 | function omit (obj, args) { 31 | var omitKeys = []; 32 | args.forEach(function (key) { 33 | omitKeys = omitKeys.concat(key); 34 | }); 35 | var keys = Object.keys(obj); 36 | var out = pick(obj, keys); 37 | omitKeys.forEach(remove(out)); 38 | return out; 39 | } 40 | 41 | function remove (obj) { 42 | return function (key) { 43 | keypather.del(obj, key); 44 | }; 45 | } 46 | -------------------------------------------------------------------------------- /or.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/or 3 | */ 4 | 5 | /** 6 | * Functional version of || 7 | * @function module:101/or 8 | * @param {*} a - any value 9 | * @param {*} b - any value 10 | * @return {*} a || b 11 | */ 12 | 13 | module.exports = or; 14 | 15 | function or (a, b) { 16 | return a || b; 17 | } 18 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "101", 3 | "version": "1.6.3", 4 | "description": "common javascript utils that can be required selectively that assume es5+", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "lab -c -l -t 100 -a code", 8 | "test-watch": "nodemon --exec lab -c" 9 | }, 10 | "repository": { 11 | "type": "git", 12 | "url": "https://github.com/tjmehta/101" 13 | }, 14 | "keywords": [ 15 | "utils", 16 | "js", 17 | "helpers", 18 | "functional", 19 | "pick", 20 | "pluck", 21 | "map", 22 | "array", 23 | "object", 24 | "string" 25 | ], 26 | "author": "Tejesh Mehta", 27 | "license": "MIT", 28 | "bugs": { 29 | "url": "https://github.com/tjmehta/101/issues" 30 | }, 31 | "homepage": "https://github.com/tjmehta/101", 32 | "devDependencies": { 33 | "code": "^1.5.0", 34 | "lab": "^5.9.0", 35 | "sinon": "^1.17.3" 36 | }, 37 | "dependencies": { 38 | "clone": "^1.0.2", 39 | "deep-eql": "^0.1.3", 40 | "keypather": "^1.10.2" 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /pass-all.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/pass-all 3 | */ 4 | 5 | var isFunction = require('./is-function'); 6 | var and = require('./and'); 7 | var apply = require('./apply'); 8 | 9 | /** 10 | * Muxes arguments across many functions and &&'s the results 11 | * @function module:101/pass-all 12 | * @param {function} funcs... - functions which return a boolean 13 | * @return {function} function which accepts args which it applies to funcs and &&s the results 14 | */ 15 | module.exports = passAll; 16 | 17 | function passAll (/* funcs */) { 18 | var funcs = Array.prototype.slice.call(arguments); 19 | if (!funcs.every(isFunction)) { 20 | throw new TypeError('all funcs should be functions'); 21 | } 22 | return function (/* arguments */) { 23 | return funcs.map(apply(this, arguments)).reduce(and); 24 | }; 25 | } -------------------------------------------------------------------------------- /pass-any.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/pass-any 3 | */ 4 | 5 | var isFunction = require('./is-function'); 6 | 7 | /** 8 | * Muxes arguments across many functions and ||'s the results 9 | * @function module:101/pass-any 10 | * @param {function} funcs... - functions which return a boolean 11 | * @return {function} function which accepts args which it applies to funcs and ||s the results 12 | */ 13 | module.exports = passAny; 14 | 15 | function passAny (/* funcs */) { 16 | var funcs = Array.prototype.slice.call(arguments); 17 | if (!funcs.every(isFunction)) { 18 | throw new TypeError('all funcs should be functions'); 19 | } 20 | return function (/* arguments */) { 21 | var args = arguments; 22 | var self = this; 23 | return funcs.some(function (func) { 24 | return func.apply(self, args); 25 | }); 26 | }; 27 | } -------------------------------------------------------------------------------- /pick.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/pick 3 | */ 4 | 5 | var exists = require('./exists'); 6 | var isObject = require('./is-object'); 7 | var isRegExp = require('./is-regexp'); 8 | var isString = require('./is-string'); 9 | var keypather = require('keypather')(); 10 | var isKeypath = function (val) { 11 | return Array.isArray(val) || isString(val) || isRegExp(val) 12 | } 13 | 14 | /** 15 | * Returns a new object with the specified keys (with key values from obj). 16 | * When only keys are specified pick returns a partial-function which accepts obj. 17 | * @function module:101/pick 18 | * @param {object} [obj] - object whose keys are picked 19 | * @param {string|regexp|array} keys... - keys which will be taken from obj, can be specifieds as args (strings, regular epxressions, and/or arrays) 20 | * @return {object|function} Object with only the keys specified from the original obj or Partial-function pick (which accepts obj) and returns an object 21 | */ 22 | module.exports = function () { 23 | var args = Array.prototype.slice.call(arguments); 24 | if (exists(args[0]) && !isKeypath(args[0])) { 25 | var obj = args.shift(); 26 | return pick(obj, args); 27 | } else { 28 | return function (obj) { 29 | return pick(obj, args); 30 | }; 31 | } 32 | }; 33 | 34 | function pick (obj, args) { 35 | var keys = []; 36 | args.forEach(function (key) { 37 | keys = keys.concat(key); 38 | }); 39 | var out = {}; 40 | keys.forEach(copy(obj, out)); 41 | return out; 42 | } 43 | 44 | function copy (from, to) { 45 | return function (key) { 46 | if (isRegExp(key)) { 47 | var flatFrom = keypather.flatten(from); 48 | Object.keys(flatFrom).forEach(function(keypathFrom) { 49 | if (key.test(keypathFrom)) { 50 | keypather.set(to, keypathFrom, keypather.get(from, keypathFrom)); 51 | } 52 | }); 53 | } else { 54 | if (keypather.in(from, key)) { 55 | keypather.set(to, key, keypather.get(from, key)); 56 | } 57 | } 58 | }; 59 | } 60 | -------------------------------------------------------------------------------- /pluck.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/pluck 3 | */ 4 | 5 | var isObject = require('./is-object'); 6 | var exists = require('./exists'); 7 | var keypather = require('keypather')(); 8 | 9 | /** 10 | * Functional version of obj[key], returns the value of the key from obj. 11 | * When only a key is specified pluck returns a partial-function which accepts obj. 12 | * @function module:101/pluck 13 | * @param {object} [obj] - object from which the value is plucked 14 | * @param {string|array} key - key of the value from obj which is returned 15 | * @param {boolean} [isKeypath=true] - specifies whether the key is a keypath or key 16 | * @return {*|function} The value of the key from obj or Partial-function pluck (which accepts obj) and returns the value of the key from obj 17 | */ 18 | module.exports = function (obj, key, isKeypath) { 19 | if (!isObject(obj)) { 20 | isKeypath = key; 21 | key = obj; 22 | return function (obj) { 23 | return pluck(obj, key, isKeypath); 24 | }; 25 | } 26 | else { 27 | return pluck(obj, key, isKeypath); 28 | } 29 | }; 30 | 31 | function pluck (obj, key, isKeypath) { 32 | key = Array.isArray(key) ? key[0] : key; 33 | isKeypath = exists(isKeypath) ? isKeypath : true; 34 | return isKeypath ? 35 | keypather.get(obj, key): 36 | obj[key]; 37 | } -------------------------------------------------------------------------------- /put.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/put 3 | */ 4 | 5 | var clone = require("./clone"); 6 | var isString = require('./is-string'); 7 | var isNumber = require('./is-number'); 8 | var isObject = require('./is-object'); 9 | var keypather = require('keypather')(); 10 | 11 | /** 12 | * Immutable version of obj[key] = val. 13 | * When only key and val are specified, put returns a partial function which accepts obj. 14 | * @function module:101/put 15 | * @param {*} [obj] - object which will be cloned and assigned with {key: value} 16 | * @param {string|number} key - key of the value being put on obj 17 | * @param {*} val - value of the key being put on obj 18 | * @return {*|function} New obj with new value set or Partial-function put (which accepts obj) and returns a new obj with val set 19 | */ 20 | module.exports = put; 21 | 22 | function put (obj, key, val) { 23 | var setObj; 24 | if (arguments.length === 1) { 25 | // (setObj) 26 | setObj = obj; 27 | return function (obj) { 28 | return putKeypaths(obj, setObj); // extends original 29 | }; 30 | } 31 | if (arguments.length === 2) { 32 | if (isString(obj) || isNumber(obj)) { 33 | // (key, val) 34 | val = key; 35 | key = obj; 36 | setObj = {}; 37 | keypather.set(setObj, key, val); 38 | return function (obj) { 39 | return putKeypaths(obj, setObj); // extends original 40 | }; 41 | } 42 | else if (isObject(key)) { 43 | // (obj, setObj) 44 | setObj = key; 45 | return putKeypaths(obj, setObj); // extends original 46 | } 47 | else { 48 | throw new TypeError('Invalid arguments: expected string, number, or object'); 49 | } 50 | } 51 | else { 52 | setObj = {}; 53 | setObj[key] = val 54 | return putKeypaths(obj, setObj); // extends original 55 | } 56 | } 57 | 58 | function putKeypaths (obj, setObj) { 59 | // copy the object 60 | obj = clone(obj); 61 | Object.keys(setObj).forEach(function (keypath) { 62 | var val = setObj[keypath]; 63 | keypather.set(obj, keypath, val); 64 | }); 65 | return obj; 66 | } -------------------------------------------------------------------------------- /set.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/set 3 | */ 4 | 5 | var isString = require('./is-string'); 6 | var isNumber = require('./is-number'); 7 | var isObject = require('./is-object'); 8 | var keypather = require('keypather')(); 9 | 10 | /** 11 | * Functional version of obj[key] = val. 12 | * When only a key and val are specified set returns a partial-function which accepts obj. 13 | * @function module:101/set 14 | * @param {*} [obj] - object on which the values will be set 15 | * @param {string} key - key of the value being set on obj 16 | * @param {*} val - value of the key being set on obj 17 | * @return {*|function} The same obj with new value set or Partial-function set (which accepts obj) and returns the same obj with val set 18 | */ 19 | module.exports = set; 20 | 21 | function set (obj, key, val) { 22 | var setObj; 23 | if (arguments.length === 1) { 24 | // (setObj) 25 | setObj = obj; 26 | return function (obj) { 27 | return setKeypaths(obj, setObj); // extends original 28 | }; 29 | } 30 | if (arguments.length === 2) { 31 | if (isString(obj) || isNumber(obj)) { 32 | // (key, val) 33 | val = key; 34 | key = obj; 35 | setObj = {}; 36 | keypather.set(setObj, key, val); 37 | return function (obj) { 38 | return setKeypaths(obj, setObj); // extends original 39 | }; 40 | } 41 | else if (isObject(key)) { 42 | // (obj, setObj) 43 | setObj = key; 44 | return setKeypaths(obj, setObj); // extends original 45 | } 46 | else { 47 | throw new TypeError('Invalid arguments: expected string, number, or object'); 48 | } 49 | } 50 | else { 51 | setObj = {}; 52 | setObj[key] = val 53 | return setKeypaths(obj, setObj); // extends original 54 | } 55 | } 56 | 57 | function setKeypaths (obj, setObj) { 58 | Object.keys(setObj).forEach(function (keypath) { 59 | var val = setObj[keypath]; 60 | keypather.set(obj, keypath, val); 61 | }); 62 | return obj; 63 | } -------------------------------------------------------------------------------- /test/test-and.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var and = require('../and'); 10 | 11 | describe('and', function() { 12 | it('should work with reduce', function (done) { 13 | expect([true, true, false].reduce(and)).to.equal(false); 14 | expect([true, true, true].reduce(and)).to.equal(true); 15 | done(); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /test/test-apply.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var before = lab.before; 7 | var after = lab.after; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var apply = require('../apply'); 12 | 13 | describe('apply', function () { 14 | var ctx = {}; 15 | before(function (done) { 16 | ctx.args = [1,2,3]; 17 | done(); 18 | }); 19 | after(function (done) { 20 | delete ctx.args; 21 | done(); 22 | }); 23 | it('should apply context and arguments to a function - working array functions', function (done) { 24 | expect([sum].map(apply(null, ctx.args))).to.deep.equal([sum.apply(null, ctx.args)]); 25 | done(); 26 | }); 27 | describe('context', function() { 28 | before(function (done) { 29 | ctx.ctx = { foo: 1 }; 30 | done(); 31 | }); 32 | after(function (done) { 33 | delete ctx.ctx; 34 | done(); 35 | }); 36 | it('should apply context and arguments to a function - working array functions', function (done) { 37 | var context = {}; 38 | apply(context)(checkContext); 39 | done(); 40 | function checkContext () { 41 | return expect(this).to.deep.equal(context); 42 | } 43 | }); 44 | }); 45 | }); 46 | 47 | function sum (/* args */) { 48 | var args = Array.prototype.slice.call(arguments); 49 | return args.reduce(function (memo, item) { 50 | return memo + item; 51 | }, 0); 52 | } 53 | 54 | -------------------------------------------------------------------------------- /test/test-assign.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var assign = require('../assign'); 10 | 11 | // very simple test primarily checking exportation, see npm `assign` module... 12 | describe('assign', function () { 13 | it('should assign an object', function (done) { 14 | var obj = { 15 | foo: 1, 16 | bar: 1, 17 | qux: 1 18 | }; 19 | var obj2 = { 20 | you: 1 21 | }; 22 | var assigned = assign(obj, obj2); 23 | expect(assigned).to.deep.equal(obj); 24 | expect(assigned).to.deep.equal({ 25 | foo: 1, 26 | bar: 1, 27 | qux: 1, 28 | you: 1 29 | }); 30 | done(); 31 | }); 32 | it('should support partial functionality', function (done) { 33 | var obj = { 34 | foo: 1, 35 | bar: 1, 36 | qux: 1 37 | }; 38 | var obj2 = { 39 | you: 1 40 | }; 41 | var assignPartial = assign(obj2); 42 | var assigned = assignPartial(obj); // works great with map 43 | expect(assigned).to.deep.equal(obj); 44 | expect(assigned).to.deep.equal({ 45 | foo: 1, 46 | bar: 1, 47 | qux: 1, 48 | you: 1 49 | }); 50 | done(); 51 | }); 52 | it('should throw an error if source is undefined', function (done) { 53 | try { 54 | assign(undefined, {}); 55 | } 56 | catch (e) { 57 | expect(e.message).to.equal('Cannot convert first argument to object'); 58 | done(); 59 | } 60 | }); 61 | it('should throw an error if source is null', function (done) { 62 | try { 63 | assign(null, {}); 64 | } 65 | catch (e) { 66 | expect(e.message).to.equal('Cannot convert first argument to object'); 67 | done(); 68 | } 69 | }); 70 | it('should just return the target if sources are undefined or null', function(done) { 71 | var obj = {}; 72 | expect(assign(obj, null)).to.deep.equal(obj); 73 | expect(assign(obj, undefined)).to.deep.equal(obj); 74 | done(); 75 | }); 76 | }); 77 | -------------------------------------------------------------------------------- /test/test-bind-all.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var bindAll = require('../bind-all'); 10 | 11 | describe('bind-all', function() { 12 | it('should bind all the methods', function(done) { 13 | var res; 14 | var Test = function() { 15 | bindAll(this); 16 | this.run(this.fn); 17 | }; 18 | Test.prototype = { 19 | run: function(fn) { return fn(); }, 20 | fn: function() { res = this instanceof Test; } 21 | }; 22 | new Test(); 23 | 24 | expect(res).to.be.true(); 25 | done(); 26 | }); 27 | 28 | it('should bind only the specified method', function(done) { 29 | var binded; 30 | var unbinded; 31 | var Test = function() { 32 | bindAll(this, ['fn']); 33 | this.run(this.fn, this.not); 34 | }; 35 | Test.prototype = { 36 | run: function(one, two) { one(); two(); }, 37 | fn: function() { binded = this instanceof Test; }, 38 | not: function() { unbinded = this instanceof Test; } 39 | }; 40 | new Test(); 41 | 42 | expect(binded).to.be.true(); 43 | expect(unbinded).to.be.false(); 44 | done(); 45 | }); 46 | 47 | it('should bind an array with multiple keys', function(done) { 48 | var binded; 49 | var also; 50 | var Test = function() { 51 | bindAll(this, ['fn', 'also']); 52 | this.run(this.fn, this.also); 53 | }; 54 | Test.prototype = { 55 | run: function(one, two) { one(); two(); }, 56 | fn: function() { binded = this instanceof Test; }, 57 | also: function() { also = this instanceof Test; } 58 | }; 59 | new Test(); 60 | 61 | expect(binded).to.be.true(); 62 | expect(also).to.be.true(); 63 | done(); 64 | }); 65 | 66 | it('should trow an error when a wrong format is passed', function(done) { 67 | var object = {}; 68 | expect(bindAll.bind(this, object, 'key')).to.throw(TypeError); 69 | done(); 70 | }); 71 | 72 | it('should return the original object', function(done) { 73 | var object = { 74 | hello: function() {} 75 | }; 76 | 77 | expect(bindAll(object)).to.deep.equal(object); 78 | done(); 79 | }); 80 | 81 | it('should return the original empty object', function(done) { 82 | var object = {}; 83 | var res = bindAll(object); 84 | 85 | expect(res).to.deep.equal(object); 86 | done(); 87 | }); 88 | 89 | it('should not try to bind non-functions keys', function(done) { 90 | var object = { 91 | bool: true, 92 | str: 'hello', 93 | call: function() {}, 94 | }; 95 | 96 | expect(bindAll(object)).to.deep.equal(object); 97 | done(); 98 | }); 99 | 100 | it('should not fail when we specify a non-existing key', function(done) { 101 | var object = { 102 | call: function() {} 103 | }; 104 | 105 | expect(bindAll(object, ['call', 'world'])).to.deep.equal(object); 106 | done(); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /test/test-clone.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var clone = require('../clone'); 10 | 11 | // very simple test primarily checking exportation, see npm `clone` module... 12 | describe('clone', function () { 13 | it('should clone an object', function(done) { 14 | var obj = { 15 | foo: 1, 16 | bar: 1, 17 | qux: 1 18 | }; 19 | expect(clone(obj)).to.deep.equal({ 20 | foo: 1, 21 | bar: 1, 22 | qux: 1 23 | }); 24 | done(); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /test/test-compose.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var compose = require('../compose'); 3 | var lab = exports.lab = Lab.script(); 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | describe('compose', function() { 10 | it('compose(f, g)(x) should be identical to f(g(x))', function(done) { 11 | var f = function(x) { return x * x; } 12 | var g = function(x) { return x / 5; } 13 | var x = Math.random(); 14 | var expected = f(g(x)); 15 | var composed = compose(f, g); 16 | var actual = composed(x); 17 | expect(actual).to.equal(expected); 18 | done(); 19 | }); 20 | 21 | it('compose(f, sum)(x, y) should be identical to f(sum(x, y))', function(done) { 22 | var f = function(x) { return x * x; } 23 | var sum = function(x, y) { return x + y; } 24 | var x = Math.random(); 25 | var y = Math.random(); 26 | var expected = f(sum(x, y)); 27 | var composed = compose(f, sum); 28 | var actual = composed(x, y); 29 | expect(actual).to.equal(expected); 30 | done(); 31 | }); 32 | 33 | 34 | it('compose(f, g)(x) should be identical to [x].map(g).map(f)[0]', function(done) { 35 | var f = function(x) { return -x; } 36 | var g = function(x) { return x * 5; } 37 | var x = Math.random(); 38 | var expected = [x].map(g).map(f)[0]; 39 | var composed = compose(f, g); 40 | var actual = composed(x); 41 | expect(actual).to.equal(expected); 42 | done(); 43 | }); 44 | 45 | it('[f,g].reduce(compose) should be identical to f(g(x))', function(done) { 46 | var f = function(x) { return x + x; } 47 | var g = function(x) { return x - 9; } 48 | var x = Math.random(); 49 | var expected = f(g(x)); 50 | var composed = [f,g].reduce(compose); 51 | var actual = composed(x); 52 | expect(actual).to.equal(expected); 53 | done(); 54 | }); 55 | }); 56 | -------------------------------------------------------------------------------- /test/test-converge.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var converge = require('../converge'); 3 | var compose = require('../compose'); 4 | var lab = exports.lab = Lab.script(); 5 | var describe = lab.describe; 6 | var it = lab.it; 7 | var beforeEach = lab.beforeEach; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | describe('converge', function() { 12 | var add, f, g, h, x; 13 | 14 | beforeEach(function(done) { 15 | add = function(a, b) { return a + b; }; 16 | f = function(x) { return x * x; }; 17 | g = function(x) { return x / 5; }; 18 | h = function(x) { return x + 5; }; 19 | x = Math.random(); 20 | done(); 21 | }); 22 | 23 | it('converge(f, [g])(x) should be identical to f(g(x))', function(done) { 24 | var expected = f(g(x)); 25 | var converged = converge(f, [g]); 26 | var actual = converged(x); 27 | expect(actual).to.equal(expected); 28 | done(); 29 | }); 30 | 31 | it('converge(add, [g, h])(x) should be identical to add(g(x), h(x))', function(done) { 32 | var expected = add(g(x), h(x)); 33 | var converged = converge(add, [g, h]); 34 | var actual = converged(x); 35 | expect(actual).to.equal(expected); 36 | done(); 37 | }); 38 | 39 | it('[f, converge(add, [f, g]), h].reduce(compose) should be identical to f(add(f(h(x)), g(h(x))))', function(done) { 40 | var expected = f(add(f(h(x)), g(h(x)))); 41 | var converged = [f, converge(add, [f, g]), h].reduce(compose); 42 | var actual = converged(x); 43 | expect(actual).to.equal(expected); 44 | done(); 45 | }); 46 | }); 47 | -------------------------------------------------------------------------------- /test/test-curry.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var curry = require('../curry'); 3 | var lab = exports.lab = Lab.script(); 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var beforeEach = lab.beforeEach; 7 | var Code = require('code'); 8 | var expect = Code.expect; 9 | 10 | describe('curry', function() { 11 | var x, y, f, g, h; 12 | 13 | beforeEach(function(done) { 14 | var slice = Array.prototype.slice; 15 | 16 | f = function(a) { 17 | return a; 18 | }; 19 | 20 | g = function(a, b) { 21 | return a + b; 22 | }; 23 | 24 | h = function() { 25 | return slice.call(arguments).join(); 26 | }; 27 | 28 | x = Math.random(); 29 | y = Math.random(); 30 | 31 | done(); 32 | }); 33 | 34 | it('curry(f)(1) should be identical to f(1)', function(done) { 35 | var expected = f(x); 36 | var curryF = curry(f); 37 | var actual = curryF(x); 38 | expect(actual).to.equal(expected); 39 | done(); 40 | }); 41 | 42 | it('curry(g)(1)(2) should be identical to g(1, 2)', function(done) { 43 | var expected = g(x, y); 44 | var curryG = curry(g); 45 | var actual = curryG(x)(y); 46 | expect(actual).to.equal(expected); 47 | done(); 48 | }); 49 | 50 | it('curry(g)(1, 2) should be identical to g(1, 2)', function(done) { 51 | var expected = g(x, y); 52 | var curryG = curry(g); 53 | var actual = curryG(x, y); 54 | expect(actual).to.equal(expected); 55 | done(); 56 | }); 57 | 58 | it('curry(h, 3)(1, 2, 3) should be identical to h(1, 2, 3)', function(done) { 59 | var expected = h(x, y, y); 60 | var curryH = curry(h, 3); 61 | var actual = curryH(x, y, y); 62 | expect(actual).to.equal(expected); 63 | done(); 64 | }); 65 | 66 | it('curry(g)(1, 2, 3) should be identical to g(1, 2)', function(done) { 67 | var expected = g(x, y); 68 | var curryG = curry(g); 69 | var actual = curryG(x, y, y); 70 | expect(actual).to.equal(expected); 71 | done(); 72 | }); 73 | 74 | it('curry(h, 2)(1, 2, 3) should be identical to h(1, 2)', function(done) { 75 | var expected = h(x, y); 76 | var curryH = curry(h, 2); 77 | var actual = curryH(x, y, y); 78 | expect(actual).to.equal(expected); 79 | done(); 80 | }); 81 | }); 82 | -------------------------------------------------------------------------------- /test/test-defaults.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var defaults = require('../defaults'); 10 | 11 | describe('defaults', function () { 12 | it('should provide default values for an object', function (done) { 13 | var d = { 14 | foo: 1, 15 | bar: 4, 16 | qux: 3 17 | }; 18 | 19 | var o = { 20 | foo: 0, 21 | bar: 2 22 | }; 23 | 24 | var c = defaults(o, d); 25 | 26 | expect(c).to.deep.equal({ 27 | foo: 0, 28 | bar: 2, 29 | qux: 3 30 | }); 31 | 32 | done(); 33 | }); 34 | 35 | it('should not default deep objects w/o flag', function (done) { 36 | var d = { 37 | qux: { 38 | one: 1, 39 | two: 2 40 | }, 41 | foo: { 42 | bar: true 43 | }, 44 | empty: false 45 | }; 46 | 47 | var o = { 48 | qux: { 49 | two: 3, 50 | three: 3 51 | }, 52 | baz: { 53 | buz: false 54 | }, 55 | empty: {} 56 | }; 57 | 58 | var c = defaults(o, d); 59 | 60 | expect(c).to.deep.equal({ 61 | qux: { 62 | // one is skipped (in object) 63 | two: 3, // set in the initial object 64 | three: 3 // in the target (not from defaults) 65 | }, 66 | baz: { 67 | buz: false // object from default 68 | }, 69 | foo: { 70 | bar: true // object from default 71 | }, 72 | empty: {} // set in initial object 73 | }); 74 | 75 | done(); 76 | }); 77 | 78 | it('should allow defaults in sub objects with deep flag', function (done) { 79 | var d = { 80 | qux: { 81 | one: 1, 82 | two: 2 83 | }, 84 | foo: { 85 | bar: true 86 | }, 87 | empty: false 88 | }; 89 | 90 | var o = { 91 | qux: { 92 | two: 3, 93 | three: 3 94 | }, 95 | baz: { 96 | buz: false 97 | }, 98 | empty: {} 99 | }; 100 | 101 | var c = defaults(o, d, true); 102 | 103 | expect(c).to.deep.equal({ 104 | qux: { 105 | one: 1, // from defaults 106 | two: 3, // set in the set value (but in default) 107 | three: 3 // in the target (not from defaults) 108 | }, 109 | foo: { 110 | bar: true // object from default 111 | }, 112 | baz: { 113 | buz: false // object from default 114 | }, 115 | empty: {} // target object, primitive default 116 | }); 117 | 118 | done(); 119 | }); 120 | 121 | it('should initialize a new target if one does not exist', function (done) { 122 | var o = null; 123 | 124 | var d = { 125 | foo: 1, 126 | bar: 2, 127 | qux: 3 128 | }; 129 | 130 | var c = defaults(o, d); 131 | 132 | expect(c).to.deep.equal({ 133 | foo: 1, 134 | bar: 2, 135 | qux: 3 136 | }); 137 | 138 | done(); 139 | }); 140 | 141 | it('should return target if source does not exist', function (done) { 142 | var d = null; 143 | 144 | var o = { 145 | foo: 1, 146 | bar: 2, 147 | qux: 3 148 | }; 149 | 150 | var c = defaults(o, d); 151 | 152 | expect(c).to.deep.equal({ 153 | foo: 1, 154 | bar: 2, 155 | qux: 3 156 | }); 157 | 158 | done(); 159 | }); 160 | 161 | describe('should support partial functionality', function () { 162 | it('should work basically', function (done) { 163 | var o = { 164 | foo: 10 165 | }; 166 | 167 | var d = { 168 | foo: 1, 169 | bar: 2, 170 | qux: 3 171 | }; 172 | 173 | var partial = defaults(d); 174 | var c = partial(o); 175 | 176 | expect(c).to.deep.equal({ 177 | foo: 10, 178 | bar: 2, 179 | qux: 3 180 | }); 181 | 182 | done(); 183 | }); 184 | 185 | it('should work with deep flag', function (done) { 186 | var o = { 187 | foo: { 188 | one: 1, 189 | two: 2 190 | } 191 | }; 192 | 193 | var d = { 194 | foo: { 195 | one: 100, 196 | three: 300 197 | }, 198 | bar: true 199 | }; 200 | 201 | var partial = defaults(d, true); 202 | var c = partial(o); 203 | 204 | expect(c).to.deep.equal({ 205 | foo: { 206 | one: 1, 207 | two: 2, 208 | three: 300 209 | }, 210 | bar: true 211 | }); 212 | 213 | done(); 214 | }); 215 | }); 216 | 217 | }); 218 | -------------------------------------------------------------------------------- /test/test-del.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var clone = require('clone'); 10 | var del = require('../del'); 11 | var pluck = require('../pluck'); 12 | 13 | describe('del', function () { 14 | it('should del a key with value on a object', function(done) { 15 | var obj = { 16 | foo: 1, 17 | bar: 1, 18 | qux: 1 19 | }; 20 | 21 | var key = 'bar'; 22 | 23 | var expected = clone(obj); 24 | delete expected[key]; 25 | 26 | expect(del(obj, key)).to.deep.equal(expected); 27 | expect(obj[key]).to.equal(undefined); // original obj modified 28 | done(); 29 | }); 30 | it('should support keypaths', function(done) { 31 | var obj = { 32 | foo: { 33 | moo: 1, 34 | boo: 2 35 | }, 36 | bar: 1, 37 | qux: 1 38 | }; 39 | 40 | var key = 'foo.moo'; 41 | 42 | var expected = clone(obj); 43 | delete expected.foo.moo; 44 | 45 | expect(del(obj, key)).to.deep.equal(expected); 46 | expect(obj.foo.moo).to.equal(undefined); // original obj modified 47 | done(); 48 | }); 49 | it('should del a set of keys when given an array', function (done) { 50 | var obj = { 51 | foo: 1, 52 | bar: 1, 53 | qux: 1 54 | }; 55 | 56 | var delKeys = ['foo', 'bar']; 57 | 58 | var expected = clone(obj); 59 | delete expected.foo; 60 | delete expected.bar; 61 | 62 | expect(del(obj, delKeys)).to.deep.equal(expected); 63 | expect(obj.foo).to.equal(undefined); // original obj modified 64 | expect(obj.bar).to.equal(undefined); // original obj modified 65 | done(); 66 | }); 67 | it('should del a set of keys when given an array when used with array functions', function (done) { 68 | var objs = [ 69 | { 70 | bar: 1 71 | }, 72 | { 73 | foo: 2, 74 | bar: 2, 75 | qux: 2 76 | }, 77 | { 78 | foo: 3, 79 | bar: 3, 80 | koo: 3, 81 | goo: 3 82 | } 83 | ]; 84 | 85 | var delKeys = ['foo', 'bar']; 86 | 87 | var expected = objs.map(function (obj) { 88 | var copy = clone(obj); 89 | delete copy.foo; 90 | delete copy.bar; 91 | return copy; 92 | }); 93 | expect(objs.map(del(delKeys))).to.deep.equal(expected); 94 | expect(objs.map(pluck('foo'))).to.deep.equal([undefined, undefined, undefined]); // original obj modified 95 | done(); 96 | }); 97 | describe('errors', function() { 98 | it('should error when given two args that artent str, val or obj, obj', function (done) { 99 | try { 100 | del(/what/, /what/); 101 | } 102 | catch (err) { 103 | expect(err).to.exist(); 104 | done(); 105 | } 106 | }); 107 | }); 108 | }); 109 | -------------------------------------------------------------------------------- /test/test-env-is.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var envIs = require('../env-is'); 10 | 11 | describe('envIs', function() { 12 | it('should return true when the argument matches the environment', function (done) { 13 | process.env.NODE_ENV='test'; 14 | expect(envIs('test')).to.equal(true); 15 | done(); 16 | }); 17 | it('should return false when the argument doesnt match the environment', function (done) { 18 | process.env.NODE_ENV='test'; 19 | expect(envIs('development')).to.equal(false); 20 | done(); 21 | }); 22 | it('should "or" if passed multiple environments', function (done) { 23 | process.env.NODE_ENV='test'; 24 | expect(envIs('development', 'test')).to.equal(true); 25 | done(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/test-equals.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var equals = require('../equals'); 10 | 11 | describe('equals', function() { 12 | it('should work like Object.is', function (done) { 13 | var obj = {}; 14 | var compares = [ 15 | ['hey', 'hey'], 16 | [2, 2], 17 | [obj, obj], 18 | ['hey', 'hey'], 19 | [2, '3'], 20 | [obj, {}], 21 | [false, ''], 22 | [+0, -0], 23 | [Number.NaN, NaN], 24 | [0, 0] 25 | ]; 26 | compares.forEach(function (items) { 27 | expect(equals(items[0], items[1])).to.equal(Object.is(items[0], items[1])); 28 | }); 29 | // Monkey patching Object.is, better way? 30 | var temp = Object.is; 31 | Object.is = false; 32 | compares.forEach(function (items) { 33 | expect(equals(items[0], items[1])).to.equal(temp(items[0], items[1])); 34 | }); 35 | Object.is = temp; 36 | done(); 37 | }); 38 | it('should works with array functions', function (done) { 39 | expect([1,2,3].map(equals(1))).to.deep.equal([true, false, false]); 40 | done(); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /test/test-exists.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var exists = require('../exists'); 10 | 11 | describe('exists', function () { 12 | it('should return true for existant vars', function(done) { 13 | expect(exists(['foo'])).to.be.true(); 14 | expect(exists('foo')).to.be.true(); 15 | expect(exists(101)).to.be.true(); 16 | expect(exists({})).to.be.true(); 17 | expect(exists(/re/)).to.be.true(); 18 | expect(exists(true)).to.be.true(); 19 | expect(exists(function () {})).to.be.true(); 20 | done(); 21 | }); 22 | it('should return false for non-existant vars', function(done) { 23 | expect(exists(null)).to.be.false(); 24 | expect(exists(undefined)).to.be.false(); 25 | done(); 26 | }); 27 | }); 28 | -------------------------------------------------------------------------------- /test/test-find-index.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var beforeEach = lab.beforeEach; 7 | var afterEach = lab.afterEach; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var isArray = Array.isArray; 12 | var isObject = require('../is-object'); 13 | var isFunction = require('../is-function'); 14 | 15 | var findIndex = require('../find-index'); 16 | 17 | describe('findIndex', function () { 18 | var ctx = {}; 19 | beforeEach(function (done) { 20 | ctx.arr = [ 21 | { 22 | bar: 1 23 | }, 24 | { 25 | foo: 2, 26 | bar: 2, 27 | qux: 2 28 | }, 29 | [], 30 | { 31 | foo: 3, 32 | bar: 3, 33 | koo: 3, 34 | goo: 3 35 | } 36 | ]; 37 | ctx.str = 'hello'; 38 | done(); 39 | }); 40 | afterEach(function (done) { 41 | delete ctx.arr; 42 | delete ctx.str; 43 | done(); 44 | }); 45 | it('should return -1 in an empty list', function (done) { 46 | var arr = []; 47 | expect(findIndex(arr, function (v) { return v === 1; })).to.equal(-1); 48 | done(); 49 | }); 50 | it('should get the index of an item in an array/string that passes a given function', function (done) { 51 | var arr = ctx.arr; 52 | expect(findIndex(arr, isObject)).to.equal(0); 53 | expect(findIndex(arr, isArray)).to.equal(2); 54 | expect(findIndex(arr, isFunction)).to.equal(-1); 55 | done(); 56 | }); 57 | it('should get the index of an item in an array/string that passes a given function when used with map', function (done) { 58 | var arr = ctx.arr; 59 | expect([arr].map(findIndex(isObject))).to.deep.equal([0]); 60 | expect([arr].map(findIndex(isArray))).to.deep.equal([2]); 61 | expect([arr].map(findIndex(isFunction))).to.deep.equal([-1]); 62 | done(); 63 | }); 64 | it('should error when given invalid arguments', function (done) { 65 | try { 66 | findIndex({}); 67 | } 68 | catch (err) { 69 | expect(err.message).to.equal('first argument must be a list (have length) or function'); 70 | } 71 | try { 72 | findIndex(); 73 | } 74 | catch (err) { 75 | expect(err.message).to.equal('first argument must be a list (have length) or function'); 76 | } 77 | try { 78 | findIndex(ctx.arr, {}); 79 | } 80 | catch (err) { 81 | expect(err.message).to.equal('predicate must be a function'); 82 | } 83 | try { 84 | findIndex(isArray)({}); 85 | } 86 | catch (err) { 87 | expect(err.message).to.equal('list must have length property'); 88 | } 89 | try { 90 | findIndex(isArray)(); 91 | } 92 | catch (err) { 93 | expect(err.message).to.equal('list must have length property'); 94 | } 95 | done(); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /test/test-find.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var beforeEach = lab.beforeEach; 7 | var afterEach = lab.afterEach; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var isArray = Array.isArray; 12 | var isObject = require('../is-object'); 13 | var isFunction = require('../is-function'); 14 | 15 | var find = require('../find'); 16 | 17 | describe('find', function () { 18 | var ctx = {}; 19 | beforeEach(function (done) { 20 | ctx.arr = [ 21 | { 22 | bar: 1 23 | }, 24 | { 25 | foo: 2, 26 | bar: 2, 27 | qux: 2 28 | }, 29 | [], 30 | { 31 | foo: 3, 32 | bar: 3, 33 | koo: 3, 34 | goo: 3 35 | } 36 | ]; 37 | ctx.str = 'hello'; 38 | done(); 39 | }); 40 | afterEach(function (done) { 41 | delete ctx.arr; 42 | delete ctx.str; 43 | done(); 44 | }); 45 | it('should return -1 in an empty list', function (done) { 46 | var arr = []; 47 | expect(find(arr, function (v) { return v === 1; })).to.equal(null); 48 | done(); 49 | }); 50 | it('should get the index of an item in an array/string that passes a given function', function (done) { 51 | var arr = ctx.arr; 52 | expect(find(arr, isObject)).to.equal(arr[0]); 53 | expect(find(arr, isArray)).to.equal(arr[2]); 54 | expect(find(arr, isFunction)).to.equal(null); 55 | done(); 56 | }); 57 | it('should get the index of an item in an array/string that passes a given function when used with map', function (done) { 58 | var arr = ctx.arr; 59 | expect([arr].map(find(isObject))).to.deep.equal([arr[0]]); 60 | expect([arr].map(find(isArray))).to.deep.equal([arr[2]]); 61 | expect([arr].map(find(isFunction))).to.deep.equal([null]); 62 | done(); 63 | }); 64 | it('should error when given invalid arguments', function (done) { 65 | try { 66 | find({}); 67 | } 68 | catch (err) { 69 | expect(err.message).to.equal('first argument must be a list (have length) or function'); 70 | } 71 | try { 72 | find(); 73 | } 74 | catch (err) { 75 | expect(err.message).to.equal('first argument must be a list (have length) or function'); 76 | } 77 | try { 78 | find(ctx.arr, {}); 79 | } 80 | catch (err) { 81 | expect(err.message).to.equal('predicate must be a function'); 82 | } 83 | try { 84 | find(isArray)({}); 85 | } 86 | catch (err) { 87 | expect(err.message).to.equal('list must have length property'); 88 | } 89 | try { 90 | find(isArray)(); 91 | } 92 | catch (err) { 93 | expect(err.message).to.equal('list must have length property'); 94 | } 95 | done(); 96 | }); 97 | }); 98 | -------------------------------------------------------------------------------- /test/test-flip.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var flip = require('../flip'); 10 | 11 | function prefix(pre, str) { 12 | return pre + str; 13 | } 14 | 15 | describe('flip', function() { 16 | it('should flip a function', function (done) { 17 | expect(flip(prefix)('hello', '_')).to.equal('_hello'); 18 | done(); 19 | }); 20 | }); 21 | -------------------------------------------------------------------------------- /test/test-group-by.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var groupBy = require('../group-by'); 10 | var pluck = require('../pluck'); 11 | var pick = require('../pick'); 12 | 13 | describe('groupBy', function() { 14 | it('should return empty object when no arguments are given', function(done) { 15 | expect(groupBy).to.throw(/must be a (string|function)/); 16 | done(); 17 | }); 18 | it('should work with an array and a string argument', function (done) { 19 | var arr = [ 20 | { foo: 'bar', bar: 'yo' }, 21 | { foo: 'bar', bar: 'yo2'}, 22 | { foo: 'qux' }, 23 | { foo: 'flux' }, 24 | { foo: 100 } 25 | ]; 26 | expect(groupBy([], 'foo')).to.deep.equal({}); 27 | expect(groupBy([{foo: 'bar'}], 'foo')).to.deep.equal({ 28 | 'bar': [{foo: 'bar'}] 29 | }); 30 | expect(groupBy(arr, 'foo')).to.deep.equal({ 31 | 'bar': [{foo: 'bar', bar: 'yo'}, { foo: 'bar', bar: 'yo2'}], 32 | 'qux': [{foo: 'qux'}], 33 | 'flux': [{foo: 'flux'}], 34 | '100': [{foo: 100}] 35 | }); 36 | done(); 37 | }); 38 | it('should work with an array and a function argument', function (done) { 39 | var arr = [ 40 | { foo: 'bar', bar: 'yo' }, 41 | { foo: 'qux' }, 42 | { foo: 'flux' }, 43 | { foo: 100 } 44 | ]; 45 | expect(groupBy([], pluck('foo'))).to.deep.equal({}); 46 | expect(groupBy([{foo: 'bar'}], pluck('foo'))).to.deep.equal({ 47 | 'bar': [{foo: 'bar'}] 48 | }); 49 | expect(groupBy(arr, pluck('foo'))).to.deep.equal({ 50 | 'bar': [{foo: 'bar', bar: 'yo'}], 51 | 'qux': [{foo: 'qux'}], 52 | 'flux': [{foo: 'flux'}], 53 | '100': [{foo: 100}] 54 | }); 55 | done(); 56 | }); 57 | it('should work with reduce, with a string argument', function (done) { 58 | var arr = [ 59 | { foo: 'bar', bar: 'yo' }, 60 | { foo: 'qux' }, 61 | { foo: 'flux' }, 62 | { foo: 100 } 63 | ]; 64 | expect([].reduce(groupBy('foo'), {})).to.deep.equal({}); 65 | expect([{foo:'bar'}].reduce(groupBy('foo'), {})).to.deep.equal({ 66 | 'bar': [{foo: 'bar'}] 67 | }); 68 | expect(arr.reduce(groupBy('foo'), {})).to.deep.equal({ 69 | 'bar': [{foo: 'bar', bar: 'yo'}], 70 | 'qux': [{foo: 'qux'}], 71 | 'flux': [{foo: 'flux'}], 72 | '100': [{foo: 100}] 73 | }); 74 | done(); 75 | }); 76 | it('should work with reduce, with a function argument', function(done) { 77 | var arr = [ 78 | { foo: 'bar', bar: 'yo' }, 79 | { foo: 'qux' }, 80 | { foo: 'flux' }, 81 | { foo: 100 } 82 | ]; 83 | expect([].reduce(groupBy(pluck('foo')), {})).to.deep.equal({}); 84 | expect(arr.reduce(groupBy(pluck('foo')), {})).to.deep.equal({ 85 | 'bar': [{ foo: 'bar', bar: 'yo' }], 86 | 'qux': [{ foo: 'qux' }], 87 | 'flux': [{ foo: 'flux' }], 88 | '100': [{ foo: 100 }] 89 | }); 90 | done(); 91 | }); 92 | it('should work with not-pluck functions', function(done) { 93 | expect([ 94 | { foo: 'bar', bar: 'yo' }, 95 | { foo: 'qux' }, 96 | { foo: 'flux' }, 97 | { foo: 100 } 98 | ].reduce(groupBy(function(obj){ 99 | return obj['foo'].toString() + 1; 100 | }), {})).to.deep.equal({ 101 | 'bar1': [{ foo: 'bar', bar: 'yo' }], 102 | 'qux1': [{ foo: 'qux' }], 103 | 'flux1': [{ foo: 'flux' }], 104 | '1001': [{ foo: 100 }] 105 | }); 106 | expect([ 107 | { foo: 'bar', bar: 'yo' }, 108 | { foo: 'qux', qux: 'bar' }, 109 | { foo: 'flux', goo:'foo' }, 110 | { foo: 100, 200: 'foo'} 111 | ].reduce(groupBy(function(obj){ 112 | var newKey = ''; 113 | var keys = Object.keys(obj).sort().forEach(function(el){ 114 | newKey += el; 115 | }); 116 | return newKey.toString(); 117 | }), {})).to.deep.equal({ 118 | 'barfoo': [{ foo: 'bar', bar: 'yo' }], 119 | 'fooqux': [{ foo: 'qux', qux: 'bar' }], 120 | 'foogoo': [{ foo: 'flux', goo:'foo' }], 121 | '200foo': [{ foo: 100, 200: 'foo'}] 122 | }); 123 | done(); 124 | }); 125 | }); -------------------------------------------------------------------------------- /test/test-has-keypaths.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var beforeEach = lab.beforeEach; 7 | var afterEach = lab.afterEach; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var isArray = Array.isArray; 12 | var isObject = require('../is-object'); 13 | var isFunction = require('../is-function'); 14 | 15 | var hasKeypaths = require('../has-keypaths'); 16 | 17 | describe('hasKeypaths', function () { 18 | var ctx = {}; 19 | beforeEach(function (done) { 20 | ctx.obj = { 21 | foo: 1, 22 | bar: 2, 23 | qux: 3 24 | }; 25 | done(); 26 | }); 27 | afterEach(function (done) { 28 | delete ctx.obj; 29 | done(); 30 | }); 31 | it('should return true if the object has the properties (object)', function (done) { 32 | var obj = ctx.obj; 33 | expect(hasKeypaths(obj, { foo: 1 })).to.equal(true); 34 | expect(hasKeypaths(obj, { foo: 1, bar: 2 })).to.equal(true); 35 | expect(hasKeypaths(obj, { foo: 1, bar: 2, qux: 3 })).to.equal(true); 36 | expect(hasKeypaths(obj, { bar: 2, qux: 3 })).to.equal(true); 37 | done(); 38 | }); 39 | it('should return false if the object doesn\'t have the properties (object)', function (done) { 40 | var obj = ctx.obj; 41 | expect(hasKeypaths(obj, { foo: 1, bar: 2, qux: 3, nope: 4 })).to.equal(false); 42 | expect(hasKeypaths(obj, { bar: 5 })).to.equal(false); 43 | expect(hasKeypaths(obj, { bar: 2, nope: 4 })).to.equal(false); 44 | expect(hasKeypaths()).to.equal(false); 45 | done(); 46 | }); 47 | it('should return true if the object has the properties (array)', function (done) { 48 | var obj = ctx.obj; 49 | expect(hasKeypaths(obj, ['foo'])).to.equal(true); 50 | expect(hasKeypaths(obj, ['foo', 'bar', 'qux'])).to.equal(true); 51 | done(); 52 | }); 53 | it('should return false if the object doesn\'t have the properties (array)', function (done) { 54 | var obj = ctx.obj; 55 | expect(hasKeypaths(obj, ['foo', 'bar', 'qux', 'nope'])).to.equal(false); 56 | expect(hasKeypaths(obj, ['nope'])).to.equal(false); 57 | done(); 58 | }); 59 | describe('deep equals', function() { 60 | beforeEach(function (done) { 61 | ctx.obj = { 62 | foo: { 63 | x: 1 64 | }, 65 | bar: { 66 | x: { 67 | y: 1 68 | } 69 | }, 70 | qux: 3 71 | }; 72 | Object.getPrototypeOf(ctx.obj.bar).secret = true; 73 | done(); 74 | }); 75 | afterEach(function (done) { 76 | delete Object.prototype.secret; 77 | delete ctx.obj; 78 | done(); 79 | }); 80 | it('should return true if the object has the properties (object)', function (done) { 81 | var obj = ctx.obj; 82 | expect(hasKeypaths(obj, { foo: { x: 1 } })).to.equal(true); 83 | expect(hasKeypaths(obj, { 'foo.x': 1 })).to.equal(true); 84 | expect(hasKeypaths(obj, { 'foo.x': 1 }, true)).to.equal(true); 85 | expect(hasKeypaths(obj, { 'bar.x': { y: 1 } })).to.equal(true); 86 | expect(hasKeypaths(obj, { 'bar.x': { y: 1 } }, true)).to.equal(true); 87 | done(); 88 | }); 89 | it('should return false if the object doesn\'t have the properties (object)', function (done) { 90 | var obj = ctx.obj; 91 | expect(hasKeypaths(obj, { bar: { x: 5 } })).to.equal(false); 92 | expect(hasKeypaths(obj, { 'bar.x': 5 })).to.equal(false); 93 | expect(hasKeypaths(obj, { 'bar.x': 5 }, true)).to.equal(false); 94 | expect(hasKeypaths(obj, { 'bar.x': { y: 1 } }, false)).to.equal(false); 95 | done(); 96 | }); 97 | it('should return true if the object has the properties (array)', function (done) { 98 | var obj = ctx.obj; 99 | expect(hasKeypaths(obj, ['foo.x'])).to.equal(true); 100 | expect(hasKeypaths(obj, ['foo.x', 'bar', 'qux'])).to.equal(true); 101 | expect(hasKeypaths(obj, ['foo.x', 'bar.secret', 'qux'])).to.equal(true); 102 | expect(hasKeypaths(obj, ['foo.x', 'bar.secret', 'qux'], true)).to.equal(true); 103 | done(); 104 | }); 105 | it('should return false if the object doesn\'t have the properties (array)', function (done) { 106 | var obj = ctx.obj; 107 | expect(hasKeypaths(obj, ['foo.x', 'bar', 'qux', 'foo.nope'])).to.equal(false); 108 | expect(hasKeypaths(obj, ['foo.nope'])).to.equal(false); 109 | expect(hasKeypaths(obj, ['foo.x', 'bar.secret', 'qux'], false)).to.equal(false); 110 | done(); 111 | }); 112 | }); 113 | describe('works with array functions like map', function() { 114 | beforeEach(function (done) { 115 | ctx.arr = [ 116 | { 117 | bar: 1 118 | }, 119 | { 120 | foo: 2, 121 | bar: 1, 122 | qux: 2 123 | }, 124 | { 125 | foo: 3, 126 | bar: 1, 127 | koo: 3, 128 | goo: 3 129 | }, 130 | { 131 | foo: 3, 132 | bar: 1, 133 | qux: 2 134 | } 135 | ]; 136 | done(); 137 | }); 138 | afterEach(function (done) { 139 | delete ctx.arr; 140 | done(); 141 | }); 142 | it('should return true for objects that have the properties (object)', function (done) { 143 | var arr = ctx.arr; 144 | expect(arr.map(hasKeypaths({ bar:1 }))).to.deep.equal([true, true, true, true]); 145 | expect(arr.map(hasKeypaths({ qux:2 }))).to.deep.equal([false, true, false, true]); 146 | done(); 147 | }); 148 | it('should return true for objects that have the properties (array)', function (done) { 149 | var arr = ctx.arr; 150 | expect(arr.map(hasKeypaths(['bar']))).to.deep.equal([true, true, true, true]); 151 | expect(arr.map(hasKeypaths(['bar', 'qux']))).to.deep.equal([false, true, false, true]); 152 | done(); 153 | }); 154 | }); 155 | }); 156 | -------------------------------------------------------------------------------- /test/test-has-properties.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var beforeEach = lab.beforeEach; 7 | var afterEach = lab.afterEach; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var isArray = Array.isArray; 12 | var isObject = require('../is-object'); 13 | var isFunction = require('../is-function'); 14 | var last = require('../last'); 15 | 16 | var hasProperties = require('../has-properties'); 17 | 18 | describe('hasProperties', function () { 19 | var ctx = {}; 20 | beforeEach(function (done) { 21 | ctx.obj = { 22 | foo: 1, 23 | bar: 2, 24 | qux: 3 25 | }; 26 | done(); 27 | }); 28 | afterEach(function (done) { 29 | delete ctx.obj; 30 | delete Object.prototype.qux; 31 | done(); 32 | }); 33 | it('should return true if the object has the properties (object)', function (done) { 34 | var obj = ctx.obj; 35 | expect(hasProperties(obj, { foo: 1 })).to.equal(true); 36 | expect(hasProperties(obj, { foo: 1, bar: 2 })).to.equal(true); 37 | expect(hasProperties(obj, { foo: 1, bar: 2, qux: 3 })).to.equal(true); 38 | expect(hasProperties(obj, { bar: 2, qux: 3 })).to.equal(true); 39 | done(); 40 | }); 41 | it('should return false if the object doesn\'t have the properties (object)', function (done) { 42 | var obj = ctx.obj; 43 | expect(hasProperties(obj, { foo: 1, bar: 2, qux: 3, nope: 4 })).to.equal(false); 44 | expect(hasProperties(obj, { bar: 5 })).to.equal(false); 45 | expect(hasProperties(obj, { bar: 2, nope: 4 })).to.equal(false); 46 | expect(hasProperties()).to.equal(false); 47 | done(); 48 | }); 49 | it('should return true if the object has the properties (array)', function (done) { 50 | var obj = ctx.obj; 51 | expect(hasProperties(obj, ['foo'])).to.equal(true); 52 | expect(hasProperties(obj, ['foo', 'bar', 'qux'])).to.equal(true); 53 | done(); 54 | }); 55 | it('should return false if the object doesn\'t have the properties (array)', function (done) { 56 | var obj = ctx.obj; 57 | expect(hasProperties(obj, ['foo', 'bar', 'qux', 'nope'])).to.equal(false); 58 | expect(hasProperties(obj, ['nope'])).to.equal(false); 59 | done(); 60 | }); 61 | describe('deep equals', function() { 62 | beforeEach(function (done) { 63 | ctx.obj = { 64 | foo: { 65 | x: 1 66 | }, 67 | bar: 2, 68 | qux: 3 69 | }; 70 | done(); 71 | }); 72 | afterEach(function (done) { 73 | delete ctx.obj; 74 | done(); 75 | }); 76 | it('should return true if the object has the properties (object)', function (done) { 77 | var obj = ctx.obj; 78 | expect(hasProperties(obj, { foo: { x: 1 } })).to.equal(true); 79 | expect(hasProperties(obj, { foo: { x: 1 } }, true)).to.equal(true); 80 | done(); 81 | }); 82 | it('should return false if the object doesn\'t have the properties (object)', function (done) { 83 | var obj = ctx.obj; 84 | expect(hasProperties(obj, { foo: { x: 1 } }, false)).to.equal(false); 85 | expect(hasProperties(obj, { bar: { x: 5 } })).to.equal(false); 86 | done(); 87 | }); 88 | }); 89 | describe('works with array functions like map', function() { 90 | beforeEach(function (done) { 91 | ctx.arr = [ 92 | { 93 | bar: 1 94 | }, 95 | { 96 | foo: 2, 97 | bar: 1, 98 | qux: 2 99 | }, 100 | { 101 | foo: 3, 102 | bar: 1, 103 | koo: 3, 104 | goo: 3 105 | }, 106 | { 107 | foo: 3, 108 | bar: 1, 109 | qux: 2 110 | }, 111 | { 112 | foo: { 113 | x: 1 114 | }, 115 | bar: 1 116 | } 117 | ]; 118 | done(); 119 | }); 120 | afterEach(function (done) { 121 | delete ctx.arr; 122 | done(); 123 | }); 124 | it('should return true for objects that have the properties (object)', function (done) { 125 | var arr = ctx.arr; 126 | expect(arr.map(hasProperties({ bar:1 }))).to.deep.equal([true, true, true, true, true]); 127 | expect(arr.map(hasProperties({ qux:2 }))).to.deep.equal([false, true, false, true, false]); 128 | expect(arr.map(hasProperties({ foo: { x: 1 } }))).to.deep.equal([false, false, false, false, true]); 129 | expect(arr.map(hasProperties({ foo: { x: 1 } }, true))).to.deep.equal([false, false, false, false, true]); 130 | expect(arr.map(hasProperties({ foo: { x: 1 } }, false))).to.deep.equal([false, false, false, false, false]); 131 | expect(arr.map(hasProperties({ foo: last(arr).foo }, false))).to.deep.equal([false, false, false, false, true]); 132 | done(); 133 | }); 134 | it('should return true for objects that have the properties (array)', function (done) { 135 | var arr = ctx.arr; 136 | expect(arr.map(hasProperties(['bar']))).to.deep.equal([true, true, true, true, true]); 137 | expect(arr.map(hasProperties(['bar', 'qux']))).to.deep.equal([false, true, false, true, false]); 138 | arr.forEach(function (obj) { 139 | Object.getPrototypeOf(obj).qux = 1; 140 | }); 141 | expect(arr.map(hasProperties(['bar', 'qux']))).to.deep.equal([true, true, true, true, true]); 142 | expect(arr.map(hasProperties(['bar', 'qux'], true))).to.deep.equal([true, true, true, true, true]); 143 | expect(arr.map(hasProperties(['bar', 'qux'], false))).to.deep.equal([false, true, false, true, false]); 144 | done(); 145 | }); 146 | }); 147 | }); 148 | -------------------------------------------------------------------------------- /test/test-includes.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module test/includes 3 | */ 4 | 'use strict'; 5 | 6 | var Code = require('code'); 7 | var Lab = require('lab'); 8 | var sinon = require('sinon'); 9 | 10 | var lab = exports.lab = Lab.script(); 11 | 12 | var afterEach = lab.afterEach; 13 | var beforeEach = lab.beforeEach; 14 | var describe = lab.describe; 15 | var expect = Code.expect; 16 | var it = lab.it; 17 | 18 | var includes = require('../includes'); 19 | 20 | describe('includes', function () { 21 | 22 | describe('stubbed Array.prototype.includes', function () { 23 | beforeEach(function (done) { 24 | Array.prototype.includes = sinon.stub().returns(true); 25 | done(); 26 | }); 27 | afterEach(function (done) { 28 | delete Array.prototype.includes; 29 | done(); 30 | }); 31 | it('should defer to ES7 includes if defined', function (done) { 32 | var result = includes([1, 2, 3], 2); 33 | expect(result).to.equal(true); 34 | expect(Array.prototype.includes.callCount).to.equal(1); 35 | done(); 36 | }); 37 | }); 38 | 39 | describe('without fromIndex', function () { 40 | var someObj = {}; 41 | var tests = [ 42 | // array, searchItem, expectedResult 43 | [[1, 2, 3], 'a', false], 44 | [[1, 2, 3], '', false], 45 | [[1, 2, 3], 1, true], 46 | [[1, 2, 3], 2, true], 47 | [[1, 2, 3], 3, true], 48 | [[1, 2, 3], 4, false], 49 | [[1, 2, 3], 0, false], 50 | [[1, 2, 3], -2, false], 51 | [['a', 'b', 'c'], 'b', true], 52 | [['a', 'b', 'c'], 'e', false], 53 | [['a', 'b', someObj, 'c'], someObj, true], 54 | [['a', 'b', 'c'], someObj, false], 55 | [[], 2, false], 56 | [[], '', false], 57 | [[], 0, false], 58 | [[NaN, 0, 0], NaN, true], 59 | [[NaN, 0, 0], 0, true], 60 | [[-0, 0, 0], 0, true], 61 | [[-0, 0, 0], -0, true], 62 | [[0, 0, 0], -0, true], 63 | [[0, NaN, 0, 0], NaN, true], 64 | [[0, NaN, 0, 0], 0, true], 65 | [[0, -0, 0, 0], 0, true], 66 | [[0, -0, 0, 0], -0, true], 67 | [[0, 0, 0, 0], -0, true] 68 | ]; 69 | 70 | describe('compose', function () { 71 | it('should return a function with a bound argument', function (done) { 72 | tests.forEach(function (test) { 73 | var includesFn = includes(test[0]); 74 | expect(includesFn).to.be.a.function(); 75 | expect(includesFn(test[1])).to.equal(test[2]); 76 | }); 77 | done(); 78 | }); 79 | }); 80 | 81 | describe('no compose', function () { 82 | it('should return correct bool value if element is present in array or not', function (done) { 83 | tests.forEach(function (test) { 84 | var res = includes(test[0], test[1]); 85 | expect(res).to.equal(test[2]); 86 | }); 87 | done(); 88 | }); 89 | }); 90 | 91 | }); 92 | 93 | describe('with fromIndex', function () { 94 | var someObj = {}; 95 | var tests = [ 96 | // array, searchItem, fromIndex, expectedResult 97 | [[1, 2, 3], 'a', 1, false], 98 | [[1, 2, 3], '', 1, false], 99 | [[1, 2, 3], 1, 1, false], // 1 at index 0, fromIndex 1 -- false 100 | [[1, 2, 3], 2, 0, true], 101 | [[1, 2, 3], 3, 2, true], 102 | [[1, 2, 3], 4, 0, false], 103 | [[1, 2, 3], 0, 0, false], 104 | [[1, 2, 3], -2, 0, false], 105 | [['a', 'b', 'c'], 'b', 0, true], 106 | [['a', 'b', 'c'], 'e', 0, false], 107 | [['a', 'b', someObj, 'c'], someObj, 0, true], 108 | [['a', 'b', 'c'], someObj, 0, false], 109 | [[], 2, 1000, false], 110 | [[], '', 1000, false], 111 | [[], 0, 1000, false], 112 | [[NaN, 0, 0], NaN, 0, true], 113 | [[-0, 0, 0], 0, 0, true], 114 | [[NaN, 0, 0], NaN, 0, true], 115 | [[NaN, 0, 0], 0, 0, true], 116 | [[-0, 0, 0], 0, 0, true], 117 | [[-0, 0, 0], -0, 0, true], 118 | [[0, 0, 0], -0, 0, true], 119 | [[0, NaN, 0, 0], NaN, 0, true], 120 | [[0, NaN, 0, 0], 0, 0, true], 121 | [[0, -0, 0, 0], 0, 0, true], 122 | [[0, -0, 0, 0], -0, 0, true], 123 | [[0, 0, 0, 0], -0, 0, true], 124 | [[1, 2, 3, 4, 5], 4, 10, false], 125 | [[1, 2, 3, 4, 5], 4, -10, true], // fromIndex < 0, cast to 0 126 | [[1, 2, 3, 4, 5], 4, -3, true], 127 | [[1, 2, 3, 4, 5], 4, -1, false], //-1 fromIndex, start search from array.length - 1 128 | ]; 129 | describe('compose', function () { 130 | it('should return a function with a bound argument', function (done) { 131 | tests.forEach(function (test) { 132 | var includesFn = includes(test[0]); 133 | expect(includesFn).to.be.a.function(); 134 | expect(includesFn(test[1], test[2])).to.equal(test[3]); 135 | }); 136 | done(); 137 | }); 138 | }); 139 | 140 | describe('no compose', function () { 141 | it('should return correct bool value if element is present in array or not', function (done) { 142 | tests.forEach(function (test) { 143 | var res = includes(test[0], test[1], test[2]); 144 | expect(res).to.equal(test[3]); 145 | }); 146 | done(); 147 | }); 148 | }); 149 | }); 150 | }); 151 | 152 | -------------------------------------------------------------------------------- /test/test-index-by.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var indexBy = require('../index-by'); 10 | var pluck = require('../pluck'); 11 | var pick = require('../pick'); 12 | 13 | describe('indexBy', function() { 14 | it('should return empty object when no arguments are given', function(done) { 15 | expect(indexBy).to.throw(/must be a (string|function)/); 16 | done(); 17 | }); 18 | it('should work with an array and a string argument', function (done) { 19 | var arr = [ 20 | { foo: 'bar', bar: 'yo' }, 21 | { foo: 'qux' }, 22 | { foo: 'flux' }, 23 | { foo: 100 } 24 | ]; 25 | expect(indexBy([], 'foo')).to.deep.equal({}); 26 | expect(indexBy([{foo: 'bar'}], 'foo')).to.deep.equal({ 27 | 'bar': {foo: 'bar'} 28 | }); 29 | expect(indexBy(arr, 'foo')).to.deep.equal({ 30 | 'bar': {foo: 'bar', bar: 'yo'}, 31 | 'qux': {foo: 'qux'}, 32 | 'flux': {foo: 'flux'}, 33 | '100': {foo: 100} 34 | }); 35 | done(); 36 | }); 37 | it('should work with an array and a function argument', function (done) { 38 | var arr = [ 39 | { foo: 'bar', bar: 'yo' }, 40 | { foo: 'qux' }, 41 | { foo: 'flux' }, 42 | { foo: 100 } 43 | ]; 44 | expect(indexBy([], pluck('foo'))).to.deep.equal({}); 45 | expect(indexBy([{foo: 'bar'}], pluck('foo'))).to.deep.equal({ 46 | 'bar': {foo: 'bar'} 47 | }); 48 | expect(indexBy(arr, pluck('foo'))).to.deep.equal({ 49 | 'bar': {foo: 'bar', bar: 'yo'}, 50 | 'qux': {foo: 'qux'}, 51 | 'flux': {foo: 'flux'}, 52 | '100': {foo: 100} 53 | }); 54 | done(); 55 | }); 56 | it('should work with reduce, with a string argument', function (done) { 57 | var arr = [ 58 | { foo: 'bar', bar: 'yo' }, 59 | { foo: 'qux' }, 60 | { foo: 'flux' }, 61 | { foo: 100 } 62 | ]; 63 | expect([].reduce(indexBy('foo'), {})).to.deep.equal({}); 64 | expect([{foo:'bar'}].reduce(indexBy('foo'), {})).to.deep.equal({ 65 | 'bar': {foo: 'bar'} 66 | }); 67 | expect(arr.reduce(indexBy('foo'), {})).to.deep.equal({ 68 | 'bar': {foo: 'bar', bar: 'yo'}, 69 | 'qux': {foo: 'qux'}, 70 | 'flux': {foo: 'flux'}, 71 | '100': {foo: 100} 72 | }); 73 | done(); 74 | }); 75 | it('should work with reduce, with a function argument', function(done) { 76 | var arr = [ 77 | { foo: 'bar', bar: 'yo' }, 78 | { foo: 'qux' }, 79 | { foo: 'flux' }, 80 | { foo: 100 } 81 | ]; 82 | expect([].reduce(indexBy(pluck('foo')), {})).to.deep.equal({}); 83 | expect(arr.reduce(indexBy(pluck('foo')), {})).to.deep.equal({ 84 | 'bar': { foo: 'bar', bar: 'yo' }, 85 | 'qux': { foo: 'qux' }, 86 | 'flux': { foo: 'flux' }, 87 | '100': { foo: 100 } 88 | }); 89 | done(); 90 | }); 91 | it('should work with not-pluck functions', function(done) { 92 | expect([ 93 | { foo: 'bar', bar: 'yo' }, 94 | { foo: 'qux' }, 95 | { foo: 'flux' }, 96 | { foo: 100 } 97 | ].reduce(indexBy(function(obj){ 98 | return obj['foo'].toString() + 1; 99 | }), {})).to.deep.equal({ 100 | 'bar1': { foo: 'bar', bar: 'yo' }, 101 | 'qux1': { foo: 'qux' }, 102 | 'flux1': { foo: 'flux' }, 103 | '1001': { foo: 100 } 104 | }); 105 | expect([ 106 | { foo: 'bar', bar: 'yo' }, 107 | { foo: 'qux', qux: 'bar' }, 108 | { foo: 'flux', goo:'foo' }, 109 | { foo: 100, 200: 'foo'} 110 | ].reduce(indexBy(function(obj){ 111 | var newKey = ''; 112 | var keys = Object.keys(obj).sort().forEach(function(el){ 113 | newKey += el; 114 | }); 115 | return newKey.toString(); 116 | }), {})).to.deep.equal({ 117 | 'barfoo': { foo: 'bar', bar: 'yo' }, 118 | 'fooqux': { foo: 'qux', qux: 'bar' }, 119 | 'foogoo': { foo: 'flux', goo:'foo' }, 120 | '200foo': { foo: 100, 200: 'foo'} 121 | }); 122 | done(); 123 | }); 124 | }); -------------------------------------------------------------------------------- /test/test-instance-of.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var instanceOf = require('../instance-of'); 10 | 11 | describe('instanceOf', function () { 12 | it('should return true for instances of a class when used with map', function(done) { 13 | var regexps = [/one/, /two/]; 14 | expect(regexps.map(instanceOf(RegExp))) 15 | .to.deep.equal([true, true]); 16 | done(); 17 | }); 18 | it('should return false for non-instance of a class when used with map', function(done) { 19 | var nonRegExps = ['string', function () {}, [], true, {}, null, undefined]; 20 | expect(nonRegExps.map(instanceOf(RegExp))) 21 | .to.deep.equal([false, false, false, false, false, false, false]); 22 | done(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /test/test-is-boolean.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isBoolean = require('../is-boolean'); 10 | 11 | describe('isBoolean', function () { 12 | it('should return true for booleans', function(done) { 13 | expect(isBoolean(true)).to.be.true(); 14 | done(); 15 | }); 16 | it('should return false for non-booleans', function(done) { 17 | expect(isBoolean(['foo'])).to.be.false(); 18 | expect(isBoolean('foo')).to.be.false(); 19 | expect(isBoolean(101)).to.be.false(); 20 | expect(isBoolean({})).to.be.false(); 21 | expect(isBoolean(function () {})).to.be.false(); 22 | expect(isBoolean(/re/)).to.be.false(); 23 | expect(isBoolean(null)).to.be.false(); 24 | expect(isBoolean(undefined)).to.be.false(); 25 | expect(isBoolean(new String('hey'))).to.be.false(); 26 | expect(isBoolean(new Number(101))).to.be.false(); 27 | done(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/test-is-empty.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isEmpty = require('../is-empty'); 10 | 11 | describe('isEmpty', function () { 12 | it('should return true for empty', function(done) { 13 | expect(isEmpty([])).to.be.true(); 14 | expect(isEmpty("")).to.be.true(); 15 | expect(isEmpty({})).to.be.true(); 16 | done(); 17 | }); 18 | it('should return false for non-empty', function(done) { 19 | expect(isEmpty(" ")).to.be.false(); 20 | expect(isEmpty({x : "y"})).to.be.false(); 21 | expect(isEmpty("a")).to.be.false(); 22 | expect(isEmpty(" a")).to.be.false(); 23 | expect(isEmpty([1])).to.be.false(); 24 | done(); 25 | }); 26 | it('should error when given invalid arguments', function (done) { 27 | try { 28 | isEmpty(function() {}); 29 | } 30 | catch (err) { 31 | expect(err.message).to.match(/string, array or object/); 32 | } 33 | try { 34 | isEmpty(); 35 | } 36 | catch (err) { 37 | expect(err.message).to.match(/string, array or object/); 38 | } 39 | done(); 40 | }); 41 | }); 42 | -------------------------------------------------------------------------------- /test/test-is-function.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isFunction = require('../is-function'); 10 | 11 | describe('isFunction', function () { 12 | it('should return true for functions', function(done) { 13 | expect(isFunction(function () {})).to.be.true(); 14 | done(); 15 | }); 16 | it('should return false for non-functions', function(done) { 17 | expect(isFunction(['foo'])).to.be.false(); 18 | expect(isFunction('foo')).to.be.false(); 19 | expect(isFunction(101)).to.be.false(); 20 | expect(isFunction({})).to.be.false(); 21 | expect(isFunction(/re/)).to.be.false(); 22 | expect(isFunction(true)).to.be.false(); 23 | expect(isFunction(null)).to.be.false(); 24 | expect(isFunction(undefined)).to.be.false(); 25 | expect(isFunction(new String('hey'))).to.be.false(); 26 | expect(isFunction(new Number(101))).to.be.false(); 27 | done(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/test-is-integer.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isInteger = require('../is-integer'); 10 | 11 | describe('isInteger', function () { 12 | it('should return true for integers', function(done) { 13 | expect(isInteger(0)).to.be.true(); 14 | expect(isInteger(-1)).to.be.true(); 15 | expect(isInteger(101.0)).to.be.true(); 16 | done(); 17 | }); 18 | it('should return false for non-numbers and non-ints', function(done) { 19 | expect(isInteger(1.1)).to.be.false(); 20 | expect(isInteger(2/3)).to.be.false(); 21 | expect(isInteger(NaN)).to.be.false(); 22 | expect(isInteger(false)).to.be.false(); 23 | expect(isInteger(Math.Pi)).to.be.false(); 24 | expect(isInteger(Math.Infinity)).to.be.false(); 25 | expect(isInteger([])).to.be.false(); 26 | expect(isInteger({})).to.be.false(); 27 | expect(isInteger(/regex/)).to.be.false(); 28 | done(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/test-is-number.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isNumber = require('../is-number'); 10 | 11 | describe('isNumber', function () { 12 | it('should return true for numbers', function(done) { 13 | expect(isNumber(101)).to.be.true(); 14 | expect(isNumber(new Number(101))).to.be.true(); 15 | done(); 16 | }); 17 | it('should return false for non-numbers', function(done) { 18 | expect(isNumber(true)).to.be.false(); 19 | expect(isNumber(['foo'])).to.be.false(); 20 | expect(isNumber('foo')).to.be.false(); 21 | expect(isNumber({})).to.be.false(); 22 | expect(isNumber(function () {})).to.be.false(); 23 | expect(isNumber(/re/)).to.be.false(); 24 | expect(isNumber(null)).to.be.false(); 25 | expect(isNumber(undefined)).to.be.false(); 26 | expect(isNumber(new String('hey'))).to.be.false(); 27 | expect(isNumber(NaN)).to.be.false(); 28 | done(); 29 | }); 30 | }); 31 | -------------------------------------------------------------------------------- /test/test-is-object.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isObject = require('../is-object'); 10 | 11 | describe('isObject', function () { 12 | it('should return true for objects', function(done) { 13 | expect(isObject({foo:'bar'})).to.be.true(); 14 | done(); 15 | }); 16 | it('should return false for non-objects', function(done) { 17 | expect(isObject(['foo'])).to.be.false(); 18 | expect(isObject('foo')).to.be.false(); 19 | expect(isObject(101)).to.be.false(); 20 | expect(isObject(function () {})).to.be.false(); 21 | expect(isObject(/re/)).to.be.false(); 22 | expect(isObject(null)).to.be.false(); 23 | expect(isObject(undefined)).to.be.false(); 24 | expect(isObject(new String('hey'))).to.be.false(); 25 | expect(isObject(new Number(101))).to.be.false(); 26 | done(); 27 | }); 28 | }); 29 | -------------------------------------------------------------------------------- /test/test-is-regexp.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isRegExp = require('../is-regexp'); 10 | 11 | describe('isRegExp', function () { 12 | it('should return true for instance of RegExp', function(done) { 13 | var regexp = new RegExp('.*'); 14 | expect(isRegExp(regexp)).to.be.true(); 15 | expect(isRegExp(/.*/)).to.be.true(); 16 | done(); 17 | }); 18 | 19 | it('should return false for non-regexp', function(done) { 20 | expect(isRegExp({})).to.be.false(); 21 | expect(isRegExp(['foo'])).to.be.false(); 22 | expect(isRegExp('foo')).to.be.false(); 23 | expect(isRegExp(101)).to.be.false(); 24 | expect(isRegExp(function () {})).to.be.false(); 25 | expect(isRegExp(null)).to.be.false(); 26 | expect(isRegExp(undefined)).to.be.false(); 27 | expect(isRegExp(new String('hey'))).to.be.false(); 28 | expect(isRegExp(new Number(101))).to.be.false(); 29 | done(); 30 | }); 31 | }); 32 | -------------------------------------------------------------------------------- /test/test-is-string.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isString = require('../is-string'); 10 | 11 | describe('isString', function () { 12 | it('should return true for numbers', function(done) { 13 | expect(isString('foo')).to.be.true(); 14 | expect(isString(new String('hey'))).to.be.true(); 15 | done(); 16 | }); 17 | it('should return false for non-numbers', function(done) { 18 | expect(isString(['foo'])).to.be.false(); 19 | expect(isString(function () {})).to.be.false(); 20 | expect(isString(101)).to.be.false(); 21 | expect(isString({})).to.be.false(); 22 | expect(isString(/re/)).to.be.false(); 23 | expect(isString(true)).to.be.false(); 24 | expect(isString(null)).to.be.false(); 25 | expect(isString(undefined)).to.be.false(); 26 | expect(isString(new Number(101))).to.be.false(); 27 | done(); 28 | }); 29 | }); 30 | -------------------------------------------------------------------------------- /test/test-keys-in.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var keysIn = require('../keys-in'); 10 | 11 | describe('keys-in', function() { 12 | it('should return all the keys of an object', function(done) { 13 | var object = { 14 | hello: true, 15 | world: true 16 | }; 17 | 18 | var keys = keysIn(object); 19 | 20 | expect(keys).to.have.length(2); 21 | expect(keys).to.deep.equal(['hello', 'world']); 22 | done(); 23 | }); 24 | 25 | it('should return an empty array', function(done) { 26 | var keys = keysIn(); 27 | 28 | expect(Array.isArray(keys)).to.be.true(); 29 | expect(keys.length).to.equal(0); 30 | done(); 31 | }); 32 | }); 33 | -------------------------------------------------------------------------------- /test/test-last.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var last = require('../last'); 10 | 11 | describe('last', function () { 12 | it('should return the last a val from an array, string, or object', function(done) { 13 | expect(last([1, 2, 3])).to.equal(3); 14 | expect(last('123')).to.equal('3'); 15 | expect(last(function (a) {})).to.equal('}'); 16 | expect(last(null)).to.equal(undefined); 17 | done(); 18 | }); 19 | }); 20 | -------------------------------------------------------------------------------- /test/test-lens.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lens = require('../lens'); 3 | var lab = exports.lab = Lab.script(); 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var beforeEach = lab.beforeEach; 7 | var Code = require('code'); 8 | var expect = Code.expect; 9 | 10 | describe('lens', function() { 11 | var toUpper = function(str) { return str.toUpperCase(); }; 12 | var obj, arr; 13 | 14 | beforeEach(function(done) { 15 | obj = { 16 | foo: 'foo', 17 | bar: 'bar' 18 | }; 19 | 20 | arr = ['foo', 'bar']; 21 | 22 | done(); 23 | }); 24 | 25 | it('should create a lense', function(done) { 26 | var l = lens('foo'); 27 | 28 | expect(typeof l).to.equal('function'); 29 | expect(typeof l.set).to.equal('function'); 30 | expect(typeof l.mod).to.equal('function'); 31 | done(); 32 | }); 33 | 34 | it('should create a lense for a given key', function(done) { 35 | var l = lens('foo'); 36 | 37 | expect(l(obj)).to.equal('foo'); 38 | expect(l.set('moo', obj).foo).to.equal('moo'); 39 | expect(l.mod(toUpper, obj).foo).to.equal('FOO'); 40 | done(); 41 | }); 42 | 43 | it('should create a lense with a given getter and setter', function(done) { 44 | var first = lens( 45 | function(arr) { return arr[0]; }, 46 | function(val, arr) { var clone = arr.slice(); clone[0] = val; return clone; } 47 | ); 48 | 49 | expect(first(arr)).to.equal('foo'); 50 | expect(first.set('moo', arr)[0]).to.equal('moo'); 51 | expect(first.mod(toUpper, arr)[0]).to.equal('FOO'); 52 | done(); 53 | }); 54 | 55 | it('should create a curryied set and mod', function(done) { 56 | var l = lens('foo'); 57 | 58 | expect(l(obj)).to.equal('foo'); 59 | expect(l.set('moo')(obj).foo).to.equal('moo'); 60 | expect(l.mod(toUpper)(obj).foo).to.equal('FOO'); 61 | 62 | var first = lens( 63 | function(arr) { return arr[0]; }, 64 | function(val, arr) { var clone = arr.slice(); clone[0] = val; return clone; } 65 | ); 66 | 67 | expect(first(arr)).to.equal('foo'); 68 | expect(first.set('moo')(arr)[0]).to.equal('moo'); 69 | expect(first.mod(toUpper)(arr)[0]).to.equal('FOO'); 70 | done(); 71 | }); 72 | }); 73 | -------------------------------------------------------------------------------- /test/test-noop.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var noop = require('../noop'); 10 | 11 | describe('noop', function () { 12 | it('should do nothing', function (done) { 13 | var doNothing = function () {}; 14 | expect(noop.toString()).to.equal(doNothing.toString()); 15 | expect(noop()).to.equal(undefined); 16 | done(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/test-not.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var isString = require('../is-string'); 10 | var not = require('../not'); 11 | 12 | describe('not', function() { 13 | it('should inverse a function (and work with array functions)', function (done) { 14 | expect([true, 1, 'hey'].map(not(isString))) 15 | .to.deep.equal([true, true, false]); 16 | done(); 17 | }); 18 | it('should inverse a function (and work with array functions)', function (done) { 19 | expect([true, 1, false].map(not)) 20 | .to.deep.equal([false, false, true]); 21 | done(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/test-omit.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var omit = require('../omit'); 10 | 11 | describe('omit', function () { 12 | it('should omit keys from an object', function(done) { 13 | var obj = { 14 | foo: 1, 15 | bar: 1, 16 | qux: 1 17 | }; 18 | expect(omit(obj, 'bar')).to.deep.equal({ 19 | foo: 1, 20 | qux: 1 21 | }); 22 | expect(omit(obj, ['bar'])).to.deep.equal({ 23 | foo: 1, 24 | qux: 1 25 | }); 26 | expect(omit(obj, 'foo', 'bar')).to.deep.equal({ 27 | qux: 1, 28 | }); 29 | expect(omit(obj, ['foo', 'bar'])).to.deep.equal({ 30 | qux: 1, 31 | }); 32 | expect(omit(obj, ['foo', 'bar'], 'qux')).to.deep.equal({}); 33 | expect(omit(obj, ['foo', 'bar'], ['qux'])).to.deep.equal({}); 34 | expect(omit(obj)).to.deep.equal(obj); 35 | expect(omit(obj, [])).to.deep.equal(obj); 36 | done(); 37 | }); 38 | it('should omit keys from objects in an array when used with map', function(done) { 39 | var objs = [ 40 | { 41 | bar: 1 42 | }, 43 | { 44 | foo: 2, 45 | bar: 2, 46 | qux: 2 47 | }, 48 | { 49 | foo: 3, 50 | bar: 3, 51 | koo: 3, 52 | goo: 3 53 | } 54 | ]; 55 | expect(objs.map(omit('bar'))).to.deep.equal([ 56 | {}, 57 | { 58 | foo: 2, 59 | qux: 2 60 | }, 61 | { 62 | foo: 3, 63 | koo: 3, 64 | goo: 3 65 | } 66 | ]); 67 | expect(objs.map(omit(['bar']))).to.deep.equal([ 68 | {}, 69 | { 70 | foo: 2, 71 | qux: 2 72 | }, 73 | { 74 | foo: 3, 75 | koo: 3, 76 | goo: 3 77 | } 78 | ]); 79 | expect(objs.map(omit('foo', 'bar'))).to.deep.equal([ 80 | {}, 81 | { 82 | qux: 2 83 | }, 84 | { 85 | koo: 3, 86 | goo: 3 87 | } 88 | ]); 89 | expect(objs.map(omit(['foo', 'bar']))).to.deep.equal([ 90 | {}, 91 | { 92 | qux: 2 93 | }, 94 | { 95 | koo: 3, 96 | goo: 3 97 | } 98 | ]); 99 | expect(objs.map(omit(['foo', 'bar'], 'qux'))).to.deep.equal([ 100 | {}, 101 | {}, 102 | { 103 | koo: 3, 104 | goo: 3 105 | } 106 | ]); 107 | expect(objs.map(omit(['foo', 'bar'], ['qux']))).to.deep.equal([ 108 | {}, 109 | {}, 110 | { 111 | koo: 3, 112 | goo: 3 113 | } 114 | ]); 115 | var objs2 = [ 116 | { 117 | bar: 1 118 | }, 119 | { 120 | foo: { bar: 2 }, 121 | bar: 2, 122 | qux: 2 123 | }, 124 | { 125 | foo: { bar: 3 }, 126 | bar: 3, 127 | koo: 3, 128 | goo: 3 129 | } 130 | ]; 131 | expect(objs2.map(omit(['foo.bar', 'bar'], ['qux']))).to.deep.equal([ 132 | {}, 133 | { foo: {} }, 134 | { 135 | foo: {}, 136 | koo: 3, 137 | goo: 3 138 | } 139 | ]); 140 | expect(objs.map(omit())).to.deep.equal(objs); 141 | expect(objs.map(omit([]))).to.deep.equal(objs); 142 | done(); 143 | }); 144 | }); 145 | -------------------------------------------------------------------------------- /test/test-or.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var or = require('../or'); 10 | 11 | describe('or', function() { 12 | it('should work with reduce', function (done) { 13 | expect([true, true, true].reduce(or)).to.equal(true); 14 | expect([true, false, false].reduce(or)).to.equal(true); 15 | expect([false, false, false].reduce(or)).to.equal(false); 16 | done(); 17 | }); 18 | }); 19 | -------------------------------------------------------------------------------- /test/test-pass-all.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var before = lab.before; 6 | var after = lab.after; 7 | var it = lab.it; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var isString = require('../is-string'); 12 | 13 | var passAll = require('../pass-all'); 14 | 15 | describe('passAll', function () { 16 | before(function (done) { 17 | this.arr = [true, 'foo', 'bar', 'qux', '']; 18 | this.ctx = { foo: 1 }; 19 | done(); 20 | }); 21 | after(function (done) { 22 | delete this.arr; 23 | delete this.ctx; 24 | done(); 25 | }); 26 | it('should work with array functions', function(done) { 27 | expect(this.arr.filter(passAll(isString, Boolean))) 28 | .to.deep.equal(this.arr.filter(isStringAndTruthy)); 29 | done(); 30 | }); 31 | it('should apply its context to the functions', function(done) { 32 | var self = this; 33 | this.arr.forEach(passAll(checkContext).bind(this.ctx)); 34 | done(); 35 | function checkContext () { 36 | return expect(this).to.deep.equal(self.ctx); 37 | } 38 | }); 39 | it('should throw an error if it receives non-function args', function(done) { 40 | try { 41 | this.arr.forEach(passAll(true, false)); 42 | } 43 | catch (err) { 44 | expect(err.message).to.equal('all funcs should be functions'); 45 | } 46 | done(); 47 | }); 48 | }); 49 | 50 | function isStringAndTruthy (item) { 51 | return isString(item) && Boolean(item); 52 | } 53 | -------------------------------------------------------------------------------- /test/test-pass-any.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var before = lab.before; 6 | var after = lab.after; 7 | var it = lab.it; 8 | var Code = require('code'); 9 | var expect = Code.expect; 10 | 11 | var isString = require('../is-string'); 12 | var isFunction = require('../is-function'); 13 | 14 | var passAny = require('../pass-any'); 15 | 16 | describe('passAny', function () { 17 | var ctx = {}; 18 | before(function (done) { 19 | ctx.arr = [true, 'foo', 'bar', 'qux']; 20 | ctx.ctx = { foo: 1 }; 21 | done(); 22 | }); 23 | after(function (done) { 24 | delete ctx.arr; 25 | delete ctx.ctx; 26 | done(); 27 | }); 28 | it('should work with array functions', function(done) { 29 | expect(ctx.arr.filter(passAny(isString, isFunction))) 30 | .to.deep.equal(ctx.arr.filter(isStringOrFunction)); 31 | done(); 32 | }); 33 | it('should apply its context to the functions', function(done) { 34 | ctx.arr.forEach(passAny(checkContext).bind(ctx.ctx)); 35 | done(); 36 | function checkContext () { 37 | return expect(this).to.deep.equal(ctx.ctx); 38 | } 39 | }); 40 | it('should throw an error if it receives non-function args', function(done) { 41 | try { 42 | ctx.arr.forEach(passAny(true, false)); 43 | } 44 | catch (err) { 45 | expect(err.message).to.equal('all funcs should be functions'); 46 | } 47 | done(); 48 | }); 49 | }); 50 | 51 | function isStringOrFunction (item) { 52 | return isString(item) || isFunction(item); 53 | } 54 | -------------------------------------------------------------------------------- /test/test-pick.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var pick = require('../pick'); 10 | 11 | var Animal = function (obj) { 12 | var self = this 13 | Object.keys(obj).forEach(function (key) { 14 | var val = obj[key] 15 | self[key] = val 16 | }) 17 | } 18 | 19 | describe('pick', function () { 20 | it('should pick keys from an object', function(done) { 21 | var obj = { 22 | foo: 1, 23 | bar: 1, 24 | qux: 1 25 | }; 26 | expect(pick(obj, 'bar')).to.deep.equal({ 27 | bar: 1 28 | }); 29 | expect(pick(obj, ['bar'])).to.deep.equal({ 30 | bar: 1 31 | }); 32 | expect(pick(obj, 'foo', 'bar')).to.deep.equal({ 33 | foo: 1, 34 | bar: 1 35 | }); 36 | expect(pick(obj, ['foo', 'bar'])).to.deep.equal({ 37 | foo: 1, 38 | bar: 1 39 | }); 40 | expect(pick(obj, ['foo', 'bar'], 'qux')).to.deep.equal({ 41 | foo: 1, 42 | bar: 1, 43 | qux: 1 44 | }); 45 | expect(pick(obj, ['foo', 'bar'], ['qux'])).to.deep.equal({ 46 | foo: 1, 47 | bar: 1, 48 | qux: 1 49 | }); 50 | expect(pick(obj)).to.deep.equal({}); 51 | expect(pick(obj, [])).to.deep.equal({}); 52 | expect(pick(obj, RegExp('a'))).to.deep.equal({ 53 | bar: 1 54 | }); 55 | expect(pick(obj, RegExp('a'), 'foo')).to.deep.equal({ 56 | foo: 1, 57 | bar: 1 58 | }); 59 | expect(pick(obj, [RegExp('q|b')], 'bar')).to.deep.equal({ 60 | bar: 1, 61 | qux: 1 62 | }); 63 | expect(pick(obj, [RegExp('q'), RegExp('f')], ['bar'])).to.deep.equal({ 64 | foo: 1, 65 | bar: 1, 66 | qux: 1 67 | }); 68 | expect(pick(obj, [RegExp('q'), 'foo'], 'bar')).to.deep.equal({ 69 | foo: 1, 70 | bar: 1, 71 | qux: 1 72 | }); 73 | expect(pick(obj, [RegExp('x$'), 'foo'], [RegExp('b')])).to.deep.equal({ 74 | foo: 1, 75 | bar: 1, 76 | qux: 1 77 | }); 78 | done(); 79 | }); 80 | it('should pick keys from objects when using keypaths', function(done) { 81 | var obj = { 82 | koo: 1, 83 | qux: 1, 84 | fiz: { 85 | buz: 1 86 | }, 87 | 'fiz.buz': 2 88 | }; 89 | expect(pick(obj, 'fiz')).to.deep.equal({ fiz: { buz: 1 } }); 90 | expect(pick(obj, 'fiz.buz')).to.deep.equal({ fiz: { buz: 1 } }); 91 | expect(pick(obj, '["fiz.buz"]')).to.deep.equal({ 'fiz.buz': 2 }); 92 | expect(pick(obj, 'fiz.nop')).to.deep.equal({}); 93 | done(); 94 | }); 95 | it('should pick keys/keypaths from objects using RegExp', function (done) { 96 | var objs = [ 97 | { 98 | bar: 1 99 | }, 100 | { 101 | foo: 2, 102 | bar: 2, 103 | qux: 2 104 | }, 105 | { 106 | foo: 3, 107 | bar: 3, 108 | koo: 3, 109 | goo: 3 110 | }, 111 | { 112 | deep: { 113 | keypath: 1 114 | } 115 | } 116 | ]; 117 | expect(objs.map(pick(RegExp('q|g')))).to.deep.equal([ 118 | {}, 119 | { 120 | qux: 2 121 | }, 122 | { 123 | goo: 3 124 | }, 125 | { } 126 | ]); 127 | expect(objs.map(pick(RegExp('BAR', 'i'), 'foo'))).to.deep.equal([ 128 | { 129 | bar: 1 130 | }, 131 | { 132 | foo: 2, 133 | bar: 2 134 | }, 135 | { 136 | foo: 3, 137 | bar: 3 138 | }, 139 | { } 140 | ]); 141 | expect(objs.map(pick([RegExp('b')], 'foo'))).to.deep.equal([ 142 | { 143 | bar: 1 144 | }, 145 | { 146 | foo: 2, 147 | bar: 2 148 | }, 149 | { 150 | foo: 3, 151 | bar: 3 152 | }, 153 | { } 154 | ]); 155 | expect(objs.map(pick([RegExp('b'), 'qux'], ['foo']))).to.deep.equal([ 156 | { 157 | bar: 1 158 | }, 159 | { 160 | bar: 2, 161 | foo: 2, 162 | qux: 2 163 | }, 164 | { 165 | foo: 3, 166 | bar: 3 167 | }, 168 | { } 169 | ]); 170 | expect(objs.map(pick([RegExp('b'), RegExp('^f')], [RegExp('oo$')]))).to.deep.equal([ 171 | { 172 | bar: 1 173 | }, 174 | { 175 | bar: 2, 176 | foo: 2 177 | }, 178 | { 179 | bar: 3, 180 | foo: 3, 181 | koo: 3, 182 | goo: 3 183 | }, 184 | { } 185 | ]); 186 | expect(objs.map(pick([RegExp('^d')]))).to.deep.equal([ 187 | { }, 188 | { }, 189 | { }, 190 | { 191 | deep: { 192 | keypath: 1 193 | } 194 | }, 195 | ]); 196 | done(); 197 | }); 198 | it('should pick keys from objects in an array when used with map', function(done) { 199 | var objs = [ 200 | { 201 | bar: 1 202 | }, 203 | { 204 | foo: 2, 205 | bar: 2, 206 | qux: 2 207 | }, 208 | { 209 | foo: 3, 210 | bar: 3, 211 | koo: 3, 212 | goo: 3 213 | }, { 214 | yolo: undefined, 215 | yoloyolo: false 216 | } 217 | ]; 218 | expect(objs.map(pick('bar'))).to.deep.equal([ 219 | { 220 | bar: 1 221 | }, 222 | { 223 | bar: 2 224 | }, 225 | { 226 | bar: 3 227 | }, 228 | {} 229 | ]); 230 | expect(objs.map(pick(['bar']))).to.deep.equal([ 231 | { 232 | bar: 1 233 | }, 234 | { 235 | bar: 2 236 | }, 237 | { 238 | bar: 3 239 | }, 240 | {} 241 | ]); 242 | expect(objs.map(pick('foo', 'bar'))).to.deep.equal([ 243 | { 244 | bar: 1 245 | }, 246 | { 247 | foo: 2, 248 | bar: 2 249 | }, 250 | { 251 | foo: 3, 252 | bar: 3 253 | }, 254 | {} 255 | ]); 256 | expect(objs.map(pick(['foo', 'bar']))).to.deep.equal([ 257 | { 258 | bar: 1 259 | }, 260 | { 261 | foo: 2, 262 | bar: 2 263 | }, 264 | { 265 | foo: 3, 266 | bar: 3 267 | }, 268 | {} 269 | ]); 270 | expect(objs.map(pick(['foo', 'bar'], 'qux'))).to.deep.equal([ 271 | { 272 | bar: 1 273 | }, 274 | { 275 | foo: 2, 276 | bar: 2, 277 | qux: 2 278 | }, 279 | { 280 | foo: 3, 281 | bar: 3 282 | }, 283 | {} 284 | ]); 285 | expect(objs.map(pick(['foo', 'bar'], ['qux']))).to.deep.equal([ 286 | { 287 | bar: 1 288 | }, 289 | { 290 | foo: 2, 291 | bar: 2, 292 | qux: 2 293 | }, 294 | { 295 | foo: 3, 296 | bar: 3 297 | }, 298 | {} 299 | ]); 300 | expect(objs.map(pick(['foo', 'bar', 'qux', 'yolo', 'yoloyolo']))).to.deep.equal([ 301 | { 302 | bar: 1 303 | }, 304 | { 305 | foo: 2, 306 | bar: 2, 307 | qux: 2 308 | }, 309 | { 310 | foo: 3, 311 | bar: 3 312 | }, { 313 | yolo: undefined, 314 | yoloyolo: false 315 | } 316 | ]); 317 | expect(objs.map(pick())).to.deep.equal([ 318 | {}, {}, {}, {} 319 | ]); 320 | expect(objs.map(pick([]))).to.deep.equal([ 321 | {}, {}, {}, {} 322 | ]); 323 | objs = [ 324 | new Animal({ bar: 1 }) 325 | ] 326 | expect(objs.map(pick('bar'))).to.deep.equal([ 327 | { bar: 1 } 328 | ]); 329 | done(); 330 | }); 331 | }); 332 | -------------------------------------------------------------------------------- /test/test-pluck.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var pluck = require('../pluck'); 10 | 11 | describe('pluck', function () { 12 | it('should pluck a key from an object', function(done) { 13 | var obj = { 14 | foo: 1, 15 | bar: 1, 16 | qux: 1 17 | }; 18 | expect(pluck(obj, 'bar')).to.equal(1); 19 | expect(pluck(obj, ['bar'])).to.equal(1); 20 | expect(pluck(obj)).to.equal(undefined); 21 | expect(pluck(obj, [])).to.equal(undefined); 22 | done(); 23 | }); 24 | it('should pluck keys from objects in an array when used with map', function(done) { 25 | var objs = [ 26 | { 27 | bar: 1 28 | }, 29 | { 30 | foo: 2, 31 | bar: 2, 32 | qux: 2 33 | }, 34 | { 35 | foo: 3, 36 | bar: 3, 37 | koo: 3, 38 | goo: 3 39 | } 40 | ]; 41 | expect(objs.map(pluck('bar'))).to.deep.equal([ 42 | 1, 43 | 2, 44 | 3 45 | ]); 46 | expect(objs.map(pluck(['bar']))).to.deep.equal([ 47 | 1, 48 | 2, 49 | 3 50 | ]); 51 | expect(objs.map(pluck())).to.deep.equal([ 52 | undefined, undefined, undefined 53 | ]); 54 | expect(objs.map(pluck([]))).to.deep.equal([ 55 | undefined, undefined, undefined 56 | ]); 57 | done(); 58 | }); 59 | describe('isKeypath', function() { 60 | var objs = [{ 61 | foo: { 62 | bar: 1 63 | }, 64 | 'foo.bar': 2 65 | }]; 66 | var obj = objs[0]; 67 | describe('true and default', function (done) { 68 | it('should pluck a keypath from an object', function (done) { 69 | expect(pluck(obj, 'foo.bar')).to.equal(1); 70 | expect(pluck(obj, 'foo.bar', true)).to.equal(1); 71 | done(); 72 | }); 73 | it('should pluck keypaths from objects in an array when used with map', function (done) { 74 | expect(objs.map(pluck('foo.bar'))).to.deep.equal([1]); 75 | expect(objs.map(pluck('foo.bar', true))).to.deep.equal([1]); 76 | done(); 77 | }); 78 | }); 79 | describe('false', function (done) { 80 | it('should pluck a key from an object', function (done) { 81 | expect(pluck(obj, 'foo.bar', false)).to.equal(2); 82 | done(); 83 | }); 84 | it('should pluck keys from objects in an array when used with map', function (done) { 85 | expect(objs.map(pluck('foo.bar', false))).to.deep.equal([2]); 86 | done(); 87 | }); 88 | }); 89 | }); 90 | }); 91 | -------------------------------------------------------------------------------- /test/test-put.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var clone = require('../clone'); 10 | var put = require('../put'); 11 | var set = require('../set'); 12 | 13 | describe('put', function () { 14 | it('should put a value at a key on a new object', function(done) { 15 | var obj = { 16 | foo: 1, 17 | bar: 1, 18 | qux: 1 19 | }; 20 | 21 | var key = 'bar'; 22 | var val = 100; 23 | 24 | var original = clone(obj); 25 | 26 | var expected = clone(obj); 27 | expected[key] = val; 28 | 29 | expect(put(obj, key, val)).to.deep.equal(expected); 30 | expect(obj).to.deep.equal(original); // original not modified 31 | done(); 32 | }); 33 | 34 | it('should put a value at a key when used with array functions', function(done) { 35 | var objs = [ 36 | { 37 | bar: 1 38 | }, 39 | { 40 | foo: 2, 41 | bar: 2, 42 | qux: 2 43 | }, 44 | { 45 | foo: 3, 46 | bar: 3, 47 | koo: 3, 48 | goo: 3 49 | } 50 | ]; 51 | 52 | var key = 'bar'; 53 | var val = 100; 54 | 55 | var originals = clone(objs); 56 | 57 | var expected = objs.map(function (obj) { 58 | var out = clone(obj); 59 | out[key] = val; 60 | return out; 61 | }); 62 | expect(objs.map(put(key, val))).to.deep.equal(expected); 63 | expect(objs).to.deep.equal(originals); // original not modified 64 | done(); 65 | }); 66 | 67 | it('should put a key-value set on a new object', function(done) { 68 | var obj = { 69 | foo: 1, 70 | bar: 1, 71 | qux: 1 72 | }; 73 | 74 | var key = 'bar'; 75 | var val = 100; 76 | var putObj = set({}, key, val); 77 | 78 | var original = clone(obj); 79 | 80 | var expected = clone(obj); 81 | expected[key] = val; 82 | 83 | expect(put(obj, putObj)).to.deep.equal(expected); 84 | expect(obj).to.deep.equal(original); // original not modified 85 | done(); 86 | }); 87 | 88 | it('should put a key-value set when used with array functions', function(done) { 89 | var objs = [ 90 | { 91 | bar: 1 92 | }, 93 | { 94 | foo: 2, 95 | bar: 2, 96 | qux: 2 97 | }, 98 | { 99 | foo: 3, 100 | bar: 3, 101 | koo: 3, 102 | goo: 3 103 | } 104 | ]; 105 | 106 | var key = 'bar'; 107 | var val = 100; 108 | var putObj = set({}, key, val); 109 | 110 | var originals = clone(objs); 111 | 112 | var expected = objs.map(function (obj) { 113 | var out = clone(obj); 114 | out[key] = val; 115 | return out; 116 | }); 117 | expect(objs.map(put(putObj))).to.deep.equal(expected); 118 | expect(objs).to.deep.equal(originals); // original not modified 119 | done(); 120 | }); 121 | 122 | describe('keypaths', function () { 123 | it('should put via keypath object', function (done) { 124 | console.log('hello') 125 | var obj = { 126 | foo: { 127 | bar: 1 128 | } 129 | } 130 | var expected = { 131 | foo: { 132 | bar: 1, 133 | qux: 1 134 | }, 135 | yolo: { 136 | dolo: 1 137 | } 138 | } 139 | var out = put(obj, { 'foo.qux': 1, 'yolo.dolo': 1 }) 140 | expect(out).to.deep.equal(expected) 141 | done(); 142 | }); 143 | 144 | it('should put via keypath and val', function (done) { 145 | var obj = { 146 | foo: { 147 | bar: 1 148 | } 149 | } 150 | var expected = { 151 | foo: { 152 | bar: 1, 153 | qux: 1 154 | } 155 | } 156 | var out = put(obj, 'foo.qux', 1) 157 | expect(out).to.deep.equal(expected) 158 | done(); 159 | }); 160 | }); 161 | 162 | it("shouldn't change the type of the object", function(done) { 163 | var obj = new Date(); 164 | 165 | var key = 'bar'; 166 | var val = 100; 167 | 168 | var expected = clone(obj); 169 | expected[key] = val; 170 | 171 | var result = put(obj, key, val); 172 | expect(result).to.deep.equal(expected); 173 | expect(result instanceof Date).to.equal(true); 174 | done(); 175 | }); 176 | 177 | describe('errors', function() { 178 | it('should error when given two args other than (key, value) or (obj, putObj)', function (done) { 179 | try { put(/whatever/, /whatever/); } 180 | catch (err) { expect(err).to.exist(); } 181 | done(); 182 | }); 183 | 184 | it('should error when given no args', function (done) { 185 | try { put(); } 186 | catch (err) { expect(err).to.exist(); } 187 | done(); 188 | }); 189 | 190 | it('should error when one arg other than putObj', function (done) { 191 | try { put("anything"); } 192 | catch (err) { expect(err).to.exist(); } 193 | done(); 194 | }); 195 | }); 196 | }); 197 | -------------------------------------------------------------------------------- /test/test-set.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var clone = require('clone'); 10 | var set = require('../set'); 11 | var pluck = require('../pluck'); 12 | 13 | describe('set', function () { 14 | it('should set a key with value on a object', function(done) { 15 | var obj = { 16 | foo: 1, 17 | bar: 1, 18 | qux: 1 19 | }; 20 | 21 | var key = 'bar'; 22 | var val = 100; 23 | 24 | var expected = clone(obj); 25 | expected[key] = val; 26 | 27 | expect(set(obj, key, val)).to.deep.equal(expected); 28 | expect(obj[key]).to.equal(100); // original obj modified 29 | done(); 30 | }); 31 | it('should set a key with a val when used with array functions', function(done) { 32 | var objs = [ 33 | { 34 | bar: 1 35 | }, 36 | { 37 | foo: 2, 38 | bar: 2, 39 | }, 40 | { 41 | foo: 3, 42 | bar: 3, 43 | koo: 3, 44 | goo: 3 45 | } 46 | ]; 47 | var key = 'bar'; 48 | var val = 100; 49 | var expected = objs.map(function (obj) { 50 | var out = clone(obj); 51 | out[key] = val; 52 | return out; 53 | }); 54 | expect(objs.map(set(key, val))).to.deep.equal(expected); 55 | expect(objs.map(pluck(key))).to.deep.equal([100, 100, 100]); // original obj modified 56 | done(); 57 | }); 58 | it('should set a set of keys and vals when given an object', function (done) { 59 | var obj = { 60 | foo: 1, 61 | bar: 1, 62 | qux: 1 63 | }; 64 | 65 | var key = 'bar'; 66 | var val = 100; 67 | var setObj = {}; 68 | setObj[key] = val; 69 | 70 | var expected = clone(obj); 71 | expected[key] = val; 72 | 73 | expect(set(obj, setObj)).to.deep.equal(expected); 74 | expect(obj[key]).to.equal(100); // original obj modified 75 | done(); 76 | }); 77 | it('should set the right value when given an object and a keypath', function (done) { 78 | var obj = { 79 | foo: 1, 80 | qux: 1 81 | }; 82 | 83 | var expected = { 84 | foo: 1, 85 | bar: { 86 | baz: 100 87 | }, 88 | qux: 1 89 | }; 90 | 91 | expect(set(obj, 'bar.baz', 100)).to.deep.equal(expected); 92 | expect(obj).to.deep.equal(expected); 93 | done(); 94 | }); 95 | it('should set the right value when given an object and a keypath object', function (done) { 96 | var obj = { 97 | foo: 1, 98 | qux: 1 99 | }; 100 | 101 | var keypathObj = { 102 | 'bar.baz' : 100, 103 | yolo: 1 104 | }; 105 | 106 | var expected = { 107 | foo: 1, 108 | bar: { 109 | baz: 100 110 | }, 111 | qux: 1, 112 | yolo: 1 113 | }; 114 | expect(set(obj, keypathObj)).to.deep.equal(expected); 115 | expect(obj).to.deep.equal(expected); 116 | done(); 117 | }); 118 | it('should set a set of keys and vals when given an object when used with array functions', function (done) { 119 | var objs = [ 120 | { 121 | bar: 1 122 | }, 123 | { 124 | foo: 2, 125 | bar: 2, 126 | qux: 2 127 | }, 128 | { 129 | foo: 3, 130 | bar: 3, 131 | koo: 3, 132 | goo: 3 133 | } 134 | ]; 135 | var key = 'bar'; 136 | var val = 100; 137 | var setObj = {}; 138 | setObj[key] = val; 139 | var expected = objs.map(function (obj) { 140 | var copy = clone(obj); 141 | copy[key] = val; 142 | return copy; 143 | }); 144 | expect(objs.map(set(setObj))).to.deep.equal(expected); 145 | expect(objs.map(pluck(key))).to.deep.equal([100, 100, 100]); // original obj modified 146 | done(); 147 | }); 148 | describe('deep', function () { 149 | it('should set a deep keypath', function (done) { 150 | const obj = { 151 | // foo: 1, 152 | bar: 2 153 | } 154 | const out = set(obj, 'foo.qux', 100); 155 | expect(out).to.deep.equal({ foo: { qux: 100 }, bar: 2 }); 156 | done(); 157 | }) 158 | }) 159 | describe('errors', function() { 160 | it('should error when given two args that artent str, val or obj, obj', function (done) { 161 | try { 162 | set(/what/, /what/); 163 | } 164 | catch (err) { 165 | expect(err).to.exist(); 166 | done(); 167 | } 168 | }); 169 | }); 170 | }); 171 | -------------------------------------------------------------------------------- /test/test-values.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var values = require('../values'); 10 | 11 | describe('values', function () { 12 | it('should return all of the values for all '+ 13 | 'of the properties in a given object as '+ 14 | 'an Array', function (done) { 15 | expect(values({foo:'1', bar:'a'})).to.deep.equal(['1', 'a']); 16 | done(); 17 | }); 18 | 19 | it('should handle object with no keys', function (done) { 20 | expect(values({})).to.deep.equal([]); 21 | done(); 22 | }); 23 | }); 24 | -------------------------------------------------------------------------------- /test/test-xor.js: -------------------------------------------------------------------------------- 1 | var Lab = require('lab'); 2 | var lab = exports.lab = Lab.script(); 3 | 4 | var describe = lab.describe; 5 | var it = lab.it; 6 | var Code = require('code'); 7 | var expect = Code.expect; 8 | 9 | var xor = require('../xor'); 10 | 11 | describe('xor', function() { 12 | it('should work with reduce', function (done) { 13 | expect([true, true, true].reduce(xor, true)).to.equal(false); 14 | expect([false, false, false].reduce(xor, false)).to.equal(false); 15 | expect([false, false, false].reduce(xor, true)).to.equal(true); 16 | expect([true, false, false].reduce(xor)).to.equal(true); 17 | expect([false, true, false].reduce(xor)).to.equal(true); 18 | expect([false, false, true].reduce(xor)).to.equal(true); 19 | expect([false, true, true].reduce(xor)).to.equal(false); 20 | expect([true, false, true].reduce(xor)).to.equal(false); 21 | expect([true, true, false].reduce(xor)).to.equal(false); 22 | done(); 23 | }); 24 | }); 25 | -------------------------------------------------------------------------------- /values.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Retrieve the values of an object's properties 3 | * @module 101/values 4 | */ 5 | 'use strict'; 6 | 7 | module.exports = values; 8 | 9 | /** 10 | * Borrowing from underscorejs 11 | * https://github.com/jashkenas/underscore 12 | * @param {Object} obj 13 | * @return {Array} 14 | */ 15 | function values (obj) { 16 | var keys = Object.keys(obj); 17 | var length = keys.length; 18 | var vals = new Array(length); 19 | for (var i = 0; i < length; i++) { 20 | vals[i] = obj[keys[i]]; 21 | } 22 | return vals; 23 | } 24 | -------------------------------------------------------------------------------- /xor.js: -------------------------------------------------------------------------------- 1 | /** 2 | * @module 101/xor 3 | */ 4 | 5 | /** 6 | * Exclusive or 7 | * @function module:101/xor 8 | * @param {*} a - any value 9 | * @param {*} b - any value 10 | * @return {boolean} a xor b 11 | */ 12 | 13 | module.exports = xor; 14 | 15 | function xor (a, b) { 16 | return !(!a && !b) && !(a && b); 17 | } 18 | --------------------------------------------------------------------------------