Skip to content

Commit 8a60376

Browse files
Merge pull request #21 from Jozty/dev-ch
Dev ch
2 parents 2decf23 + c3b8380 commit 8a60376

10 files changed

+226
-1
lines changed

crossproduct.ts

+17
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
import curryN from "./utils/curry_n.ts"
2+
import { Curry2 } from "./utils/types.ts"
3+
4+
function crossproduct(a: Array<any>, b: Array<any>) {
5+
let result = []
6+
for(let idx = 0; idx < a.length; idx++)
7+
for(let j = 0; j < b.length; j++)
8+
result[result.length] = [a[idx], b[j]]
9+
return result
10+
}
11+
12+
/** Creates a new list out of the two supplied by creating each possible pair
13+
* from the list passed as arguments.
14+
*
15+
* Fae.crossproduct([1, 2, 3], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b'], [3, 'a'], [3, 'b']]
16+
*/
17+
export default curryN(2, crossproduct) as Curry2<Array<any>>

mod.ts

+4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ export { default as complement } from './complement.ts'
1515
export { default as compose } from './compose.ts'
1616
export { default as concat } from './concat.ts'
1717
export { default as contains } from './contains.ts'
18+
export { default as crossproduct } from './crossproduct.ts'
1819
export { default as curry } from './curry.ts'
1920
export { default as dec } from './dec.ts'
2021
export { default as dissoc } from './dissoc.ts'
@@ -66,6 +67,7 @@ export { default as props } from './props.ts'
6667
export { default as range } from './range.ts'
6768
export { default as rangeUntil } from './rangeUntil.ts'
6869
export { default as reduce } from './reduce.ts'
70+
export { default as reject } from './reject.ts'
6971
export { default as reverse } from './reverse.ts'
7072
export { default as set } from './set.ts'
7173
export { default as slice } from './slice.ts'
@@ -84,6 +86,8 @@ export { default as when } from './when.ts'
8486
export { default as where } from './where.ts'
8587
export { default as whereAll } from './whereAll.ts'
8688
export { default as whereAny } from './whereAny.ts'
89+
export { default as whereEq } from './whereEq.ts'
90+
export { default as xor } from './xor.ts'
8791
export { default as zip } from './zip.ts'
8892
export { default as zipObj } from './zipObj.ts'
8993
export { default as zipWith } from './zipWith.ts'

reject.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import curryN from "./utils/curry_n.ts"
2+
import { Func, Curry2, Obj, Predicate1 } from "./utils/types.ts"
3+
import complement from './complement.ts';
4+
import filter from './filter.ts';
5+
6+
function reject<T>(pred: Predicate1, filterable: Array<T> | Obj) {
7+
return filter(complement(pred), filterable)
8+
}
9+
10+
/** works as the complement of filter
11+
*
12+
* const isOdd = n => (n & 1) === 1;
13+
* const f = Fae.reject(isOdd, [1, 2, 3, 4])
14+
* f() // [2, 4]
15+
*/
16+
export default curryN(2, reject) as Curry2<Predicate1, Array<any> | Obj, Array<any> | Obj>

specs/crossproduct.spec.ts

+18
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import { describe, it } from "./_describe.ts"
2+
import { crossproduct } from '../mod.ts'
3+
import { eq } from "./utils/utils.ts"
4+
5+
6+
describe('crossproduct', () => {
7+
let a = [1, 2, null]
8+
let b = ['a', 'b', 'c']
9+
10+
it('should return an empty list if either input list is empty', () => {
11+
eq(crossproduct([], [1, 2, 3]), [])
12+
eq(crossproduct([1, 2, 3], []), [])
13+
})
14+
15+
it('should create the collection of all cross-product pairs of its parameters', () => {
16+
eq(crossproduct(a, b), [[1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, 'b'], [2, 'c'], [null, 'a'], [null, 'b'], [null, 'c']])
17+
})
18+
})

specs/reject.spec.ts

+28
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { describe, it } from "./_describe.ts"
2+
import { reject, curry } from '../mod.ts'
3+
import { eq } from "./utils/utils.ts"
4+
5+
describe('reject', () => {
6+
const equals = curry(2, (x: number, y: number) => x === y)
7+
let even = (x: number) => (x & 1) === 0
8+
let odd = (x: number) => (x & 1) === 1
9+
10+
it('should reduce an array to those not matching a filter', () => {
11+
eq(reject(even, [1, 2, 3, 4, 5]), [1, 3, 5])
12+
eq(reject(odd, [1, 2, 3, 4, 5]), [2, 4])
13+
})
14+
15+
it('should return an empty array if no element matches', () => {
16+
eq(reject((x) => x < 100, [1, 9, 99]), [])
17+
eq(reject(odd, []), [])
18+
})
19+
20+
it('should filter objects', () => {
21+
eq(reject(equals(0), {}), {})
22+
eq(reject(equals(0), {x: 0, y: 0, z: 0}), {})
23+
eq(reject(equals(0), {x: 1, y: 0, z: 0}), {x: 1})
24+
eq(reject(equals(0), {x: 1, y: 2, z: 0}), {x: 1, y: 2})
25+
eq(reject(equals(0), {x: 1, y: 2, z: 3}), {x: 1, y: 2, z: 3})
26+
})
27+
28+
})

specs/whereEq.spec.ts

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import { describe, it } from "./_describe.ts"
2+
import { whereEq } from '../mod.ts'
3+
import { eq } from "./utils/utils.ts"
4+
5+
6+
describe('whereEq', () => {
7+
8+
it('should return true if the test object satisfies the spec', () => {
9+
let spec = {x: 1, y: 2}
10+
let test1 = {x: 0, y: 200}
11+
let test2 = {x: 0, y: 10}
12+
let test3 = {x: 1, y: 101}
13+
let test4 = {x: 1, y: 2}
14+
eq(whereEq(spec, test1), false)
15+
eq(whereEq(spec, test2), false)
16+
eq(whereEq(spec, test3), false)
17+
eq(whereEq(spec, test4), true)
18+
})
19+
20+
it('should work if interfaces are different', () => {
21+
let spec = {x: 100}
22+
let test1 = {x: 20, y: 100, z: 100}
23+
let test2 = {w: 1, x: 100, y: 100, z: 100}
24+
let test3 = {}
25+
26+
27+
eq(whereEq(spec, test1), false)
28+
eq(whereEq(spec, test2), true)
29+
eq(whereEq(spec, test3), false)
30+
})
31+
32+
it('should match specs that have undefined properties', () => {
33+
let spec = {x: undefined}
34+
let test1 = {}
35+
let test2 = {x: 1}
36+
eq(whereEq(spec, test1), true)
37+
eq(whereEq(spec, test2), false)
38+
})
39+
40+
it('should return true for an empty spec', () => {
41+
eq(whereEq({}, {a: 1}), true)
42+
})
43+
44+
})

specs/xor.spec.ts

+59
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
import { describe, it } from "./_describe.ts"
2+
import { xor } from '../mod.ts'
3+
import { eq } from "./utils/utils.ts"
4+
5+
6+
describe('xor', () => {
7+
8+
it('should compare two values with exclusive or', () => {
9+
eq(xor(true, true), false)
10+
eq(xor(true, false), true)
11+
eq(xor(false, true), true)
12+
eq(xor(false, false), false)
13+
})
14+
15+
it('should return false when both values are true', () => {
16+
eq(xor(true, 'foo'), false)
17+
eq(xor(42, true), false)
18+
eq(xor('foo', 42), false)
19+
eq(xor({}, true), false)
20+
eq(xor(true, []), false)
21+
eq(xor([], {}), false)
22+
eq(xor(new Date(), true), false)
23+
eq(xor(true, Infinity), false)
24+
eq(xor(Infinity, new Date()), false)
25+
})
26+
27+
it('should return false when both values are false', () => {
28+
eq(xor(null, false), false)
29+
eq(xor(false, undefined), false)
30+
eq(xor(undefined, null), false)
31+
eq(xor(0, false), false)
32+
eq(xor(false, NaN), false)
33+
eq(xor(NaN, 0), false)
34+
eq(xor('', false), false)
35+
})
36+
37+
it('should return true when one argument is true and the other is false', () => {
38+
eq(xor('foo', null), true)
39+
eq(xor(null, 'foo'), true)
40+
eq(xor(undefined, 42), true)
41+
eq(xor(42, undefined), true)
42+
eq(xor(Infinity, NaN), true)
43+
eq(xor(NaN, Infinity), true)
44+
eq(xor({}, ''), true)
45+
eq(xor('', {}), true)
46+
eq(xor(new Date(), 0), true)
47+
eq(xor(0, new Date()), true)
48+
eq(xor([], null), true)
49+
eq(xor(undefined, []), true)
50+
})
51+
52+
it('should return a curried function', () => {
53+
eq(xor()(true)(true), false)
54+
eq(xor()(true)(false), true)
55+
eq(xor()(false)(true), true)
56+
eq(xor()(false)(false), false)
57+
})
58+
59+
})

utils/types.ts

+1-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,7 @@ export type ObjArr<T = any> = {
4646
}
4747

4848
export type ObjRec<T = number> = {
49-
[key: string]: ObjRec | ObjArr | string | number | T
49+
[key: string]: ObjRec | ObjArr | string | number | null | undefined | T
5050
}
5151

5252
export type Comparator<T> = (a: T, b: T) => 1 | -1 | 0

whereEq.ts

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import curryN from "./utils/curry_n.ts"
2+
import { Curry2, ObjRec, Obj } from "./utils/types.ts"
3+
import where from "./where.ts"
4+
import map from "./map.ts"
5+
import equals from './equals.ts'
6+
7+
function whereEq(spec: ObjRec, testObj: ObjRec) {
8+
return where(map(equals, spec), testObj)
9+
}
10+
11+
/**
12+
* Takes a spec object and a test object, returns true if the test satisfies
13+
* the spec, false otherwise.
14+
* `whereEq` is a specialization of [`where`].
15+
*
16+
* const pred = Fae.whereEq({a: 1, b: 2})
17+
*
18+
* pred({a: 1}) //=> false
19+
* pred({a: 1, b: 2}) //=> true
20+
* pred({a: 1, b: 2, c: 3}) //=> true
21+
* pred({a: 1, b: 1}) //=> false
22+
*/
23+
export default curryN(2, whereEq) as Curry2<ObjRec, ObjRec, boolean>

xor.ts

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import curryN from "./utils/curry_n.ts"
2+
import { Curry2, Obj } from "./utils/types.ts"
3+
4+
function xor(a: any, b: any) {
5+
return Boolean(a ? !b : b)
6+
}
7+
8+
/** Exclusive Or - Returns `true` if one of the arguments is truthy and the other is falsy.
9+
* Otherwise, it returns `false`.
10+
*
11+
* Fae.xor(true, true) //=> false
12+
* Fae.xor(true, false) //=> true
13+
* Fae.xor(false, true) //=> true
14+
* Fae.xor(false, false) //=> false
15+
*/
16+
export default curryN(2, xor) as Curry2<any, any, boolean>

0 commit comments

Comments
 (0)