Skip to content

Commit

Permalink
Merge pull request #176 from smartprocure/feature/TreeEnhancements
Browse files Browse the repository at this point in the history
Feature/tree enhancements
  • Loading branch information
daedalus28 committed Oct 28, 2017
2 parents 9c18e4f + 4a6a629 commit 0020899
Show file tree
Hide file tree
Showing 8 changed files with 75 additions and 10 deletions.
7 changes: 6 additions & 1 deletion CHANGELOG.md
@@ -1,4 +1,9 @@
# 1.34.1
# 1.35.0
- Add tree `treeLookup`
- Add deep path support to `lensProp`
- Add `unsetOn`

# 1.34.1
- Ignore browser testing errors.
- Add karma JSON reporter.
- Only watch files and record videos/screenshots for the local test.
Expand Down
14 changes: 9 additions & 5 deletions README.md
@@ -1,4 +1,4 @@
<img src='https://user-images.githubusercontent.com/8062245/28718527-796382ac-7374-11e7-98a3-9791223042a4.png' width='200' alt='futil-js'>
<img src='https://user-images.githubusercontent.com/8062245/28718527-796382ac-7374-11e7-98a3-9791223042a4.png' width='200' alt='futil-js'>

---

Expand Down Expand Up @@ -111,7 +111,7 @@ These methods provide alternative orderings that are sometimes more convenient.
The idea of `In` methods is to name them by convention, so when ever you need a method that actually takes the collection first (e.g. a `get` where the data is static but the field is dynamic), you can just add `In` to the end (such as `getIn` which takes the object first)

### `On`s (Immutable False)
`extendOn`, `defaultsOn`, `mergeOn`, `setOn`
`extendOn`, `defaultsOn`, `mergeOn`, `setOn`, `unsetOn`
lodash/fp likes to keep things pure, but sometimes JS can get pretty dirty.
These methods are alternatives for working with data that--for whatever the use case is--needs to be mutable
Any methods that interact with mutable data will use the `On` convention (as it is some action occuring `On` some data)
Expand All @@ -133,7 +133,7 @@ Any method with uncapped iteratee arguments will use the `Indexed` convention.
### dotJoinWith
`filterFunction -> data:array -> result:string` Compacts an array by
the provided function, then joins it with '.'

### repeated
`data:array -> result:array` Returns an array of elements that are repeated in the array.

Expand Down Expand Up @@ -391,7 +391,7 @@ This the first main way you'll generally interact with the lens API

#### lensProp
`lensProp :: string -> object -> { get: () -> T, set: T -> T }`
Creates an object lens for a given property on an object. `.get` returns the value at that path and `set` places a new value at that path
Creates an object lens for a given property on an object. `.get` returns the value at that path and `set` places a new value at that path. Supports deep paths like lodash get/set.


#### lensOf
Expand Down Expand Up @@ -531,6 +531,10 @@ Like `treeToArray`, but accepts a customizer to process the tree nodes before pu
`traverse -> tree -> [treeNodes]`
Returns an array of the tree nodes that can't be traversed into in `pre-order`.

### treeLookup
`(traverse, buildIteratee) -> ([path], tree) -> treeNode`
Looks up a node matching a path, which defaults to lodash `iteratee` but can be customized with buildIteratee.

### tree
`traverse -> {walk, reduce, toArray, toArrayBy, leaves}`
`(traverse, buildIteratee) -> {walk, reduce, toArray, toArrayBy, leaves, lookup}`
Takes a traversal function and returns an object with all of the tree methods pre-applied with the traversal. This is useful if you want to use a few of the tree methods with a custom traversal and can provides a slightly nicer api.
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "futil-js",
"version": "1.34.1",
"version": "1.35.0",
"description": "F(unctional) util(ities). Resistance is futile.",
"main": "lib/futil-js.js",
"scripts": {
Expand Down
2 changes: 2 additions & 0 deletions src/conversion.js
Expand Up @@ -18,6 +18,8 @@ export const extendOn = _.extend.convert(mutable)
export const defaultsOn = _.defaults.convert(mutable)
export const mergeOn = _.merge.convert(mutable)
export const setOn = _.set.convert(mutable)
// Curry required until https://github.com/lodash/lodash/issues/3440 is resolved
export let unsetOn = _.curryN(2, _.unset.convert({immutable: false}))

// This reduce based version is easier to maintain but requires calling `F.inversions.fn` instead of `F.fn`
const inversionList = ['get', 'pick', 'includes']
Expand Down
6 changes: 4 additions & 2 deletions src/lens.js
@@ -1,4 +1,5 @@
import _ from 'lodash/fp'
import {setOn} from './conversion'

// Stubs
export let functionLens = val => (...x) => {
Expand All @@ -22,9 +23,10 @@ export let objToFn = lens => (...values) =>

// Lens Construction
export let lensProp = (field, source) => ({
get: () => source[field],
get: () => _.get(field, source),//source[field],
set: value => {
source[field] = value
setOn(field, value, source)
// source[field] = value
},
})

Expand Down
7 changes: 6 additions & 1 deletion src/tree.js
Expand Up @@ -33,10 +33,15 @@ export let treeToArray = (next = traverse) => treeToArrayBy(next)(x => x)
export let leaves = (next = traverse) =>
_.flow(treeToArray(next), _.reject(next))

export let tree = (next = traverse) => ({
export let treeLookup = (next = traverse, buildIteratee = _.identity) => (path, tree) =>
_.reduce((tree, path) => _.find(buildIteratee(path), next(tree)), tree, path)


export let tree = (next = traverse, buildIteratee = _.identity) => ({
walk: walk(next),
reduce: reduceTree(next),
toArrayBy: treeToArrayBy(next),
toArray: treeToArray(next),
leaves: leaves(next),
lookup: treeLookup(next, buildIteratee)
})
10 changes: 10 additions & 0 deletions test/lens.spec.js
Expand Up @@ -42,6 +42,16 @@ describe('Lens Functions', () => {
l.set(5)
expect(l.get()).to.equal(5)
})
it('lensProp deep', () => {
let l = f.lensProp('x.a', {
x: {
a: 1
},
})
expect(l.get()).to.equal(1)
l.set(5)
expect(l.get()).to.equal(5)
})
it('lensOf', () => {
let l = f.lensOf({
a: 1,
Expand Down
37 changes: 37 additions & 0 deletions test/tree.spec.js
Expand Up @@ -131,4 +131,41 @@ describe('Tree Functions', () => {
let tree = f.tree()
expect(tree.toArray(x)).to.deep.equal([x, x.a, x.b, x.b.c])
})
it('lookup', () => {
let x = {
a: 1,
items: [{
a: 2,
items: [{
a: 3
}, {
a: 4,
b: 4
}]
}, {
a: 5
}]
}
let tree = f.tree(x => x.items)

expect(tree.lookup([{a:2}, {a:4}], x)).to.deep.equal(x.items[0].items[1])
})
it('lookup with path', () => {
let x = {
a: '1',
items: [{
a: '2',
items: [{
a: '3'
}, {
a: '4',
b: 4
}]
}, {
a: '5'
}]
}
let tree = f.tree(x => x.items, a => ({a}))
expect(tree.lookup(['2', '4'], x)).to.deep.equal(x.items[0].items[1])
})
})

0 comments on commit 0020899

Please sign in to comment.