From 12a69619f4152a549706e21e82f24d19112c1e68 Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Fri, 22 Jan 2016 04:18:37 +0000 Subject: [PATCH 1/7] * add filter and tests --- index.js | 21 ++++++++++++++++++++- package.json | 33 +++++++++++++++++++++++++++++++++ test/index.spec.js | 15 ++++++++++++--- 3 files changed, 65 insertions(+), 4 deletions(-) create mode 100644 package.json diff --git a/index.js b/index.js index d795c32..1c01e28 100644 --- a/index.js +++ b/index.js @@ -19,4 +19,23 @@ 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; \ No newline at end of file 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 1a2b29a..390a7b8 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -10,8 +10,8 @@ describe('lodown', function() { var action = sinon.spy(); lodown.each(customers, action); expect(action.callCount).to.equal(customers.length); - customers.forEach(function(customer){ - expect(action.calledWith(customer)).to.be.true; + customers.forEach(function(customer, index){ + expect(action.calledWith(customer, index, customers)).to.be.true; }); }); @@ -21,8 +21,17 @@ describe('lodown', function() { lodown.each(customer, action); expect(action.callCount).to.equal(Object.keys(customer).length); for(var key in customer) { - expect(action.calledWith(customer[key])).to.be.true; + expect(action.calledWith(customer[key], key, customer)).to.be.true; } }); }); + + 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']); + }); + }); }); \ No newline at end of file From f39ed2dc6caeefbe47a01e0ab420ecbe761e90f2 Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Fri, 22 Jan 2016 05:23:53 +0000 Subject: [PATCH 2/7] * add map and tests --- index.js | 21 ++++++++++++++++++++- test/index.spec.js | 9 +++++++++ 2 files changed, 29 insertions(+), 1 deletion(-) diff --git a/index.js b/index.js index 1c01e28..97d0965 100644 --- a/index.js +++ b/index.js @@ -38,4 +38,23 @@ function filter(collection, test) { }); return filtered; } -module.exports.filter = filter; \ No newline at end of file +module.exports.filter = filter; + +/** + * 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; \ No newline at end of file diff --git a/test/index.spec.js b/test/index.spec.js index 390a7b8..abf663f 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -34,4 +34,13 @@ describe('lodown', function() { expect(lodown.filter({one: 'one', two: 'two', three: 'three'}, function(value) { return value[0] === 't' })).to.eql(['two', 'three']); }); }); + + describe('map', function() { + it('map 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('map 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']); + }); + }); }); \ No newline at end of file From f7d85eef6262d40f4ecd363ab390bc9ff8723a04 Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Sun, 24 Jan 2016 07:38:32 +0000 Subject: [PATCH 3/7] * add imp and tests --- index.js | 20 ++++++++++++++++++++ test/index.spec.js | 22 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/index.js b/index.js index 97d0965..885bcde 100644 --- a/index.js +++ b/index.js @@ -1,5 +1,25 @@ 'use strict'; +/** + * 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; + /** * each: Designed to loop over a collection, Array or Object, and applies the action * Function to each value in the collection. diff --git a/test/index.spec.js b/test/index.spec.js index abf663f..a32a143 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -36,11 +36,29 @@ describe('lodown', function() { }); describe('map', function() { - it('map should create an Array of transformations for each value in an Array', 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('map should create an Array of transformations for each value in an Object', function() { + 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'); + }); + }); + +// * - "array" +// * - "object" +// * - "undefined" +// * - "number" +// * - "boolean" +// * - "null" +// * - "function" }); \ No newline at end of file From 6dcd176699cd63b4fd2d6200a0ee3eec9bf0c0fc Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Sun, 24 Jan 2016 07:45:22 +0000 Subject: [PATCH 4/7] * add first and test --- index.js | 7 +++++++ test/index.spec.js | 23 ++++++++++++++++------- 2 files changed, 23 insertions(+), 7 deletions(-) diff --git a/index.js b/index.js index 885bcde..c098777 100644 --- a/index.js +++ b/index.js @@ -20,6 +20,13 @@ function typeOf(value) { } module.exports.typeOf = typeOf; +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; + /** * each: Designed to loop over a collection, Array or Object, and applies the action * Function to each value in the collection. diff --git a/test/index.spec.js b/test/index.spec.js index a32a143..feec5c6 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -54,11 +54,20 @@ describe('lodown', function() { }); }); -// * - "array" -// * - "object" -// * - "undefined" -// * - "number" -// * - "boolean" -// * - "null" -// * - "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 From 64004307e6869b35329e21d0f1cc60ec58755477 Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Sun, 24 Jan 2016 08:06:51 +0000 Subject: [PATCH 5/7] * add first docs --- index.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/index.js b/index.js index c098777..b68d8f6 100644 --- a/index.js +++ b/index.js @@ -20,6 +20,16 @@ function 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 []; From e7105ce02dd112a3b6262fd8028bd03e9c5c5e0e Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Sun, 24 Jan 2016 17:51:59 +0000 Subject: [PATCH 6/7] * add last --- index.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/index.js b/index.js index da21cc2..6731467 100644 --- a/index.js +++ b/index.js @@ -39,6 +39,23 @@ function first(array, n) { } 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. From b955ac94ef9394f60eef5016a8e911819ce1a18c Mon Sep 17 00:00:00 2001 From: myexampleusername Date: Fri, 29 Jan 2016 08:17:34 +0000 Subject: [PATCH 7/7] * add reject --- index.js | 19 +++++++++++++++++++ test/index.spec.js | 10 ++++++++++ 2 files changed, 29 insertions(+) diff --git a/index.js b/index.js index 6731467..f02ab8a 100644 --- a/index.js +++ b/index.js @@ -96,6 +96,25 @@ function filter(collection, test) { } 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. diff --git a/test/index.spec.js b/test/index.spec.js index e5389e5..348512c 100644 --- a/test/index.spec.js +++ b/test/index.spec.js @@ -35,6 +35,16 @@ describe('lodown', function() { }); }); + 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]);