Skip to content

Commit

Permalink
Merge pull request #24 from Jozty/dev-ch
Browse files Browse the repository at this point in the history
add functions - propEq, propIs, propSatisfies, eqProps, defaultTo, pathOr, propOr
  • Loading branch information
singla-shivam authored Jun 5, 2020
2 parents d879264 + cee0ff5 commit b799838
Show file tree
Hide file tree
Showing 16 changed files with 318 additions and 5 deletions.
20 changes: 20 additions & 0 deletions defaultTo.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { Curry2 } from "./utils/types.ts"
import curryN from "./utils/curry_n.ts"

function _defaultTo(defaultV: any, value: any) {
return value == null || value !== value ? defaultV : value;
}

/**
* Returns the second argument if it is not `null`, `undefined` or `NaN`;
* otherwise the first argument is returned.
*
*
* const defaultTo125 = Fae.defaultTo(125)
*
* defaultTo125(null) //=> 125
* defaultTo125(undefined) //=> 125
* defaultTo125(false) //=> false
* defaultTo125('Fae') //=> 'Fae'
*/
export const defaultTo: Curry2<any, any, any> = curryN(2, _defaultTo)
18 changes: 18 additions & 0 deletions eqProps.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Curry3, Obj } from "./utils/types.ts"
import curryN from "./utils/curry_n.ts"
import { equals } from "./equals.ts"

function _eqProps(prop: string, obj1: Obj, obj2: Obj) {
return equals(obj1[prop], obj2[prop])
}

/**
* Reports whether two objects have the same value, for the specified property.
* Useful as a curried predicate.
*
* const obj1 = { a: 1, b: 2, c: 3, d: 4 }
* const obj2 = { a: 10, b: 20, c: 3, d: 40 }
* Fae.eqProps('a', obj1, obj2) //=> false
* Fae.eqProps('c', obj1, obj2) //=> true
*/
export const eqProps: Curry3<string, Obj, Obj, boolean> = curryN(3, _eqProps)
7 changes: 7 additions & 0 deletions mod.ts
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ export { contains } from './contains.ts'
export { crossProduct } from './crossProduct.ts'
export { curry } from './curry.ts'
export { dec } from './dec.ts'
export { defaultTo } from './defaultTo.ts'
export { dissoc } from './dissoc.ts'
export { dissocPath } from './dissocPath.ts'
export { divide } from './divide.ts'
Expand All @@ -45,6 +46,7 @@ export { dropRepeats } from './dropRepeats.ts'
export { dropRepeatsWith } from './dropRepeatsWith.ts'
export { dropWhile } from './dropWhile.ts'
export { endsWith } from './endsWith.ts'
export { eqProps } from './eqProps.ts'
export { equals } from './equals.ts'
export { filter } from './filter.ts'
export { find } from './find.ts'
Expand Down Expand Up @@ -81,11 +83,16 @@ export { not } from './not.ts'
export { nth } from './nth.ts'
export { over } from './over.ts'
export { path } from './path.ts'
export { pathOr } from './pathOr.ts'
export { paths, Path } from './paths.ts'
export { pipe } from './pipe.ts'
export { prepend } from './prepend.ts'
export { prop } from './prop.ts'
export { propEq } from './propEq.ts'
export { propIs } from './propIs.ts'
export { propOr } from './propOr.ts'
export { props } from './props.ts'
export { propSatisfies } from './propSatisfies.ts'
export { range } from './range.ts'
export { rangeUntil } from './rangeUntil.ts'
export { reduce } from './reduce.ts'
Expand Down
18 changes: 18 additions & 0 deletions pathOr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import { Curry3, Obj } from "./utils/types.ts"
import curryN from "./utils/curry_n.ts"
import { defaultTo } from './defaultTo.ts'
import { path } from './path.ts'

function _pathOr(d: any, p: Array<any>, obj: any) {
return defaultTo(d, path(p, obj))
}

/**
* If the given, non-null object has a value at the given path, returns the
* value at that path. Otherwise returns the provided default value.
*
*
* Fae.pathOr('N/A', ['a', 'b'], {a: {b: 2}}); //=> 2
* Fae.pathOr('N/A', ['a', 'b'], {c: {b: 2}}); //=> "N/A"
*/
export const pathOr: Curry3<any, Array<any>, any, any> = curryN(3, _pathOr)
19 changes: 19 additions & 0 deletions propEq.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import curryN from "./utils/curry_n.ts"
import { Curry3, ObjRec } from "./utils/types.ts"
import { equals } from './equals.ts'

function _propEq(name: string, val: any, obj: ObjRec) {
return equals(val, obj[name])
}

/**
* Returns `true` if the specified object property is equal, to the given value; `false` otherwise.
*
* const shivam = {name: 'shivam', age: 20, hair: 'brown'}
* const shubham = {name: 'shubham', age: 22, hair: 'black'}
* const Krish = {name: 'krish', age: 25, hair: 'black'}
* const students = [shivam, shubham, krish]
* const hasBrownHair = Fae.propEq('hair', 'brown')
* Fae.filter(hasBrownHair, students) //=> [shubham]
*/
export const propEq: Curry3<string, any, ObjRec, boolean> = curryN(3, _propEq)
17 changes: 17 additions & 0 deletions propIs.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import curryN from "./utils/curry_n.ts"
import { Curry3, Obj } from "./utils/types.ts"
import { is } from "./utils/is.ts";

function _propIs(type: string, name: string, obj: Obj) {
return is(obj[name], type)
}

/**
* Returns `true` if the specified object property(must be passed as string) is of the given type;
* `false` otherwise.
*
* Fae.propIs('Number', 'a', {a: 1, y: 2}); //=> true
* Fae.propIs('String', 'a', {a: 'foo'}); //=> true
* Fae.propIs('Number', 'a', {}); //=> false
*/
export const propIs: Curry3<string, string, Obj, boolean> = curryN(3, _propIs)
24 changes: 24 additions & 0 deletions propOr.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import curryN from "./utils/curry_n.ts"
import { Curry3, Obj, ObjRec } from "./utils/types.ts"
import { pathOr } from "./pathOr.ts"
import { Path } from "./paths.ts"

function _propOr(val: any, p: Path, obj: ObjRec | null) {
return pathOr(val, [p], obj)
}

/**
* If the given, non-null object has an own property with the specified name,
* returns the value of that property. Otherwise returns the provided default
* value.
* const alice = {
* name: 'Fae',
* age: 15
* };
* const Great = Fae.prop('GreatLibrary');
* const GreatWithDefault = Fae.propOr('FaeModule', 'GreatLibrary');
*
* Great(Fae); //=> undefined
* GreatWithDefault(Fae); //=> 'FaeModule'
*/
export const propOr: Curry3<any, Path, ObjRec | null, any> = curryN(3, _propOr)
14 changes: 14 additions & 0 deletions propSatisfies.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { ObjRec, Predicate1, Curry3 } from "./utils/types.ts"
import curryN from "./utils/curry_n.ts"

function _propSatisfies(pred: Predicate1, name: string, obj: ObjRec) {
return pred(obj[name]);
}

/**
* Returns `true` if the specified object property satisfies the given
* predicate; `false` otherwise.
*
* Fae.propSatisfies(x => x > 0, 'x', {x: 1, y: 2}); //=> true
*/
export const propSatisfies: Curry3<Predicate1, string, ObjRec, boolean> = curryN(3, _propSatisfies)
16 changes: 16 additions & 0 deletions specs/PropEq.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { describe, it } from "./_describe.ts"
import { propEq } from '../mod.ts'
import { eq } from "./utils/utils.ts"

describe('propEq', () => {

let obj1 = {name: 'shubham', age: 22, hair: 'blue'}
let obj2 = {name: 'Shivam', age: 21, hair: 'black'}

it('should determine property matching a given value for a specific object properly', () => {
eq(propEq('name', 'shubham', obj1), true)
eq(propEq('hair', 'black', obj2), true)
eq(propEq('hair', 'blue', obj2), false)
})

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

describe('defaultTo', () => {

let defaultTo125 = defaultTo(125)

it('should return the default value if input is null, undefined or NaN', () => {
eq(125, defaultTo125(null))
eq(125, defaultTo125(undefined))
eq(125, defaultTo125(NaN))
})

it('should return the input value if it is not null/undefined', () => {
eq('a real value', defaultTo125('a real value'))
})

it('should return the input value even if it is considered falsy', () => {
eq('', defaultTo125(''))
eq(0, defaultTo125(0))
eq(false, defaultTo125(false))
eq([], defaultTo125([]))
})

it('should be called with both arguments directly', () => {
eq(125, defaultTo(125, null))
eq('a real value', defaultTo(125, 'a real value'))
})

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

describe('eqProps', () => {

it('should return true when two objects have the same value for a given property', () => {
eq(eqProps('name', {name: 'shubham', age: 10}, {name: 'shubham', age: 12}), true)
eq(eqProps('name', {name: 'shivam', age: 10}, {name: 'shubham', age: 10}), false)
eq(eqProps('value', {value: 0}, {value: -0}), false)
eq(eqProps('value', {value: -0}, {value: 0}), false)
eq(eqProps('value', {value: NaN}, {value: NaN}), true)
})

})
5 changes: 0 additions & 5 deletions specs/not.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@ import { describe, it, expect } from "./_describe.ts"
import { not } from '../mod.ts'
import { eq } from "./utils/utils.ts"

/**
* @function
* takes an argument and returns its not
*/

describe('not', () => {
it('should be properly declared',() => {
eq(not(true), false)
Expand Down
52 changes: 52 additions & 0 deletions specs/pathOr.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
import { describe, it } from "./_describe.ts"
import { pathOr } from '../mod.ts'
import { eq } from "./utils/utils.ts"

describe('pathOr', () => {

let deepObject = {a: {b: {c: 'c'}}, falseVal: false, nullVal: null, undefinedVal: undefined, arrayVal: ['arr']}

it('should take a path and an object and returns the value at the path or the default value', () => {
let obj = {
a: {
b: {
c: 100,
d: 200
},
e: {
f: [100, 101, 102],
g: 'G'
},
h: 'H'
},
i: 'I',
j: ['J']
}
eq(pathOr('Unknown', ['a', 'b', 'c'], obj), 100)
eq(pathOr('Unknown', [], obj), obj)
eq(pathOr('Unknown', ['a', 'e', 'f', 1], obj), 101)
eq(pathOr('Unknown', ['j', 0], obj), 'J')
eq(pathOr('Unknown', ['j', 1], obj), 'Unknown')
eq(pathOr('Unknown', ['a', 'b', 'c'], null), 'Unknown')
})

it("should get a deep property's value from objects", () => {
eq(pathOr('Unknown', ['a', 'b', 'c'], deepObject), 'c')
eq(pathOr('Unknown', ['a'], deepObject), deepObject.a)
})

it('should return the default value for items not found', () => {
eq(pathOr('Unknown', ['a', 'b', 'foo'], deepObject), 'Unknown')
eq(pathOr('Unknown', ['bar'], deepObject), 'Unknown')
})

it('should return the default value for null/undefined', () => {
eq(pathOr('Unknown', ['toString'], null), 'Unknown')
eq(pathOr('Unknown', ['toString'], undefined), 'Unknown')
})

it('should work with falsy items', () => {
eq(pathOr('Unknown', ['toString'], false), Boolean.prototype.toString)
})

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

describe('propIs', () => {

it('should return true if the specified object property is of the given type', () => {
eq(propIs('Number', 'a', {a: 1, y: 2}), true)
eq(propIs('String', 'a', {a: 'foo'}), true)
eq(propIs('Number', 'a', {}), false)
})

it('Should return false otherwise', () => {
eq(propIs('String', 'ob', {ob: 1}), false)
eq(propIs('String', 'ob', {}), false)
})

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


describe('propOr', () => {

let shubham = {name: 'shubham', age: 23}
let shivam = {age: 99}

let num = propOr('Unknown', 'name')

it('should return a function that fetches the appropriate property', () => {
eq(typeof num, 'function')
eq(num(shubham), 'shubham')
})

it('should return the default value when the property does not exist', () => {
eq(num(shivam), 'Unknown')
})

it('should return the default value when the object is nil', () => {
eq(num(null), 'Unknown')
eq(num(void 0), 'Unknown')
})

it('should use the default when supplied an object with a nil value', () => {
eq(propOr('foo', 'x', {x: null}), 'foo')
eq(propOr('foo', 'x', {x: undefined}), 'foo')
})

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

describe('propSatisfies', () => {

let isPositive = (n: number) => n > 0

it('should return true if the specified object property satisfies the given predicate', () => {
eq(propSatisfies(isPositive, 'x', {x: 1, y: 0}), true)
})

it('should return false otherwise', () => {
eq(propSatisfies(isPositive, 'y', {x: 1, y: 0}), false)
})

})

0 comments on commit b799838

Please sign in to comment.