Skip to content

Commit

Permalink
Merge pull request #21 from Jozty/dev-ch
Browse files Browse the repository at this point in the history
Dev ch
  • Loading branch information
singla-shivam authored Jun 3, 2020
2 parents 2decf23 + c3b8380 commit 8a60376
Show file tree
Hide file tree
Showing 10 changed files with 226 additions and 1 deletion.
17 changes: 17 additions & 0 deletions crossproduct.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import curryN from "./utils/curry_n.ts"
import { Curry2 } from "./utils/types.ts"

function crossproduct(a: Array<any>, b: Array<any>) {
let result = []
for(let idx = 0; idx < a.length; idx++)
for(let j = 0; j < b.length; j++)
result[result.length] = [a[idx], b[j]]
return result
}

/** Creates a new list out of the two supplied by creating each possible pair
* from the list passed as arguments.
*
* Fae.crossproduct([1, 2, 3], ['a', 'b']); //=> [[1, 'a'], [1, 'b'], [2, 'a'], [2, 'b'], [3, 'a'], [3, 'b']]
*/
export default curryN(2, crossproduct) as Curry2<Array<any>>
4 changes: 4 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ export { default as complement } from './complement.ts'
export { default as compose } from './compose.ts'
export { default as concat } from './concat.ts'
export { default as contains } from './contains.ts'
export { default as crossproduct } from './crossproduct.ts'
export { default as curry } from './curry.ts'
export { default as dec } from './dec.ts'
export { default as dissoc } from './dissoc.ts'
Expand Down Expand Up @@ -66,6 +67,7 @@ export { default as props } from './props.ts'
export { default as range } from './range.ts'
export { default as rangeUntil } from './rangeUntil.ts'
export { default as reduce } from './reduce.ts'
export { default as reject } from './reject.ts'
export { default as reverse } from './reverse.ts'
export { default as set } from './set.ts'
export { default as slice } from './slice.ts'
Expand All @@ -84,6 +86,8 @@ export { default as when } from './when.ts'
export { default as where } from './where.ts'
export { default as whereAll } from './whereAll.ts'
export { default as whereAny } from './whereAny.ts'
export { default as whereEq } from './whereEq.ts'
export { default as xor } from './xor.ts'
export { default as zip } from './zip.ts'
export { default as zipObj } from './zipObj.ts'
export { default as zipWith } from './zipWith.ts'
16 changes: 16 additions & 0 deletions reject.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import curryN from "./utils/curry_n.ts"
import { Func, Curry2, Obj, Predicate1 } from "./utils/types.ts"
import complement from './complement.ts';
import filter from './filter.ts';

function reject<T>(pred: Predicate1, filterable: Array<T> | Obj) {
return filter(complement(pred), filterable)
}

/** works as the complement of filter
*
* const isOdd = n => (n & 1) === 1;
* const f = Fae.reject(isOdd, [1, 2, 3, 4])
* f() // [2, 4]
*/
export default curryN(2, reject) as Curry2<Predicate1, Array<any> | Obj, Array<any> | Obj>
18 changes: 18 additions & 0 deletions specs/crossproduct.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { describe, it } from "./_describe.ts"
import { crossproduct } from '../mod.ts'
import { eq } from "./utils/utils.ts"


describe('crossproduct', () => {
let a = [1, 2, null]
let b = ['a', 'b', 'c']

it('should return an empty list if either input list is empty', () => {
eq(crossproduct([], [1, 2, 3]), [])
eq(crossproduct([1, 2, 3], []), [])
})

it('should create the collection of all cross-product pairs of its parameters', () => {
eq(crossproduct(a, b), [[1, 'a'], [1, 'b'], [1, 'c'], [2, 'a'], [2, 'b'], [2, 'c'], [null, 'a'], [null, 'b'], [null, 'c']])
})
})
28 changes: 28 additions & 0 deletions specs/reject.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { describe, it } from "./_describe.ts"
import { reject, curry } from '../mod.ts'
import { eq } from "./utils/utils.ts"

describe('reject', () => {
const equals = curry(2, (x: number, y: number) => x === y)
let even = (x: number) => (x & 1) === 0
let odd = (x: number) => (x & 1) === 1

it('should reduce an array to those not matching a filter', () => {
eq(reject(even, [1, 2, 3, 4, 5]), [1, 3, 5])
eq(reject(odd, [1, 2, 3, 4, 5]), [2, 4])
})

it('should return an empty array if no element matches', () => {
eq(reject((x) => x < 100, [1, 9, 99]), [])
eq(reject(odd, []), [])
})

it('should filter objects', () => {
eq(reject(equals(0), {}), {})
eq(reject(equals(0), {x: 0, y: 0, z: 0}), {})
eq(reject(equals(0), {x: 1, y: 0, z: 0}), {x: 1})
eq(reject(equals(0), {x: 1, y: 2, z: 0}), {x: 1, y: 2})
eq(reject(equals(0), {x: 1, y: 2, z: 3}), {x: 1, y: 2, z: 3})
})

})
44 changes: 44 additions & 0 deletions specs/whereEq.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import { describe, it } from "./_describe.ts"
import { whereEq } from '../mod.ts'
import { eq } from "./utils/utils.ts"


describe('whereEq', () => {

it('should return true if the test object satisfies the spec', () => {
let spec = {x: 1, y: 2}
let test1 = {x: 0, y: 200}
let test2 = {x: 0, y: 10}
let test3 = {x: 1, y: 101}
let test4 = {x: 1, y: 2}
eq(whereEq(spec, test1), false)
eq(whereEq(spec, test2), false)
eq(whereEq(spec, test3), false)
eq(whereEq(spec, test4), true)
})

it('should work if interfaces are different', () => {
let spec = {x: 100}
let test1 = {x: 20, y: 100, z: 100}
let test2 = {w: 1, x: 100, y: 100, z: 100}
let test3 = {}


eq(whereEq(spec, test1), false)
eq(whereEq(spec, test2), true)
eq(whereEq(spec, test3), false)
})

it('should match specs that have undefined properties', () => {
let spec = {x: undefined}
let test1 = {}
let test2 = {x: 1}
eq(whereEq(spec, test1), true)
eq(whereEq(spec, test2), false)
})

it('should return true for an empty spec', () => {
eq(whereEq({}, {a: 1}), true)
})

})
59 changes: 59 additions & 0 deletions specs/xor.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { describe, it } from "./_describe.ts"
import { xor } from '../mod.ts'
import { eq } from "./utils/utils.ts"


describe('xor', () => {

it('should compare two values with exclusive or', () => {
eq(xor(true, true), false)
eq(xor(true, false), true)
eq(xor(false, true), true)
eq(xor(false, false), false)
})

it('should return false when both values are true', () => {
eq(xor(true, 'foo'), false)
eq(xor(42, true), false)
eq(xor('foo', 42), false)
eq(xor({}, true), false)
eq(xor(true, []), false)
eq(xor([], {}), false)
eq(xor(new Date(), true), false)
eq(xor(true, Infinity), false)
eq(xor(Infinity, new Date()), false)
})

it('should return false when both values are false', () => {
eq(xor(null, false), false)
eq(xor(false, undefined), false)
eq(xor(undefined, null), false)
eq(xor(0, false), false)
eq(xor(false, NaN), false)
eq(xor(NaN, 0), false)
eq(xor('', false), false)
})

it('should return true when one argument is true and the other is false', () => {
eq(xor('foo', null), true)
eq(xor(null, 'foo'), true)
eq(xor(undefined, 42), true)
eq(xor(42, undefined), true)
eq(xor(Infinity, NaN), true)
eq(xor(NaN, Infinity), true)
eq(xor({}, ''), true)
eq(xor('', {}), true)
eq(xor(new Date(), 0), true)
eq(xor(0, new Date()), true)
eq(xor([], null), true)
eq(xor(undefined, []), true)
})

it('should return a curried function', () => {
eq(xor()(true)(true), false)
eq(xor()(true)(false), true)
eq(xor()(false)(true), true)
eq(xor()(false)(false), false)
})

})
2 changes: 1 addition & 1 deletion utils/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ export type ObjArr<T = any> = {
}

export type ObjRec<T = number> = {
[key: string]: ObjRec | ObjArr | string | number | T
[key: string]: ObjRec | ObjArr | string | number | null | undefined | T
}

export type Comparator<T> = (a: T, b: T) => 1 | -1 | 0
Expand Down
23 changes: 23 additions & 0 deletions whereEq.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import curryN from "./utils/curry_n.ts"
import { Curry2, ObjRec, Obj } from "./utils/types.ts"
import where from "./where.ts"
import map from "./map.ts"
import equals from './equals.ts'

function whereEq(spec: ObjRec, testObj: ObjRec) {
return where(map(equals, spec), testObj)
}

/**
* Takes a spec object and a test object, returns true if the test satisfies
* the spec, false otherwise.
* `whereEq` is a specialization of [`where`].
*
* const pred = Fae.whereEq({a: 1, b: 2})
*
* pred({a: 1}) //=> false
* pred({a: 1, b: 2}) //=> true
* pred({a: 1, b: 2, c: 3}) //=> true
* pred({a: 1, b: 1}) //=> false
*/
export default curryN(2, whereEq) as Curry2<ObjRec, ObjRec, boolean>
16 changes: 16 additions & 0 deletions xor.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import curryN from "./utils/curry_n.ts"
import { Curry2, Obj } from "./utils/types.ts"

function xor(a: any, b: any) {
return Boolean(a ? !b : b)
}

/** Exclusive Or - Returns `true` if one of the arguments is truthy and the other is falsy.
* Otherwise, it returns `false`.
*
* Fae.xor(true, true) //=> false
* Fae.xor(true, false) //=> true
* Fae.xor(false, true) //=> true
* Fae.xor(false, false) //=> false
*/
export default curryN(2, xor) as Curry2<any, any, boolean>

0 comments on commit 8a60376

Please sign in to comment.