diff --git a/index.js b/index.js index a00f794..f02ab8a 100644 --- a/index.js +++ b/index.js @@ -2,6 +2,60 @@ // YOU KNOW WHAT TO DO // +/** + * typeOf: Returns a String representing the type of the value provided. + * + * @param {*} value Value can be anything + * + * @return {String} A String value representing the type of the value, for + * example : typeOf('hello') // => 'string' + */ +function typeOf(value) { + if(Array.isArray(value)) { + return 'array'; + } else if (value === null) { + return 'null'; + } else if (value instanceof Date) { + return 'date'; + } + return typeof value; +} +module.exports.typeOf = typeOf; + +/** + * first: Returns the first or first n elements from the provided Array. + * Provding a negative value for n will result in an empty Array. If n is + * greater than the length of the Array, the full Array will be returned. + * + * @param {Array} array The Array from which to draw the first value(s). + * @param {Number} n The number of beginning elements to be returned. + * + * @return {String} A value or an Array of the first n values. + */ +function first(array, n) { + n = n || 1; + if (n < 1 || !Array.isArray(array)) return []; + return n > 1 ? array.slice(0, n) : array[0]; +} +module.exports.first = first; + +/** + * last: Returns the last or last n elements from the provided Array. + * Provding a negative value for n will result in an empty Array. If n is + * greater than the length of the Array, the full Array will be returned. + * + * @param {Array} array The Array from which to draw the last value(s). + * @param {Number} n The number of ending elements to be returned. + * + * @return {String} A value or an Array of the first n values. + */ +function last(array, n) { + n = n || 1; + if (n < 1 || !Array.isArray(array)) return []; + return n > 1 ? array.slice(-n) : array[array.length - 1]; +} +module.exports.last = last; + /** * each: Designed to loop over a collection, Array or Object, and applies the action * Function to each value in the collection. @@ -21,4 +75,61 @@ function each(collection, action) { } } } -module.exports.each = each; \ No newline at end of file +module.exports.each = each; + +/** + * Based a a test Function, filter is designed to collect values from a + * collection, Array or Object, and return those filtered values. + * + * @param {Array or Object} collection The collection from which to filter. + * @param {Function} test The Function that tests whether values should be + * inlcuded in the returned output. The test Function MUST return a Boolean. + * + * @return {Array} An Array of the filtered values. + */ +function filter(collection, test) { + var filtered = []; + each(collection, function(value, position, collection) { + if(test(value, position, collection)) filtered.push(value); + }); + return filtered; +} +module.exports.filter = filter; + +/** + * reject: Returns an Array of values from a collection, Array or Object + * that failed a test Function. + * + * @param {Array or Object} collection The collection from which to reject. + * @param {Function} test The Function that tests whether values should be + * rejected. If the test Function returns false, the value is added to the + * rejected output. The test Function MUST return a Boolean. The test Function + * is invoked with the value, the index or key, and the collection. + * + * @return {Array} An Array of the rejected values. + */ +function reject(collection, test) { + return filter(collection, function (value, position, collection) { + return !test(value, position, collection); + }); +} +module.exports.reject = reject; + +/** + * Takes a collection, and applies a tranformation function to each value in + * the collection, and returns an Array of the tranformations. + * + * @param {Array or Object} collection The collection from which to map. + * @param {Function} transform The transformation Function, it MUST return a + * value representing a transformation of the collection value. + * + * @return {Array} An Array of the mapped or transformed values. + */ +function map(collection, transform) { + var mapped = []; + each(collection, function(value, position, collection) { + mapped.push(transform(value, position, collection)); + }); + return mapped; +} +module.exports.map = map; diff --git a/package.json b/package.json new file mode 100644 index 0000000..50dbcbd --- /dev/null +++ b/package.json @@ -0,0 +1,33 @@ +{ + "name": "lodown", + "version": "1.0.0", + "description": "My functional programming library", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "istanbul cover _mocha -- test/ -R spec" + }, + "repository": { + "type": "git", + "url": "git+https://github.com/myexampleusername/lodown.git" + }, + "keywords": [ + "functional", + "programming" + ], + "author": "jfraboni", + "license": "MIT", + "bugs": { + "url": "https://github.com/myexampleusername/lodown/issues" + }, + "homepage": "https://github.com/myexampleusername/lodown#readme", + "devDependencies": { + "chai": "^3.4.1", + "i": "^0.3.4", + "istanbul": "^0.4.2", + "mocha": "^2.3.4", + "sinon": "^1.17.2" + } +} diff --git a/test/index.spec.js b/test/index.spec.js index 2303062..348512c 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -25,4 +25,59 @@ describe('lodown', function() { } }); }); + + describe('filter', function() { + it('filter should filter Array items based on test provided', function () { + expect(lodown.filter([1, 2, 3], function(value) { return value > 2; } )).to.eql([3]); + }); + it('filter should filter Object values based on test provided', function() { + expect(lodown.filter({one: 'one', two: 'two', three: 'three'}, function(value) { return value[0] === 't' })).to.eql(['two', 'three']); + }); + }); + + describe('reject', function() { + it('should reject elements in an Array wihtout side effects', function() { + var input = ["a", 1, "b", 2, "c", 4]; + expect(lodown.reject(input, function(value, position, collection){ + return typeof value === "string" || position < collection.length / 2; + })).to.eql([2,4]); + expect(input).to.eql(["a", 1, "b", 2, "c", 4]); + }); + }); + + describe('map', function() { + it('should create an Array of transformations for each value in an Array', function () { + expect(lodown.map([1, 2, 3], function(value) { return value + 1; } )).to.eql([2, 3, 4]); + }); + it('should create an Array of transformations for each value in an Object', function() { + expect(lodown.map({one: 'one', two: 'two', three: 'three'}, function(value) { return value.toUpperCase(); })).to.eql(['ONE', 'TWO', 'THREE']); + }); + }); + + describe('typeOf', function() { + it('should return a String representing the type of the value provided', function(){ + expect(lodown.typeOf([])).to.equal('array'); + expect(lodown.typeOf('a')).to.equal('string'); + expect(lodown.typeOf(null)).to.equal('null'); + expect(lodown.typeOf(new Date())).to.equal('date'); + expect(lodown.typeOf(function () { })).to.equal('function'); + }); + }); + + describe('first', function() { + it('should return the first value or n values in an Array', function() { + expect(lodown.first(["a","b","c"])).to.equal("a"); + expect(lodown.first(["a","b","c"], 2)).to.eql(["a","b"]); + }); + it('should return empty Array if first is invoked with negative n value', function() { + expect(lodown.first(["a","b","c"], -1)).to.eql([]); + }); + it('Should return the whole Array first is invoked with n value greater than the array\'s length.', function(){ + expect(lodown.first(["a","b","c"], 5)).to.eql(["a","b","c"]); + }); + it('Should return empty Array if the array param is not an Array.', function() { + expect(lodown.first({a:"b"}, 2)).to.eql([]); + }); + }); + }); \ No newline at end of file