Skip to content

Commit

Permalink
fix 🪲 with prop and propPath and remove safe from core (#145)
Browse files Browse the repository at this point in the history
  • Loading branch information
evilsoft authored Sep 5, 2017
1 parent a149a0c commit 99987fe
Show file tree
Hide file tree
Showing 10 changed files with 65 additions and 64 deletions.
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -582,14 +582,14 @@ flow('string', 100).runWith(data)
#### prop
`crocks/Maybe/prop`
```haskell
prop : (String | Number) -> (Object | Array) -> Maybe a
prop : (String | Number) -> a -> Maybe b
```
If you want some safety around pulling a value out of an Object or Array with a single key or index, you can always reach for `prop`. Well, as long as you are working with non-nested data that is. Just tell `prop` either the key or index you are interested in, and you will get back a function that will take anything and return a `Just` with the wrapped value if the key/index exists. If the key/index does not exist however, you will get back a `Nothing`.

#### propPath
`crocks/Maybe/propPath`
```haskell
propPath : [ String | Number ] -> (Object | Array) -> Maybe a
propPath : [ String | Number ] -> a -> Maybe b
```
While [`prop`](#prop) is good for simple, single-level structures, there may come a time when you have to work with nested POJOs or Arrays. When you run into this situation, just pull in `propPath` and pass it a left-to-right traversal path of keys, indices or a combination of both (gross...but possible). This will kick you back a function that behaves just like [`prop`](#prop). You pass it some data, and it will attempt to resolve your provided path. If the path is valid, it will return the value residing there (`null` included!) in a `Just`. But if at any point that path "breaks" it will give you back a `Nothing`.

Expand Down
11 changes: 8 additions & 3 deletions src/Maybe/prop.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,19 +3,24 @@

const curry = require('../core/curry')
const isDefined = require('../core/isDefined')
const isNil= require('../core/isNil')
const isInteger = require('../core/isInteger')
const isString = require('../core/isString')
const safe = require('../core/safe')
const { Nothing, Just } = require('../core/Maybe')

const lift =
safe(isDefined)
const lift = x =>
isDefined(x) ? Just(x) : Nothing()

// prop : String | Number -> a -> Maybe b
function prop(key, target) {
if(!(isString(key) || isInteger(key))) {
throw new TypeError('prop: String or integer required for first argument')
}

if(isNil(target)) {
return Nothing()
}

return lift(target[key])
}

Expand Down
6 changes: 6 additions & 0 deletions src/Maybe/prop.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -42,5 +42,11 @@ test('prop function', t => {
t.equals(arrBad.option('nothing'), 'nothing', 'returns a Nothing when index is not found')
t.equals(arrNull(arr).option('nothing'), null, 'returns a Just null when index is found and value is null')

const fn =
x => prop('key', x).option('nothing')

t.equals(fn(undefined), 'nothing', 'returns Nothing when data is undefined')
t.equals(fn(null), 'nothing', 'returns Nothing when data is null')

t.end()
})
13 changes: 9 additions & 4 deletions src/Maybe/propPath.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,22 +2,27 @@
/** @author Ian Hofmann-Hicks (evil) */

const Maybe = require('../core/Maybe')
const { Nothing, Just } = Maybe

const curry = require('../core/curry')
const isArray = require('../core/isArray')
const isDefined = require('../core/isDefined')
const isInteger = require('../core/isInteger')
const isNil= require('../core/isNil')
const isString = require('../core/isString')
const isArray = require('../core/isArray')
const safe = require('../core/safe')

const lift =
safe(isDefined)
const lift = x =>
isDefined(x) ? Just(x) : Nothing()

// propPath : [ String | Number ] -> a -> Maybe b
function propPath(keys, target) {
if(!isArray(keys)) {
throw new TypeError('propPath: Array of strings or integers required for first argument')
}

if(isNil(target)) {
return Nothing()
}
return keys.reduce((maybe, key) => {
if(!(isString(key) || isInteger(key))) {
throw new TypeError('propPath: Array of strings or integers required for first argument')
Expand Down
6 changes: 6 additions & 0 deletions src/Maybe/propPath.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,11 @@ test('propPath function', t => {

t.equals(propPath([ 'things', 2 ], mixed).option('nothing'), value, 'allows for traversal with a mixed path on a mixed structure')

const fn =
x => propPath([ 'key' ], x).option('nothing')

t.equals(fn(undefined), 'nothing', 'returns Nothing when data is undefined')
t.equals(fn(null), 'nothing', 'returns Nothing when data is null')

t.end()
})
7 changes: 5 additions & 2 deletions src/Maybe/safe.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
/** @license ISC License (c) copyright 2016 original and current authors */
/** @author Ian Hofmann-Hicks (evil) */

const _safe = require('../core/safe')
const Pred = require('../core/types').proxy('Pred')
const { Nothing, Just } = require('../core/Maybe')
const predOrFunc = require('../core/predOrFunc')

const curry = require('../core/curry')
const isFunction = require('../core/isFunction')
Expand All @@ -14,7 +15,9 @@ function safe(pred, x) {
throw new TypeError('safe: Pred or predicate function required for first argument')
}

return _safe(pred)(x)
return predOrFunc(pred, x)
? Just(x)
: Nothing()
}

module.exports = curry(safe)
28 changes: 28 additions & 0 deletions src/Maybe/safe.spec.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,31 @@ test('safe helper', t => {

t.end()
})

test('safe predicate function', t => {
const pred = x => !!x

const f = safe(pred)

const fResult = f(false).option('nothing')
const tResult = f('just').option('nothing')

t.equals(fResult, 'nothing', 'returns a Nothing when false')
t.equals(tResult, 'just', 'returns a Just when true')

t.end()
})

test('safe Pred', t => {
const pred = Pred(x => !!x)

const f = safe(pred)

const fResult = f(0).option('nothing')
const tResult = f('just').option('nothing')

t.equals(fResult, 'nothing', 'returns a Nothing when false')
t.equals(tResult, 'just', 'returns a Just when true')

t.end()
})
2 changes: 1 addition & 1 deletion src/Maybe/safeLift.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ const compose = require('../core/compose')
const curry = require('../core/curry')
const isFunction = require('../core/isFunction')
const isSameType = require('../core/isSameType')
const safe = require('../core/safe')
const safe = require('./safe')

const map =
fn => m => m.map(fn)
Expand Down
13 changes: 0 additions & 13 deletions src/core/safe.js

This file was deleted.

39 changes: 0 additions & 39 deletions src/core/safe.spec.js

This file was deleted.

0 comments on commit 99987fe

Please sign in to comment.