Skip to content

Commit

Permalink
Either implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
phixid committed Dec 20, 2017
1 parent ff7f9d0 commit 439fb9e
Show file tree
Hide file tree
Showing 9 changed files with 189 additions and 26 deletions.
3 changes: 2 additions & 1 deletion .eslintrc
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"linebreak-style": [
"error",
"unix"
]
],
"no-unused-vars": ["error", { "args": "none" }]
}
}
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ as a guide, making sure your own implementation behaves as expected.

- [Box](#box)
- [LazyBox](#lazybox)
- Either
- composeLeft
- composeRight
- pipeLeft
Expand Down
2 changes: 1 addition & 1 deletion dist/cjs/subterfuge.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Subterfuge v0.5.1
/* Subterfuge v0.6.0
* https://github.com/phixid/subterfuge
* (c) 2017-2017 Kristof Hermans <@phixid>
* Subterfuge may be freely distributed under the MIT license.
Expand Down
2 changes: 1 addition & 1 deletion dist/es/subterfuge.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/* Subterfuge v0.5.1
/* Subterfuge v0.6.0
* https://github.com/phixid/subterfuge
* (c) 2017-2017 Kristof Hermans <@phixid>
* Subterfuge may be freely distributed under the MIT license.
Expand Down
25 changes: 5 additions & 20 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,16 +1,11 @@
{
"name": "subterfuge",
"version": "0.5.1",
"version": "0.6.0",
"description": "Simple functional Javascript",
"keywords": [
"functional",
"javascript"
],
"keywords": ["functional", "javascript"],
"author": "Kristof Hermans <@phixid>",
"repository": "git@github.com:phixid/subterfuge.git",
"files": [
"dist"
],
"files": ["dist"],
"main": "dist/cjs/subterfuge.js",
"module": "dist/es/subterfuge.js",
"scripts": {
Expand Down Expand Up @@ -50,19 +45,9 @@
"rollup-plugin-commonjs": "^8.2.6",
"rollup-plugin-node-resolve": "^3.0.0"
},
"jest": {
"bail": true,
"testMatch": [
"**/src/**/*.(spec|test).js",
"**/**/__tests__/**/*.(spec|test).js"
]
},
"jest": { "bail": true, "testMatch": ["**/src/**/*.(spec|test).js", "**/**/__tests__/**/*.(spec|test).js"] },
"lint-staged": {
"*.js": [
"eslint",
"prettier --write --single-quote --bracket-space=true --print-width=100",
"git add"
]
"*.js": ["eslint", "prettier --write --single-quote --bracket-space=true --print-width=100", "git add"]
},
"license": "MIT"
}
4 changes: 2 additions & 2 deletions src/containers/box.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@ import { Box } from './box';
import { isFunction, resemblesBox } from '../../__tests__/testUtilities';
import { addOne, double, randomNumberBetween1And10 } from '../../__tests__/utilities';

const randomNumber = randomNumberBetween1And10;
const randomNumber = randomNumberBetween1And10();

describe('A Box data type', () => {
describe('A Box container type', () => {
it('is a function', () => {
isFunction(Box);
});
Expand Down
13 changes: 13 additions & 0 deletions src/containers/either.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
export const Left = value => ({
map: func => Left(value),
fold: (errorhandler, successhandler) => errorhandler(value),
inspect: () => `Left(${value})`
});

export const Right = value => ({
map: func => Right(func(value)),
fold: (errorhandler, successhandler) => successhandler(value),
inspect: () => `Right(${value})`
});

export const Either = value => (value == null ? Left(value) : Right(value));
163 changes: 163 additions & 0 deletions src/containers/either.spec.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
import { Either, Left, Right } from './either';
import { isFunction, resemblesBox } from '../../__tests__/testUtilities';
import { addOne, randomNumberBetween1And10 } from '../../__tests__/utilities';

describe('Either container type: code branching', () => {
let randomNumber = randomNumberBetween1And10();

it('is a function', () => {
isFunction(Either);
});

describe('input:', () => {
it('takes one parameter', () => {
expect(Either.length).toEqual(1);
});
});

describe('output:', () => {
describe('Left container type:', () => {
const left = Left(randomNumber);

it('is a function', () => {
isFunction(Left);
});

it('API looks like that of a Box', () => {
resemblesBox(Left());
});

describe('map method:', () => {
it('returns a new Left', () => {
resemblesBox(Left(4).map(x => x));
});

it('takes one parameter', () => {
expect(left.map.length).toEqual(1);
});

it('does not apply the functor to the value', () => {
let mockFn = jest.fn();
Left().map(mockFn);
expect(mockFn).toHaveBeenCalledTimes(0);
});
});

describe('fold method:', () => {
it('is a function', () => {
isFunction(Right().fold);
});

it('takes two parameters', () => {
expect(left.fold.length).toEqual(2);
});

it('applies the second functor to the value', () => {
let mock1 = jest.fn();
let mock2 = jest.fn();

left.fold(mock1, mock2);

expect(mock1).toHaveBeenCalledTimes(1);
expect(mock2).toHaveBeenCalledTimes(0);
expect(left.fold(() => 'error', addOne)).toEqual('error');
});
});

describe('inspect', () => {
it('is a function', () => {
isFunction(left.inspect);
});

it('takes no arguments', () => {
expect(left.inspect.length).toEqual(0);
});

it('returns the current value in a `Left(${})`-template', () => {
expect(left.inspect()).toEqual(`Left(${randomNumber})`);
});
});
});

describe('Right container type:', () => {
const right = Right(randomNumber);

it('is a function', () => {
isFunction(Right);
});

it('API looks like that of a Box', () => {
resemblesBox(Right());
});

describe('map method:', () => {
it('returns a new Right', () => {
resemblesBox(Right(4).map(x => x));
});

it('takes one parameter', () => {
expect(right.map.length).toEqual(1);
});

it('applies the functor to the value', () => {
let mockFn = jest.fn();

right.map(mockFn);
expect(mockFn).toHaveBeenCalledTimes(1);
expect(mockFn).toBeCalledWith(randomNumber);
});
});

describe('fold method:', () => {
it('is a function', () => {
isFunction(Right().fold);
});

it('takes two parameters', () => {
expect(right.fold.length).toEqual(2);
});

it('applies the second functor to the value', () => {
let mock1 = jest.fn();
let mock2 = jest.fn();

right.fold(mock1, mock2);

expect(mock1).toHaveBeenCalledTimes(0);
expect(mock2).toHaveBeenCalledTimes(1);
expect(right.fold(x => x, addOne)).toEqual(randomNumber + 1);
});
});

describe('inspect', () => {
it('is a function', () => {
isFunction(right.inspect);
});

it('takes no arguments', () => {
expect(right.inspect.length).toEqual(0);
});

it('returns the current value in a `Right(${})`-template', () => {
expect(right.inspect()).toEqual(`Right(${randomNumber})`);
});
});
});

it('branches to a Left when parameter is null || undefined', () => {
expect(
Either(null)
.map(x => x + 1)
.fold(() => 'error', x => x)
).toEqual('error');
});

it('branches to a Right when parameter is not null || undefined', () => {
expect(
Either(randomNumber)
.map(x => x + 1)
.fold(() => 'error', x => x / 2)
).toEqual((randomNumber + 1) / 2);
});
});
});
2 changes: 1 addition & 1 deletion src/containers/lazybox.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ const mockFn = jest.fn();
const randomNumber = randomNumberBetween1And10;
const giveRandomNumber = () => randomNumber;

describe('A LazyBox data type', () => {
describe('A LazyBox container type', () => {
it('is a function', () => {
isFunction(LazyBox);
});
Expand Down

0 comments on commit 439fb9e

Please sign in to comment.