Skip to content
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
1 change: 1 addition & 0 deletions lab-andrew/.eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
**/*/vendor/
26 changes: 26 additions & 0 deletions lab-andrew/.eslintrc.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"env": {
"browser": true,
"node": true,
"commonjs": true,
"jest": true,
"es6": true
},
"globals": {
"err": true,
"req": true,
"res": true,
"next": true
},
"extends": "eslint:recommended",
"parserOptions": {
"sourceType": "module"
},
"rules": {
"no-console": "off",
"indent": [ "error", 2 ],
"quotes": ["error", "single", { "allowTemplateLiterals": true }],
"comma-dangle": ["error", "always-multiline"],
"semi": [ "error", "always" ]
}
}
92 changes: 92 additions & 0 deletions lab-andrew/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@

# Created by https://www.gitignore.io/api/node,macos

### macOS ###
*.DS_Store
.AppleDouble
.LSOverride

# Icon must end with two \r
Icon

# Thumbnails
._*

# Files that might appear in the root of a volume
.DocumentRevisions-V100
.fseventsd
.Spotlight-V100
.TemporaryItems
.Trashes
.VolumeIcon.icns
.com.apple.timemachine.donotpresent

# Directories potentially created on remote AFP share
.AppleDB
.AppleDesktop
Network Trash Folder
Temporary Items
.apdisk

### Node ###
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*

# Runtime data
pids
*.pid
*.seed
*.pid.lock

# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov

# Coverage directory used by tools like istanbul
coverage

# nyc test coverage
.nyc_output

# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt

# Bower dependency directory (https://bower.io/)
bower_components

# node-waf configuration
.lock-wscript

# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release

# Dependency directories
node_modules/
jspm_packages/

# Typescript v1 declaration files
typings/

# Optional npm cache directory
.npm

# Optional eslint cache
.eslintcache

# Optional REPL history
.node_repl_history

# Output of 'npm pack'
*.tgz

# Yarn Integrity file
.yarn-integrity

# dotenv environment variables file
.env


# End of https://www.gitignore.io/api/node,macos
1 change: 1 addition & 0 deletions lab-andrew/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
The exported module from fp.js is an object with 4 functions attached. The functions are map, filter, reduce and slice. Each function takes an array as a parameter, as well as additional parameters. Map filter and reduce take callback functions, reduce takes an initial value, and slice takes a start and end value. Map will only take numbers as input into the array, and will return an error if anything else is passed in. Filter has essentially the same input validation as map. I set up reduce to only function with an array of numbers as inputs, although, broadly speaking, reduce can be used in other cases. The accumulator (initialValue) is forced in this case to be a number also. The only input validation I did for slice, was to make sure that if a parameter for start or end was passed in, that it was a number. I parsed that in my code to make sure it was an integer and not a float. Also, the array must not be empty. The start of the slice function must not be greater than the length of the array. There was more validation that could have been implemented, but it started to get a lot more complex, and the functionality present seems sufficient.
223 changes: 223 additions & 0 deletions lab-andrew/__test__/fp.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,223 @@
'use strict';

const fp = require('../lib/fp');

describe('fp.test.js', () => {

describe('testing functionality for fp.map', () => {

test('does map return expected values', () => {
expect(fp.map(
e => e + 2,
[0, 1, 2]
)).toEqual([2, 3, 4]);
});
});

describe('testing invalid input for fp.map', () => {

test('is an error thrown with invalid values in collection', () => {
const newFun = () => {
fp.map(
e => e + 2,
[null, 1, 2]
);
};
const noColl = () => {
fp.map(
e => e + 2,
[]
);
};
const noArr = () => {
fp.map(
e => e + 2,
'whatsup'
);
};
expect(newFun).toThrow();
expect(noColl).toThrow();
expect(noArr).toThrow();
});

test('is an error thrown with invalid callback', () => {
const badFun = () => {
fp.map(
'hello',
[0, 1, 2]
);
};
expect(badFun).toThrow();
});
});

describe('testing functionality for fp.filter', () => {

test('does filter return expected values', () => {
expect(fp.filter(
e => e < 5,
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
)).toEqual([0, 1, 2, 3, 4]);
});
});

describe('testing invalid input for fp.filter', () => {

test('is an error thrown with invalid values in collection', () => {
const newFilt = () => {
fp.filter(
e => e < 2,
[null, 1, 2]
);
};
const noFiltColl = () => {
fp.filter(
e => e < 2,
[]
);
};
const noFiltArr = () => {
fp.filter(
e => e < 2,
'whatsup'
);
};
expect(newFilt).toThrow();
expect(noFiltColl).toThrow();
expect(noFiltArr).toThrow();
});

test('is an error thrown with invalid callback', () => {
const badFilt = () => {
fp.filter(
'hello',
[0, 1, 2]
);
};
expect(badFilt).toThrow();
});
});

describe('testing functionality for fp.reduce', () => {

test('does reduce return expected values', () => {
expect(fp.reduce(
(a, c) => a + c,
[1, 2, 3],
0
)).toEqual(6);
});
});

describe('testing invalid input for fp.reduce', () => {

test('is an error thrown with invalid values in collection', () => {
const newRed = () => {
fp.reduce(
(a, c) => a + c,
[1, 'wawa', 3],
0
);
};
const noRedColl = () => {
fp.reduce(
(a, c) => a + c,
[],
0
);
};
const noRedArr = () => {
fp.reduce(
(a, c) => a + c,
'whatevs',
0
);
};
expect(newRed).toThrow();
expect(noRedColl).toThrow();
expect(noRedArr).toThrow();
});

test('is an error thrown with invalid accumulator', () => {
const badAcc = () => {
fp.reduce(
(a, c) => a + c,
[1, 2, 3],
'a'
);
};
expect(badAcc).toThrow();
});

test('is an error thrown with invalid callback', () => {
const badRed = () => {
fp.reduce(
'nah',
[1, 2, 3],
0
);
};
expect(badRed).toThrow();
});
});

describe('testing functionality for fp.slice', () => {

test('does slice return expected values', () => {
expect(fp.slice(
[0, 1, 2, 3],
1,
3
)).toEqual([1, 2]);
expect(fp.slice(
['apple', 'banana', 'orange', 'plum'],
undefined,
undefined
)).toEqual(['apple', 'banana', 'orange', 'plum']);
});
});

describe('testing invalid input for fp.slice', () => {

test('if a start or end value is supplied, it must be an integer not longer than array.length', () => {
const newSli = () => {
fp.slice(
[1, 2, 3],
'boop'
);
};
const newSli2 = () => {
fp.slice(
[1, 2, 3],
2,
['boop', 'lololololol']
);
};
const newSli3 = () => {
fp.slice(
[1, 2, 3],
4
);
};

expect(newSli).toThrow();
expect(newSli2).toThrow();
expect(newSli3).toThrow();
});

test('is an error thrown with an invalid collection', () => {
const badSli = () => {
fp.slice(
'foofoo'
);
};
expect(badSli).toThrow();
const noSliArr = () => {
fp.slice(
[]
);
};
expect(noSliArr).toThrow();
});
});
});
46 changes: 46 additions & 0 deletions lab-andrew/lib/fp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
'use strict';

const fp = module.exports = {};

fp.map = (callback, collection) => {
if (typeof collection !== 'object') throw new TypeError('collection must be an array');
if (collection.length < 1) throw new TypeError('collection must contain values');
collection.forEach(e => {
if (typeof e !== 'number') throw new TypeError('all array values must be numbers');
});
return Array.prototype.map.call(collection, callback);
};

fp.filter = (callback, collection) => {
if (typeof collection !== 'object') throw new TypeError('collection must be an array');
if (collection.length < 1) throw new TypeError('collection must contain values');
collection.forEach(e => {
if (typeof e !== 'number') throw new TypeError('all array values must be numbers');
});
return Array.prototype.filter.call(collection, callback);
};

fp.reduce = (callback, collection, initialValue) => {
if (typeof collection !== 'object') throw new TypeError('collection must be an array');
if (collection.length < 1) throw new TypeError('collection must contain values');
collection.forEach(e => {
if (typeof e !== 'number') throw new TypeError('all array values must be numbers');
});
if (typeof initialValue !== 'number') throw new TypeError('accumulator must be a number');
return Array.prototype.reduce.call(collection, callback, initialValue);
};

fp.slice = (collection, begin, end) => {
if (typeof collection !== 'object') throw new TypeError('collection must be an array');
if (collection.length < 1) throw new TypeError('collection must contain values');
if (begin){
begin = parseInt(begin);
if (isNaN(begin)) throw new TypeError('begin argument must be an integer');
}
if (end){
end = parseInt(end);
if (isNaN(end)) throw new TypeError('end argument must be an integer');
}
if (Math.abs(begin) > collection.length) throw new TypeError('beginning must not exceed length of array');
return Array.prototype.slice.call(collection, begin, end);
};
Loading