Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Map and filter to array (#27) #28

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions chain.js
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,15 @@ function extendChainPrototype (hideWarnings) {
'every',
'inverse',
'filter',
'filterToArray',
'findKey',
'find',
'forEach',
'keys',
'keysIn',
'mapKeys',
'map',
'mapToArray',
'reduce',
'some',
'values',
Expand Down
39 changes: 39 additions & 0 deletions filter-to-array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @module object-loops/filter-to-array
*/
var forEach = require('./for-each')

/**
* Creates a new array with all entries that pass the test implemented by the provided function.
* @function module:object-loops/filter-to-array
* @param {object} [obj] - object to filter values, not accepted if being used directly on Object.prototype
* @param {filterCallback} callback - function to test each value in the array. return true to keep that entry, false otherwise.
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {Array} newly created array with filtered values
*/
module.exports = filterToArray

function filterToArray (obj, callback, thisArg) {
if (Array.isArray(obj)) {
return obj.filter(callback, thisArg)
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' must be a function')
}
var filteredList = []
forEach(obj, function (val, key, obj) {
var include = callback.call(thisArg, val, key, obj)
if (include) {
filteredList.push(val)
}
})
return filteredList
}
/**
* This callback type is called `filterCallback` and is displayed as a global symbol.
* @callback filterCallback
* @param {*} val - value for key
* @param {string} key - object key (used in current iteration)
* @param {object} obj - object which values are being iterated
* @returns {boolean} include - return true to keep that entry, false otherwise
*/
2 changes: 2 additions & 0 deletions index.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@ function extendObjectPrototype (hideWarnings) {
'every',
'inverse',
'filter',
'filterToArray',
'findKey',
'find',
'forEach',
'keys',
'keysIn',
'mapKeys',
'map',
'mapToArray',
'reduce',
'some',
'values',
Expand Down
36 changes: 36 additions & 0 deletions map-to-array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/**
* @module object-loops/map-to-array
*/
var forEach = require('./for-each')

/**
* Creates a new array with the results of calling a provided function on every value in the object.
* @function module:object-loops/map-to-array
* @param {object} [obj] - object to map values, not accepted if being used directly on Object.prototype
* @param {mapCallback} callback - function that produces the new value for the new mapped array
* @param {*} [thisArg] - optional. context to bind to callback
* @returns {Array} newly created array with mapped values
*/
module.exports = mapToArray

function mapToArray (obj, callback, thisArg) {
if (Array.isArray(obj)) {
return obj.map(callback, thisArg)
}
if (typeof callback !== 'function') {
throw new TypeError(callback + ' must be a function')
}
var mappedList = []
forEach(obj, function (val, key, obj) {
mappedList.push(callback.call(thisArg, val, key, obj))
})
return mappedList
}
/**
* This callback type is called `mapCallback` and is displayed as a global symbol.
* @callback mapCallback
* @param {*} val - value for key
* @param {string} key - object key (used in current iteration)
* @param {object} obj - object which values are being iterated
* @returns {*} mappedValue - value for key in the new, mapped object
*/
144 changes: 144 additions & 0 deletions test/test-filter-to-array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
var Code = require('code')
var Lab = require('lab')
var lab = exports.lab = Lab.script()
var sinon = require('sinon')

var describe = lab.describe
var it = lab.it
var before = lab.before
var after = lab.after
var beforeEach = lab.beforeEach
var afterEach = lab.afterEach
var expect = Code.expect

var noop = require('101/noop')
var equals = require('101/equals')
var passAny = require('101/pass-any')
var filter = require('../filter-to-array')
var equalsOneOrThree = passAny(equals(1), equals(3))

describe('filter', function () {
describe('prototype', function () {
before(function (done) {
require('../index')()
done()
})
after(require('./fixtures/reset-object-prototype'))
it('should iterate through all the key-value pairs in the object', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var callback = sinon.spy()
var thisArg = {}
obj.filter(callback, thisArg)
// assertions
expect(callback.callCount).to.equal(3)
expect(callback.calledOn(thisArg)).to.equal(true)
expect(callback.firstCall.args[0]).to.equal(1)
expect(callback.firstCall.args[1]).to.equal('foo')
expect(callback.firstCall.args[2]).to.equal(obj)
expect(callback.secondCall.args[0]).to.equal(2)
expect(callback.secondCall.args[1]).to.equal('bar')
expect(callback.secondCall.args[2]).to.equal(obj)
expect(callback.thirdCall.args[0]).to.equal(3)
expect(callback.thirdCall.args[1]).to.equal('baz')
expect(callback.thirdCall.args[2]).to.equal(obj)
done()
})
it('should return an object with new filtered values', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var filteredList = obj.filter(equalsOneOrThree)
Object.keys(obj).forEach(function (key) {
var val = obj[key]
if (equalsOneOrThree(val)) {
expect(filteredList[key]).to.equal(obj[key])
} else {
expect(filteredList[key]).to.be.undefined()
}
})
done()
})
})
describe('require', function () {
it('should iterate through all the key-value pairs in the object', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var callback = sinon.spy()
var thisArg = {}
filter(obj, callback, thisArg)
// assertions
expect(callback.callCount).to.equal(3)
expect(callback.calledOn(thisArg)).to.equal(true)
expect(callback.firstCall.args[0]).to.equal(1)
expect(callback.firstCall.args[1]).to.equal('foo')
expect(callback.firstCall.args[2]).to.equal(obj)
expect(callback.secondCall.args[0]).to.equal(2)
expect(callback.secondCall.args[1]).to.equal('bar')
expect(callback.secondCall.args[2]).to.equal(obj)
expect(callback.thirdCall.args[0]).to.equal(3)
expect(callback.thirdCall.args[1]).to.equal('baz')
expect(callback.thirdCall.args[2]).to.equal(obj)
done()
})
it('should return an object with new filterped values', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var filteredList = filter(obj, equalsOneOrThree)
expect(filteredList[0]).to.equal(obj.foo)
expect(filteredList[1]).to.equal(obj.baz)
expect(filteredList).to.have.length(2)
done()
})
describe('errors', function () {
it('should throw an error if obj must be an object', function (done) {
var obj = 'notObject'
var callback = noop
var thisArg = {}
var fn = filter.bind(null, obj, callback, thisArg)
expect(fn).to.throw(/must be an object/)
done()
})
it('should throw an error if callback must be a function', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var callback = 'notFunction'
var thisArg = {}
var fn = filter.bind(null, obj, callback, thisArg)
expect(fn).to.throw(/must be a function/)
done()
})
})
describe('use w/ array', function () {
beforeEach(function (done) {
sinon.spy(Array.prototype, 'filter')
done()
})
afterEach(function (done) {
Array.prototype.filter.restore()
done()
})
it('should use array filter', function (done) {
var arr = [1, 2, 3]
expect(filter(arr, equalsOneOrThree, arr))
.to.deep.equal(arr.filter(equalsOneOrThree, arr))
sinon.assert.calledWith(Array.prototype.filter, equalsOneOrThree, arr)
done()
})
})
})
})
143 changes: 143 additions & 0 deletions test/test-map-to-array.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
var Code = require('code')
var Lab = require('lab')
var lab = exports.lab = Lab.script()
var sinon = require('sinon')

var describe = lab.describe
var it = lab.it
var before = lab.before
var after = lab.after
var beforeEach = lab.beforeEach
var afterEach = lab.afterEach
var expect = Code.expect

var noop = require('101/noop')
var map = require('../map-to-array')

describe('mapToArray', function () {
describe('prototype', function () {
before(function (done) {
require('../index')()
done()
})
after(require('./fixtures/reset-object-prototype'))
it('should iterate through all the key-value pairs in the object', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var callback = sinon.spy()
var thisArg = {}
obj.map(callback, thisArg)
// assertions
expect(callback.callCount).to.equal(3)
expect(callback.calledOn(thisArg)).to.equal(true)
expect(callback.firstCall.args[0]).to.equal(1)
expect(callback.firstCall.args[1]).to.equal('foo')
expect(callback.firstCall.args[2]).to.equal(obj)
expect(callback.secondCall.args[0]).to.equal(2)
expect(callback.secondCall.args[1]).to.equal('bar')
expect(callback.secondCall.args[2]).to.equal(obj)
expect(callback.thirdCall.args[0]).to.equal(3)
expect(callback.thirdCall.args[1]).to.equal('baz')
expect(callback.thirdCall.args[2]).to.equal(obj)
done()
})
it('should return an object with new mapped values', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var mappedList = obj.map(multiplyBy(2))
Object.keys(obj).forEach(function (key) {
expect(mappedList[key]).to.equal(multiplyBy(2)(obj[key]))
})
done()
})
})
describe('require', function () {
it('should iterate through all the key-value pairs in the object', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var callback = sinon.spy()
var thisArg = {}
map(obj, callback, thisArg)
// assertions
expect(callback.callCount).to.equal(3)
expect(callback.calledOn(thisArg)).to.equal(true)
expect(callback.firstCall.args[0]).to.equal(1)
expect(callback.firstCall.args[1]).to.equal('foo')
expect(callback.firstCall.args[2]).to.equal(obj)
expect(callback.secondCall.args[0]).to.equal(2)
expect(callback.secondCall.args[1]).to.equal('bar')
expect(callback.secondCall.args[2]).to.equal(obj)
expect(callback.thirdCall.args[0]).to.equal(3)
expect(callback.thirdCall.args[1]).to.equal('baz')
expect(callback.thirdCall.args[2]).to.equal(obj)
done()
})
it('should return an object with new mapped values', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var mappedList = map(obj, multiplyBy(2))
expect(mappedList[0]).to.equal(multiplyBy(2)(obj.foo))
expect(mappedList[1]).to.equal(multiplyBy(2)(obj.bar))
expect(mappedList[2]).to.equal(multiplyBy(2)(obj.baz))
done()
})
describe('errors', function () {
it('should throw an error if obj must be an object', function (done) {
var obj = 'notObject'
var callback = noop
var thisArg = {}
var fn = map.bind(null, obj, callback, thisArg)
expect(fn).to.throw(/must be an object/)
done()
})
it('should throw an error if callback must be a function', function (done) {
var obj = {
foo: 1,
bar: 2,
baz: 3
}
var callback = 'notFunction'
var thisArg = {}
var fn = map.bind(null, obj, callback, thisArg)
expect(fn).to.throw(/must be a function/)
done()
})
})
describe('use w/ array', function () {
beforeEach(function (done) {
sinon.spy(Array.prototype, 'map')
done()
})
afterEach(function (done) {
Array.prototype.map.restore()
done()
})
it('should use array map', function (done) {
var arr = [1, 2, 3]
var callback = multiplyBy(2)
expect(map(arr, callback, arr))
.to.deep.equal(arr.map(callback, arr))
sinon.assert.calledWith(Array.prototype.map, callback, arr)
done()
})
})
})
})

function multiplyBy (multiplier) {
return function (multiplicand) {
return multiplicand * multiplier
}
}