Skip to content

Commit

Permalink
Merge pull request #28 from Jozty/dev-ss
Browse files Browse the repository at this point in the history
add function - andThen
  • Loading branch information
singla-shivam authored Jun 12, 2020
2 parents 5f648af + e8b0607 commit a657064
Show file tree
Hide file tree
Showing 15 changed files with 396 additions and 5 deletions.
15 changes: 15 additions & 0 deletions andThen.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import curryN from "./utils/curry_n.ts"
import { Func, Curry2 } from "./utils/types.ts"
import { assertPromise } from "./utils/assert.ts"

function _andThen(f: Func, p: any) {
assertPromise('andThen', p)
return p.then(f)
}

/**
* Returns the result of applying the onSuccess function to the value inside
* a successfully resolved promise. This is useful for working with promises
* inside function compositions.
*/
export const andThen: Curry2<Func, any, Promise<any>> = curryN(2, _andThen)
18 changes: 18 additions & 0 deletions groupWith.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Predicate2, Curry2 } from "./utils/types.ts"
import curryN from "./utils/curry_n.ts"
import { slice } from "./slice.ts"

function _groupWith<T>(predicate: Predicate2<T | string>, functor: T[] | string) {
const result: T[][] | string[] = []
const len = functor.length
let i = 0
while(i < len) {
let j = i + 1
while(j < len && predicate(functor[j - 1], functor[j])) j++
result.push(slice(i, j, functor) as (T[] & string))
i = j
}
return result
}

export const groupWith: Curry2<Predicate2, any[] | string, any[][] | string[]> = curryN(2, _groupWith)
13 changes: 13 additions & 0 deletions head.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import { nth } from './nth.ts'

/**
* Returns the first element of the given list or string. In some libraries
* this function is named `first`.
*
* Fae.head(['fi', 'fo', 'fum']); //=> 'fi'
* Fae.head([]); //=> undefined
*
* Fae.head('abc'); //=> 'a'
* Fae.head(''); //=> ''
*/
export const head = nth(0)
56 changes: 56 additions & 0 deletions indexOf.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
import { isNumber } from './utils/is.ts'
import curryN from "./utils/curry_n.ts"
import { Curry2 } from "./utils/types.ts"
import { equals } from './equals.ts'

function _indexOf<T>(value: T, list: T[]) {
switch(typeof value) {
case 'number': {
if(value === 0) {
// handles +0 and -0
const inf = 1 / value
for (let i = 0; i < list.length; i++) {
const x: any = list[i]
if(x === 0 && 1 / x === inf) return i
}
return -1
}
else if(value !== value) {
// handles NaN
for (let i = 0; i < list.length; i++) {
const x: any = list[i]
if(isNaN(x)) return i
}
return -1
}
}
case 'string':
case 'boolean':
case 'function':
case 'undefined':
return list.indexOf(value)

case 'object':
if (value === null) {
return list.indexOf(value)
}
}


let idx = -1
list.forEach((a, i) => idx = equals(value, a) ? i : idx)
return idx
}

/**
* Returns the position of the first occurrence of `value` in `list`, or -1
* if the item is not included in the array. [`Fae.equals`](#equals) is used to
* determine equality.
*
* Fae.indexOf(3, [1,2,3,4]); //=> 2
* Fae.indexOf(10, [1,2,3,4]); //=> -1
* Fae.indexOf(0, [1, 2, 3, 0, -0, NaN]); //=> 3
* Fae.indexOf(-0, [1, 2, 3, 0, -0, NaN]); //=> 4
* Fae.indexOf(NaN, [1, 2, 3, 0, -0, NaN]); //=> 5
*/
export const indexOf: Curry2<any, any[], number> = curryN(2, _indexOf)
4 changes: 4 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ export { all } from './all.ts'
export { allPass } from './allPass.ts'
export { always } from './always.ts'
export { and } from './and.ts'
export { andThen } from './andThen.ts'
export { any } from './any.ts'
export { anyPass } from './anyPass.ts'
export { ap } from './ap.ts'
Expand Down Expand Up @@ -61,8 +62,11 @@ export { findLast } from './findLast.ts'
export { findLastIndex } from './findLastIndex.ts'
export { flip } from './flip.ts'
export { Pair, fromPairs } from './fromPairs.ts'
export { groupWith } from './groupWith.ts'
export { head } from './head.ts'
export { identity } from './identity.ts'
export { inc } from './inc.ts'
export { indexOf } from './indexOf.ts'
export { insert } from './insert.ts'
export { isEmpty } from './isEmpty.ts'
export { join } from './join.ts'
Expand Down
8 changes: 7 additions & 1 deletion nth.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,13 @@ function _nth<T>(index: number, functor: FunctorWithArLk<T> | string) {
else throwFunctorError()

index = index < 0 ? index + f.length : index
return f[index]
return(
f[index]
? f[index]
: isString(functor)
? ''
: f[index]
)
}

/**
Expand Down
16 changes: 16 additions & 0 deletions specs/_async.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@

export function it(fun: Function) {
return async function() {
let done: Function = () => void 0
const p = new Promise(resolve => {
let d = () => resolve()
done = d
})
await fun(done)
await p
}
}

export type Tests = {
[desc: string]: () => Promise<void>
}
6 changes: 6 additions & 0 deletions specs/_run.ts
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,12 @@ async function run() {
}
}
showResults(start, Date.now())

const p = Deno.run({
cmd: ["bash", "./specs/deno_test.sh"],
})

await p.status()
}

await run()
Expand Down
68 changes: 68 additions & 0 deletions specs/andThen.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import { it, Tests } from './_async.ts'
import { describe, it as itS} from "./_describe.ts"
import {
andThen,
compose,
pipe,
inc,
} from '../mod.ts'
import { eq, thr } from "./utils/utils.ts"

const tests: Tests = {
"should invoke then on the promise with the function passed to it": it(
async (done: Function) => {
const p = new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 100)
})
andThen(
function (n) {
eq(n, 1)
done()
},
p
)
}
),

"should flatten promise returning functions": it(
async (done: Function) => {
const incAndWrap = compose(Promise.resolve.bind(Promise), inc)
const asyncAddThree = pipe(incAndWrap, andThen(incAndWrap), andThen(incAndWrap))

andThen((result) => {
eq(result, 4)
done()
})(asyncAddThree(1))
}
),

"should not dependent on a particular promise implementation": it(
async (done: Function) => {
const thennable = {
then: function(f: Function) {
return f(42)
}
}

const f = function(n: number) {
eq(n, 42)
done()
}

andThen(f, thennable)
}
),
}

describe('andThen', () => {
itS('throws a typeError if the then method does not exist', () => {
thr(() => andThen(inc, 1), '`andThen` expected a Promise, received 1')

})
})

for(let desc in tests) {
Deno.test(desc, tests[desc])
}
1 change: 1 addition & 0 deletions specs/deno_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
deno test specs/andThen.spec.ts
40 changes: 40 additions & 0 deletions specs/groupWith.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import { describe, it } from "./_describe.ts"
import { groupWith, equals } from '../mod.ts'
import { eq } from "./utils/utils.ts"

describe('groupWith', () => {

it('should split the list into groups according to the grouping function', () => {
eq(groupWith(equals, [1, 2, 2, 3]), [[1], [2, 2], [3]])
eq(groupWith(equals, [1, 1, 1, 1]), [[1, 1, 1, 1]])
eq(groupWith(equals, [1, 2, 3, 4]), [[1], [2], [3], [4]])
})

it('should split the list into "streaks" testing adjacent elements', () => {
// @ts-ignore
const isConsecutive = function(a, b) { return a + 1 === b; }
eq(groupWith(isConsecutive, []), [])
eq(groupWith(isConsecutive, [4, 3, 2, 1]), [[4], [3], [2], [1]])
eq(groupWith(isConsecutive, [1, 2, 3, 4]), [[1, 2, 3, 4]])
eq(groupWith(isConsecutive, [1, 2, 2, 3]), [[1, 2], [2, 3]])
eq(groupWith(isConsecutive, [1, 2, 9, 3, 4]), [[1, 2], [9], [3, 4]])
})

it('should return an empty array if given an empty array', () => {
eq(groupWith(equals, []), [])
})

// TODO:
// it('can be turned into the original list through concatenation', () => {
// var list = [1, 1, 2, 3, 4, 4, 5, 5]
// eq(R.unnest(groupWith(equals, list)), list)
// eq(R.unnest(groupWith(R.complement(equals), list)), list)
// eq(R.unnest(groupWith(R.T, list)), list)
// eq(R.unnest(groupWith(R.F, list)), list)
// })

it('should also work on strings', () => {
eq(groupWith(equals)('Mississippi'), ['M','i','ss','i','ss','i','pp','i'])
})

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

describe('head', () => {

it('should return the first element of an ordered collection', () => {
eq(head([1, 2, 3]), 1)
eq(head([2, 3]), 2)
eq(head([3]), 3)
eq(head([]), undefined)

eq(head('abc'), 'a')
eq(head('bc'), 'b')
eq(head('c'), 'c')
eq(head(''), '')
})

it('should throw if applied to null or undefined', () => {
// @ts-ignore
thr(() => head(null), 'The functor should be an array like or iterable/iterator')
// @ts-ignore
thr(() => head(undefined), 'The functor should be an array like or iterable/iterator')
})

})
Loading

0 comments on commit a657064

Please sign in to comment.