Skip to content

Commit

Permalink
Merge pull request #15 from gossie/feature/issue#14_new-operators
Browse files Browse the repository at this point in the history
resolved #14
  • Loading branch information
gossie authored Dec 27, 2019
2 parents f2a9f2d + c2281a5 commit 570ecca
Show file tree
Hide file tree
Showing 20 changed files with 336 additions and 41 deletions.
27 changes: 27 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,33 @@ Some works similar to the `first`-operator except that not the element is return
`every` also applies the passed function to each element. As soon as one element does not evaluate to `true` the pipe immediately returns `false`.
* __none__<br />
`none` also applies the passed function to each element. As soon as one element evaluates to `true` the pipe immediately returns `false`.
* __reduceToSome__<br />
Checks if there are two consecutive elements that fullfill the constraint passed. If a pair is found `true` is returned immediately.
```typescript
const result: boolean = [1, 2, 4, 5]
.pipe(
reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0)
)
```
`result` would be `true` because `(2+4)%2 === 0` is `true`. The pair of 4 and 5 would not be checked.
* __reduceToEvery__<br />
Checks if every two consecutive elements fullfill the constraint passed. If a pair is found that does not, `false` is returned immediately.
```typescript
const result: boolean = [1, 3, 4, 6]
.pipe(
reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0)
)
```
`result` would be `false` because `(3+4)%2 === 0` is `false`. The pair of 4 and 6 would not be checked.
* __reduceToNone__<br />
Checks if no two consecutive elements fullfill the constraint passed. If a pair is found that does, `false` is returned immediately.
```typescript
const result: boolean = [1, 2, 4, 5]
.pipe(
reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0)
)
```
`result` would be `false` because `(2+4)%2 === 0` is `true`. The pair of 4 and 5 would not be checked.

<a name="customoperator"></a>
## Write your own operator
Expand Down
2 changes: 1 addition & 1 deletion src/distinct.spec.ts → __test__/distinct.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Operator, distinct } from './operators';
import { Operator, distinct } from '../src/operators';

describe('distinct', () => {

Expand Down
41 changes: 41 additions & 0 deletions __test__/every-reduce.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import { Operator, TerminalOperator, reduceToEvery } from '../src/operators';

describe('everyReduce', () => {

it('should be terminal', () => {
const operator: Operator<number, boolean> = reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.isTerminal()).toBeTruthy();
});

it('should have fallback value', () => {
const operator: TerminalOperator<number, boolean> = reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.getFallbackValue()).toBeTruthy();
});

it('should match criteria', () => {
const operator: Operator<number, boolean> = reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.perform(1)).toEqual({
value: true,
done: false
});

expect(operator.perform(3)).toEqual({
value: true,
done: false
});
});

it('should not match criteria', () => {
const operator: Operator<number, boolean> = reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.perform(1)).toEqual({
value: true,
done: false
});

expect(operator.perform(4)).toEqual({
value: false,
done: true
});
});

});
2 changes: 1 addition & 1 deletion src/every.spec.ts → __test__/every.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Operator, TerminalOperator, every } from "./operators";
import { Operator, TerminalOperator, every } from "../src/operators";

describe('every', () => {

Expand Down
2 changes: 1 addition & 1 deletion src/filter.spec.ts → __test__/filter.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Operator, filter } from './operators';
import { Operator, filter } from '../src/operators';

describe('filter', () => {

Expand Down
2 changes: 1 addition & 1 deletion src/find.spec.ts → __test__/find.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Operator, TerminalOperator, find } from './operators';
import { Operator, TerminalOperator, find } from '../src/operators';

describe('find', () => {

Expand Down
2 changes: 1 addition & 1 deletion src/flat-map.spec.ts → __test__/flat-map.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IntermediateOperator, flatMap } from './operators';
import { IntermediateOperator, flatMap } from '../src/operators';

describe('flatMap', () => {

Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import './polyfill.mock';
import './index';
import '../src/index';

describe('pipe already exists', () => {
it('should not override pipe when already set', () => {
Expand Down
88 changes: 76 additions & 12 deletions src/index.spec.ts → __test__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import './index';
import { filter, map, flatMap, distinct, find, some, every, none } from './operators';
import '../src/index';
import { filter, map, flatMap, distinct, find, some, every, none, reduceToEvery, reduceToSome, reduceToNone } from '../src/operators';

describe('pipe', () => {

Expand Down Expand Up @@ -32,7 +32,7 @@ describe('pipe', () => {
});

it('should filter', () => {
const result: Array<string> = [0, 1, 1, 2, 3, 4, 2, 5, 6, 7, 2, 8, 9]
const result: Array<number> = [0, 1, 1, 2, 3, 4, 2, 5, 6, 7, 2, 8, 9]
.pipe(
filter((n: number) => n%2 == 0)
);
Expand Down Expand Up @@ -72,7 +72,7 @@ describe('pipe', () => {
});

it('should pipe and return true because some elements match criteria', () => {
const result: number = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
const result: boolean = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
.pipe(
map((n: string) => parseInt(n)),
some((n: number) => n > 5 && n < 10)
Expand All @@ -82,7 +82,7 @@ describe('pipe', () => {
});

it('should pipe and return false because no element matches criteria', () => {
const result: number = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
const result: boolean = ['1', '2', '3', '4', '5', '6', '7', '8', '9']
.pipe(
map((n: string) => parseInt(n)),
some((n: number) => n >= 10)
Expand All @@ -92,7 +92,7 @@ describe('pipe', () => {
});

it('should pipe and return true because all elements match criteria', () => {
const result: number = ['2', '4', '6', '8', '10', '12', '14', '16', '18', '20']
const result: boolean = ['2', '4', '6', '8', '10', '12', '14', '16', '18', '20']
.pipe(
map((n: string) => parseInt(n)),
every((n: number) => n%2 === 0)
Expand All @@ -102,7 +102,7 @@ describe('pipe', () => {
});

it('should pipe and return false because not all elements match criteria', () => {
const result: number = ['2', '4', '6', '8', '11', '12', '14', '16', '18', '20']
const result: boolean = ['2', '4', '6', '8', '11', '12', '14', '16', '18', '20']
.pipe(
map((n: string) => parseInt(n)),
every((n: number) => n%2 === 0)
Expand All @@ -112,7 +112,7 @@ describe('pipe', () => {
});

it('should pipe and return true because all elements do not match criteria', () => {
const result: number = ['3', '5', '7', '9', '11', '13', '15', '17', '19', '21']
const result: boolean = ['3', '5', '7', '9', '11', '13', '15', '17', '19', '21']
.pipe(
map((n: string) => parseInt(n)),
none((n: number) => n%2 === 0)
Expand All @@ -122,7 +122,7 @@ describe('pipe', () => {
});

it('should pipe and return false because not all elements match criteria', () => {
const result: number = ['3', '5', '7', '9', '12', '13', '15', '17', '19', '21']
const result: boolean = ['3', '5', '7', '9', '12', '13', '15', '17', '19', '21']
.pipe(
map((n: string) => parseInt(n)),
none((n: number) => n%2 === 0)
Expand Down Expand Up @@ -151,7 +151,7 @@ describe('pipe', () => {

describe('flatMap', () => {
it('should pipe with flatMap as last operator', () => {
const result: number = ['1', '3', '5', '7', '9']
const result: Array<number> = ['1', '3', '5', '7', '9']
.pipe(
map((s: string) => parseInt(s)),
flatMap((n: number) => [n, n+1])
Expand All @@ -161,7 +161,7 @@ describe('pipe', () => {
});

it('should pipe with flatMap as intermediate operator', () => {
const result: number = ['1', '3', '5', '7', '9']
const result: Array<number> = ['1', '3', '5', '7', '9']
.pipe(
map((s: string) => parseInt(s)),
flatMap((n: number) => [n, n+1]),
Expand All @@ -184,7 +184,7 @@ describe('pipe', () => {
});

it('should pipe with flatMap as intermediate operator and filter in the end', () => {
const result: boolean = ['1', '3', '5', '7', '9']
const result: Array<number> = ['1', '3', '5', '7', '9']
.pipe(
map((s: string) => parseInt(s)),
flatMap((n: number) => [n, n+1]),
Expand All @@ -196,6 +196,70 @@ describe('pipe', () => {

});

describe('reducer', () => {

it('should successfully reduce to every', () => {
const result: boolean = ['1', '3', '5', '7', '9']
.pipe(
map((s: string) => parseInt(s)),
reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0)
);

expect(result).toBeTruthy();
});

it('should fail to reduce to every', () => {
const result: boolean = ['1', '3', '5', '6', '9']
.pipe(
map((s: string) => parseInt(s)),
reduceToEvery((n1: number, n2: number) => (n1+n2)%2 === 0)
);

expect(result).toBeFalsy();
});

it('should successfully reduce to some', () => {
const result: boolean = ['1', '2', '5', '7', '9']
.pipe(
map((s: string) => parseInt(s)),
reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0)
);

expect(result).toBeTruthy();
});

it('should fail to reduce to some', () => {
const result: boolean = ['1', '2', '5', '6', '9']
.pipe(
map((s: string) => parseInt(s)),
reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0)
);

expect(result).toBeFalsy();
});

it('should successfully reduce to none', () => {
const result: boolean = ['1', '2', '5', '6', '9']
.pipe(
map((s: string) => parseInt(s)),
reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0)
);

expect(result).toBeTruthy();
});

it('should fail to reduce to none', () => {
const result: boolean = ['1', '2', '5', '7', '9']
.pipe(
map((s: string) => parseInt(s)),
reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0)
);

expect(result).toBeFalsy();
});

})

});

})
2 changes: 1 addition & 1 deletion src/map.spec.ts → __test__/map.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Operator, map } from './operators';
import { Operator, map } from '../src/operators';

describe('map', () => {

Expand Down
45 changes: 45 additions & 0 deletions __test__/none-reduce.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Operator, TerminalOperator, reduceToNone } from '../src/operators';

describe('someReduce', () => {

it('should be terminal', () => {
const operator: Operator<number, boolean> = reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.isTerminal()).toBeTruthy();
});

it('should have fallback value', () => {
const operator: TerminalOperator<number, boolean> = reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.getFallbackValue()).toBeTruthy();
});

it('should match criteria', () => {
const operator: Operator<number, boolean> = reduceToNone((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.perform(1)).toEqual({
value: true,
done: false
});

expect(operator.perform(3)).toEqual({
value: false,
done: true
});
});

it('should not match criteria', () => {
interface Item {
value: number;
}

const operator: Operator<Item, boolean> = reduceToNone((n1: Item, n2: Item) => (n1.value+n2.value)%2 === 0);
expect(operator.perform({value: 1})).toEqual({
value: true,
done: false
});

expect(operator.perform({value: 4})).toEqual({
value: true,
done: false
});
});

});
2 changes: 1 addition & 1 deletion src/none.spec.ts → __test__/none.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { TerminalOperator, none } from './operators';
import { TerminalOperator, none } from '../src/operators';

describe('none', () => {

Expand Down
File renamed without changes.
45 changes: 45 additions & 0 deletions __test__/some-reduce.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import { Operator, TerminalOperator, reduceToSome } from '../src/operators';

describe('someReduce', () => {

it('should be terminal', () => {
const operator: Operator<number, boolean> = reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.isTerminal()).toBeTruthy();
});

it('should have fallback value', () => {
const operator: TerminalOperator<number, boolean> = reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.getFallbackValue()).toBe(false)
});

it('should match criteria', () => {
const operator: Operator<number, boolean> = reduceToSome((n1: number, n2: number) => (n1+n2)%2 === 0);
expect(operator.perform(1)).toEqual({
value: false,
done: false
});

expect(operator.perform(3)).toEqual({
value: true,
done: true
});
});

it('should not match criteria', () => {
interface Item {
value: number;
}

const operator: Operator<Item, boolean> = reduceToSome((n1: Item, n2: Item) => (n1.value+n2.value)%2 === 0);
expect(operator.perform({value: 1})).toEqual({
value: false,
done: false
});

expect(operator.perform({value: 4})).toEqual({
value: false,
done: false
});
});

});
2 changes: 1 addition & 1 deletion src/some.spec.ts → __test__/some.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Operator, TerminalOperator, some } from './operators';
import { Operator, TerminalOperator, some } from '../src/operators';

describe('some', () => {

Expand Down
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit 570ecca

Please sign in to comment.