Skip to content

Commit

Permalink
feat(Modules): Add lens along with assocPath
Browse files Browse the repository at this point in the history
  • Loading branch information
beardedtim committed Feb 20, 2018
1 parent 19560ed commit fcfaec6
Show file tree
Hide file tree
Showing 15 changed files with 228 additions and 25 deletions.
4 changes: 2 additions & 2 deletions __tests__/modules/assoc.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ describe('assoc', () => {
const key = 'name'
const value = {}
const obj = { name: 'John' }
const result = assoc(value, key, obj)
const result = assoc(key, value, obj)

expect(result).toEqual({
name: value
Expand All @@ -16,7 +16,7 @@ describe('assoc', () => {
const key = 'name'
const value = {}
const obj = { name: 'John' }
const result = assoc(value)(key)(obj)
const result = assoc(key)(value)(obj)

expect(result).toEqual({
name: value
Expand Down
29 changes: 29 additions & 0 deletions __tests__/modules/assocPath.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import assocPath from '../../modules/assocPath'

describe('Associate Path', () => {
test('associates a value to a nested path', () => {
const data = {
a: {
b: {
c: 1
}
},
d: 1
}

const path = ['a', 'b', 'c']
const value = 2
const expected = {
a: {
b: {
c: 2
}
},
d: 1
}

const actual = assocPath(path, value, data)

expect(actual).toEqual(expected)
})
})
27 changes: 27 additions & 0 deletions __tests__/modules/over.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import over from '../../modules/over'
import lensProp from '../../modules/lensProp'

describe('Over', () => {
test('It sets the value at the given lens by applying the given function', () => {
const data = {
name: 'Tim',
age: 29
}

const nameLens = lensProp('name')

const setName = name => {
expect(name).toBe('Tim')
return 'John'
}

const expected = {
name: 'John',
age: 29
}

const actual = over(nameLens, setName, data)

expect(actual).toEqual(expected)
})
})
22 changes: 22 additions & 0 deletions __tests__/modules/set.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import set from '../../modules/set'
import lensProp from '../../modules/lensProp'

describe('Set', () => {
test('It sets the given value on the given lens in the given data', () => {
const data = {
name: 'Tim',
age: 29
}

const nameLens = lensProp('name')

const expected = {
name: 'John',
age: 29
}

const actual = set(nameLens, 'John', data)

expect(actual).toEqual(expected)
})
})
17 changes: 17 additions & 0 deletions __tests__/modules/view.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import view from '../../modules/view'
import lensProp from '../../modules/lensProp'

describe('View', () => {
test('It returns the value at the lens', () => {
const data = {
name: 'Tim',
age: 29
}

const nameLens = lensProp('name')
const expected = 'Tim'
const actual = view(nameLens, data)

expect(actual).toBe(expected)
})
})
4 changes: 2 additions & 2 deletions modules/assoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,12 +8,12 @@ import curry from './curry'
* assoc(1, 'age', { age: 2, name: 'Tim' }) === { age: 1, name: 'Tim' }
*
*
* @param {*} value - The value to associate
* @param {string} key - The key to associate
* @param {*} value - The value to associate
* @param {Object} obj - The structure to associate with
* @return {Object}
*/
const assoc = (value, key, obj) => {
const assoc = (key, value, obj) => {
let result = {}

for (let k in obj) {
Expand Down
35 changes: 35 additions & 0 deletions modules/assocPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
import curry from './curry'
import clone from './clone'
import cloneType from './cloneType'
import assoc from './assoc'
import prop from './prop'

/**
* Associates a value at a path
*
* @example
*
* assocPath(['profile', 'age'], 30, { profile: { age: 29 } } ) === { profile: { age: 30 } }
*
*
* @param {Array<string|number>} key - The path to associate
* @param {*} value - The value to associate
* @param {Object} obj - The structure to associate with
* @return {Object}
*/
export const assocPath = (targetPath, value, data) => {
// Ensure we are not mutating anything
const path = targetPath.slice()

// If we are at the end of our recursion
if (path.length < 2) {
return assoc(targetPath.shift(), value, data)
}

const key = path.shift()

// Associate the top key with the recursive result
return assoc(key, assocPath(path, value, prop(key, data)), data)
}

export default curry(assocPath)
7 changes: 7 additions & 0 deletions modules/cloneType.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export const cloneType = base => {
if (Array.isArray(base)) {
return []
}

return {}
}
14 changes: 14 additions & 0 deletions modules/lens.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import curry from './curry'

/**
* A way to get and set values in a data structure
*
* @param {function(any) => any} get
* @param {function(any, a) => a} set
*/
export const lens = (get, set) => ({
get,
set
})

export default curry(lens)
14 changes: 14 additions & 0 deletions modules/lensPath.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import curry from './curry'
import path from './path'
import lens from './lens'
import assocPath from './assocPath'

/**
* A way to create a lens for a given path
*
* @param {Array<string|number>} keys - The path to the data we care about
* @returns {Lens} - A lens to the Path
*/
export const lensPath = keys => lens(path(keys), assocPath(keys))

export default curry(lensPath)
12 changes: 12 additions & 0 deletions modules/lensProp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import curry from './curry'
import lensPath from './lensPath'

/**
* Creates a lens at a given path
*
* @param {string|number} key - The key to associate this lens with
* @return {Lens}
*/
export const lensProp = key => lensPath([key])

export default curry(lensProp)
15 changes: 15 additions & 0 deletions modules/over.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import curry from './curry'

/**
* A way to set a value on a lens via a function
* The function gets passed the value at the key along with the
* data structure
*
* @param {Lens} lens - The lens to the value to set
* @param {function(*, *) => *} fn - A function to immutably create a new value
* @param {*} data - The data to look in
* @return {*}
*/
export const over = (lens, fn, data) => lens.set(fn(lens.get(data)), data)

export default curry(over)
13 changes: 13 additions & 0 deletions modules/set.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
import curry from './curry'

/**
* Sets the given value at the given lens
*
* @param {Lens} lens - The lens to the value
* @param {*} value - The value to set at the lens
* @param {*} data - The data structure to look in
* @return {*} - The data with the lens set
*/
export const set = (lens, value, data) => lens.set(value, data)

export default curry(set)
12 changes: 12 additions & 0 deletions modules/view.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import curry from './curry'

/**
* A way to actually view the value
*
* @param {Lens} lens - The lens to the data
* @param {*} data - The data structure to look in
* @return {*}
*/
export const view = (lens, data) => lens.get(data)

export default curry(view)
28 changes: 7 additions & 21 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -1511,7 +1511,7 @@ debug@^3.0.1, debug@^3.1.0:
dependencies:
ms "2.0.0"

debuglog@*, debuglog@^1.0.1:
debuglog@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"

Expand Down Expand Up @@ -2866,7 +2866,7 @@ import-lazy@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/import-lazy/-/import-lazy-2.1.0.tgz#05698e3d45c88e8d7e9d92cb0584e77f096f3e43"

imurmurhash@*, imurmurhash@^0.1.4:
imurmurhash@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/imurmurhash/-/imurmurhash-0.1.4.tgz#9218b9b2b928a238b13dc4fb6b6d576f231453ea"

Expand Down Expand Up @@ -3765,25 +3765,17 @@ lodash._basecopy@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz#8da0e6a876cf344c0ad8a54882111dd3c5c7ca36"

lodash._baseindexof@*:
version "3.1.0"
resolved "https://registry.yarnpkg.com/lodash._baseindexof/-/lodash._baseindexof-3.1.0.tgz#fe52b53a1c6761e42618d654e4a25789ed61822c"

lodash._baseuniq@~4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash._baseuniq/-/lodash._baseuniq-4.6.0.tgz#0ebb44e456814af7905c6212fa2c9b2d51b841e8"
dependencies:
lodash._createset "~4.0.0"
lodash._root "~3.0.0"

lodash._bindcallback@*, lodash._bindcallback@^3.0.0:
lodash._bindcallback@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/lodash._bindcallback/-/lodash._bindcallback-3.0.1.tgz#e531c27644cf8b57a99e17ed95b35c748789392e"

lodash._cacheindexof@*:
version "3.0.2"
resolved "https://registry.yarnpkg.com/lodash._cacheindexof/-/lodash._cacheindexof-3.0.2.tgz#3dc69ac82498d2ee5e3ce56091bafd2adc7bde92"

lodash._createassigner@^3.0.0:
version "3.1.1"
resolved "https://registry.yarnpkg.com/lodash._createassigner/-/lodash._createassigner-3.1.1.tgz#838a5bae2fdaca63ac22dee8e19fa4e6d6970b11"
Expand All @@ -3792,17 +3784,11 @@ lodash._createassigner@^3.0.0:
lodash._isiterateecall "^3.0.0"
lodash.restparam "^3.0.0"

lodash._createcache@*:
version "3.1.2"
resolved "https://registry.yarnpkg.com/lodash._createcache/-/lodash._createcache-3.1.2.tgz#56d6a064017625e79ebca6b8018e17440bdcf093"
dependencies:
lodash._getnative "^3.0.0"

lodash._createset@~4.0.0:
version "4.0.3"
resolved "https://registry.yarnpkg.com/lodash._createset/-/lodash._createset-4.0.3.tgz#0f4659fbb09d75194fa9e2b88a6644d363c9fe26"

lodash._getnative@*, lodash._getnative@^3.0.0:
lodash._getnative@^3.0.0:
version "3.9.1"
resolved "https://registry.yarnpkg.com/lodash._getnative/-/lodash._getnative-3.9.1.tgz#570bc7dede46d61cdcde687d65d3eecbaa3aaff5"

Expand Down Expand Up @@ -3862,7 +3848,7 @@ lodash.merge@^4.6.0:
version "4.6.0"
resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.0.tgz#69884ba144ac33fe699737a6086deffadd0f89c5"

lodash.restparam@*, lodash.restparam@^3.0.0:
lodash.restparam@^3.0.0:
version "3.6.1"
resolved "https://registry.yarnpkg.com/lodash.restparam/-/lodash.restparam-3.6.1.tgz#936a4e309ef330a7645ed4145986c85ae5b20805"

Expand Down Expand Up @@ -5138,7 +5124,7 @@ readable-stream@~2.0.5:
string_decoder "~0.10.x"
util-deprecate "~1.0.1"

readdir-scoped-modules@*, readdir-scoped-modules@^1.0.0:
readdir-scoped-modules@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/readdir-scoped-modules/-/readdir-scoped-modules-1.0.2.tgz#9fafa37d286be5d92cbaebdee030dc9b5f406747"
dependencies:
Expand Down Expand Up @@ -6217,7 +6203,7 @@ uuid@^3.0.0, uuid@^3.1.0, uuid@~3.1.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.1.0.tgz#3dd3d3e790abc24d7b0d3a034ffababe28ebbc04"

validate-npm-package-license@*, validate-npm-package-license@^3.0.1:
validate-npm-package-license@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/validate-npm-package-license/-/validate-npm-package-license-3.0.1.tgz#2804babe712ad3379459acfbe24746ab2c303fbc"
dependencies:
Expand Down

0 comments on commit fcfaec6

Please sign in to comment.