UNPKG

cappedarray

Version:

A real array that automatically removes items to maintain the capped length

291 lines (200 loc) 8.03 kB
cappedarray =========== ## Basic usage ```js var cappedArray = require('cappedarray') // Create array with a length cap of 3 var log = cappedArray(3) // [] // log.lengthCap === 3 // Add some items log.push(1) // [1] log.push(2) // [1, 2] log.push(3) // [1, 2, 3] // Add more items than the length cap log.push(4) // [2, 3, 4] - Too many items, The 1 is pushed off the front log.push(5) // [3, 4, 5] log.unshift(6) // [6, 3, 4] - The 5 is unshifted off the back // Add a lot more than the cap length for (var i = 0; i < 50; i++) { log.push(i) } // Still 3 items console.log(log.length) > 3 console.log(log) > [47, 48, 49] ``` ## Installation ```bash $ npm install cappedarray ``` ## How it works The capped array is just a normal array with the `push` and `unshift` functions overridden and an extra `lengthCap` property. The functions and lengthCap are set to enumerable `false` so they do not show up in forEach loops, Object.keys, etc... ```js var recentItems = cappedArray(5) recentItems.push('foo') recentItems.push('bar') var util = require('util') util.isArray(recentItems) // true Array.isArray(recentItems) // true Object.keys(recentItems) // ['0', '1'] JSON.stringify(recentItems) // '["foo","bar"]' ``` ## Further Examples #### Multiple arguments ```js // Create array with a length cap of 5 var log = cappedArray(5) // [] // Multiple arguments to push and unshift work as expected. log.unshift('a', 'b', 'c', 'd', 'e', 'f') // ['a', 'b', 'c', 'd', 'e'] - Too long, 'f' has already popped off the end. // If this was a 'push' the 'f' would have stayed and the 'a' would have gone. log.unshift('h') // ['h', 'a', 'b', 'c', 'd'] log.unshift.apply(log, ['i', 'j', 'k']) // ['i', 'j', 'k', 'h', 'a'] log.push('l', 'm') // ['k', 'h', 'a', 'l', 'm'] ``` #### The length cap can be changed on the fly. ```js // Create array with a length cap of 5 var recentItems = cappedArray(5) recentItems.push(1, 2, 3, 4, 5, 6, 7) // [3, 4, 5, 6, 7] // Need to keep more recent items recentItems.lengthCap = 8 // [3, 4, 5, 6, 7] Still only 5 items recentItems.push(8, 9, 10, 11) // [4, 5, 6, 7, 8, 9, 10, 11] ``` When changing the length cap to a lower value than the existing item count, the extra items will **not** be automatically removed. It is unknown whether the first or last items should be removed until `push` or `unshift` is called afterward. ```js // I've changed my mind. There's too many items now, lower the cap. recentItems.lengthCap = 6 // [4, 5, 6, 7, 8, 9, 10, 11] // More items than the lengthCap? console.log(recentItems.length) > 8 console.log(recentItems.lengthCap) > 6 ``` Passing no arguments to either `push` or `unshift` will reduce the array to the capped length. ```js // I want to keep the end of the array. recentItems.push() // [6, 7, 8, 9, 10, 11] // That has sorted it! console.log(recentItems.length) > 6 console.log(recentItems.lengthCap) > 6 ``` ## Capping existing Arrays ```js var cap = require('cappedarray').cap var messages = [{msg: 'First!'}, {msg: 'Second'}, {msg: 'Third'}] // Cap the array to 5 items cap(messages, 5) messages.push({msg: 'Forth'}, {msg: 'Fith'}, {msg: 'Sixth'}) console.log(log) > [ { msg: 'Second' }, { msg: 'Third' }, { msg: 'Forth' }, { msg: 'Fith' }, { msg: 'Sixth' } ] ``` If the second argument is missing the cap is set to the length of the array or the lengthCap property if it exists. ```js var numerosEnFrancais = cap(['un', 'deux', 'trois']) // Both the cap and length are the same console.log(numerosEnFrancais.length + ' === ' numerosEnFrancais.lengthCap) > 3 === 3 // This can be used to loop through an array repeatedly numerosEnFrancais.push(numerosEnFrancais[0]) // ['deux', 'trois', 'un'] numerosEnFrancais.push(numerosEnFrancais[0]) // ['trois', 'un', 'deux'] numerosEnFrancais.push(numerosEnFrancais[0]) // ['un', 'deux', 'trois'] var top5 = ['High Fidelity'] // This... top5.lengthCap = 5 cap(top5) // Uses the existing lengthCap property for the length cap // ...is the same as cap(top5, 5) ``` Like changing the lengthCap above, capping an existing array with more items than the length cap will **not** automatically remove the extra items. Use `push` or `unshift` with no arguments to reduce the array to the capped length. ```js var alphabet = ['a', 'b', 'c', 'd', etc..., 'x', 'y', 'z'] console.log(alphabet.length) > 26 // Cap it to 13 items... cap(alphabet, 13) // ...but it still has 26 items. console.log(alphabet.length) > 26 console.log(alphabet.lengthCap) > 13 // removes extra items from the front. cap.push() console.log(alphabet.length) > 13 console.log(alphabet) > ['n', 'o', 'p', 'q', 'r', 's', etc..., 'x', 'y', 'z'] // Lets try that again with unshift var alphabet = ['a', 'b', 'c', 'd', etc..., 'x', 'y', 'z'] // cap returns the array so we can do this. Unshift removes extra items from the back. cap(alphabet, 13).unshift() console.log(alphabet.length) > 13 console.log(alphabet) > ['a', 'b', 'c', 'd', 'e', 'f', etc..., 'k', 'l', 'm'] ``` ## Uncap Use uncap to turn the array back to normal. ```js var cap = require('cappedarray').cap var uncap = require('cappedarray').uncap var cycleNumbers = cap([1, 2, 3, 4, 5]) // Sets lengthCap to length: 5 cycleNumbers.push(cycleNumbers[0]) // [2, 3, 4, 5, 1] cycleNumbers.push(cycleNumbers[0]) // [3, 4, 5, 1, 2] cycleNumbers.push(cycleNumbers[0]) // [4, 5, 1, 2, 3] uncap(cycleNumbers) // The cycle is broken cycleNumbers.push(cycleNumbers[0]) // [4, 5, 1, 2, 3, 4] cycleNumbers.push(cycleNumbers[0]) // [4, 5, 1, 2, 3, 4, 4] cycleNumbers.push(cycleNumbers[0]) // [4, 5, 1, 2, 3, 4, 4, 4] ``` ## Clone Copy the values into a new capped array with the same lengthCap ```js var cap = require('cappedarray').cap var clone = require('cappedarray').clone var capped1 = cap([1, 2, 3]) var capped2 = clone(capped1) capped2.push(4) console.log(capped1, capped2) > [1, 2, 3] [2, 3, 4] // Clone is just a wrapper for cap(capped.slice(), capped.lengthCap) ``` ## Gotchas * Behavior maybe unexpected if a capped array is passed to a library for modification. * lengthCap must be a non negative integer. Other values will throw 'Invalid array lengthCap'. This mimics the behavior of assigning array.length. * `push` and `unshift` return the length of the array, **not** the array, in line with the existing behavior. ```js // array1 is not an array var array1 = cap([1, 2, 3, 4, 5, 6], 3).push() console.log(array1) > 3 // This works var array2 = cap([1, 2, 3, 4, 5, 6], 3) array2.push() console.log(array2) > [4, 5, 6] // or this var array3 ( array3 = cap([1, 2, 3, 4, 5, 6], 3) ).push() console.log(array3) > [4, 5, 6] ``` * Arrays can be made longer than lengthCap by using splice, assigning to a numbered key or using the Array prototype functions with `call` or `apply`. ```js var array1 = cap([1, 2, 3], 3) // [1, 2, 3] length = 3, lengthCap = 3 array1.splice(1, 0, 1.1, 1.2, 1.3) // [1, 1.1, 1.2, 1.3, 2, 3] length = 6, lengthCap = 3 var array2 = cap([1, 2, 3], 3) // [1, 2, 3] length = 3, lengthCap = 3 array2[3] = 4 // [1, 2, 3, 4] length = 4, lengthCap = 3 var array3 = cap([1, 2, 3], 3) // [1, 2, 3] length = 3, lengthCap = 3 Array.prototype.push.call(array3, 4) // [1, 2, 3, 4] length = 4, lengthCap = 3 [].push.apply(array3, [5, 6]) // [1, 2, 3, 4, 5, 6] length = 6, lengthCap = 3 ```