From 750200df7694bcff1cae18aaaffa8931253d4e3d Mon Sep 17 00:00:00 2001 From: Aaron Jensen Date: Tue, 4 Aug 2015 23:36:40 -0700 Subject: [PATCH] Add u.if --- CHANGELOG.md | 1 + README.md | 16 ++++++++++++++++ lib/if.js | 16 ++++++++++++++++ lib/{updateIn.js => in.js} | 0 lib/index.js | 6 ++++-- test/freeze-spec.js | 18 +++++++++--------- test/if-spec.js | 36 ++++++++++++++++++++++++++++++++++++ test/in-spec.js | 12 ++++++------ test/updeep-spec.js | 1 + 9 files changed, 89 insertions(+), 17 deletions(-) create mode 100644 lib/if.js rename lib/{updateIn.js => in.js} (100%) create mode 100644 test/if-spec.js diff --git a/CHANGELOG.md b/CHANGELOG.md index d153fce..a95a4ad 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,7 @@ # Change Log ## [unreleased] +* Add `u.if` to conditionally update objects. ## [0.3.1] * Actually expose `u.in`. diff --git a/README.md b/README.md index 9e7c272..734c800 100644 --- a/README.md +++ b/README.md @@ -128,6 +128,22 @@ u({ // => { x: { a: { b: 3 } } }; ``` +### `u.if(predicate(, updates)(, object))` + +Apply updates only if `predicate` is truthy or, if `predicate` is a function, +if it evaluates to truthy when called with `object`. + +```js +var obj = { a: 2 }; +function isEven(x) { return x % 2 === 0; } +function inc(x) { return x + 1; } + +u({ + a: u.if(isEven, inc), +}, obj); +// => { a: 3 } +``` + ### `u.omit(predicate(, object))` Remove properties. See [`_.omit`](https://lodash.com/docs#omit). diff --git a/lib/if.js b/lib/if.js new file mode 100644 index 0000000..8a565b0 --- /dev/null +++ b/lib/if.js @@ -0,0 +1,16 @@ +import curry from 'lodash/function/curry'; +import update from './update'; + +function updateIf(predicate, updates, object) { + const test = typeof predicate === 'function' ? + predicate(object) : + predicate; + + if (!test) { + return object; + } + + return update(updates, object); +} + +export default curry(updateIf); diff --git a/lib/updateIn.js b/lib/in.js similarity index 100% rename from lib/updateIn.js rename to lib/in.js diff --git a/lib/index.js b/lib/index.js index 53f5ffe..45da618 100644 --- a/lib/index.js +++ b/lib/index.js @@ -1,5 +1,6 @@ import update from './update'; -import updateIn from './updateIn'; +import _in from './in'; +import _if from './if'; import omit from './omit'; import reject from './reject'; import withDefault from './withDefault'; @@ -12,7 +13,8 @@ function updateAndFreeze(updates, obj) { const updeep = curry(updateAndFreeze); -updeep.in = updateIn; +updeep.if = _if; +updeep.in = _in; updeep.freeze = freeze; updeep.omit = omit; updeep.reject = reject; diff --git a/test/freeze-spec.js b/test/freeze-spec.js index 1d84b6a..7f12721 100644 --- a/test/freeze-spec.js +++ b/test/freeze-spec.js @@ -1,5 +1,5 @@ import { expect } from 'chai'; -import freeze from '../lib/freeze'; +import u from '../lib'; describe('u.freeze', () => { afterEach(() => { @@ -8,21 +8,21 @@ describe('u.freeze', () => { it('freezes objects', () => { const obj = {}; - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj)).to.be.true; }); it('freezes nested objects', () => { const obj = { foo: { bar: 3 } }; - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj.foo)).to.be.true; }); it('freezes nested arrays', () => { const obj = [[0]]; - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj)).to.be.true; expect(Object.isFrozen(obj[0])).to.be.true; @@ -30,7 +30,7 @@ describe('u.freeze', () => { it('ignores functions', () => { const obj = { foo: () => 1 }; - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj.foo)).to.be.false; }); @@ -38,7 +38,7 @@ describe('u.freeze', () => { it('does not freeze children if the parent is already frozen', () => { const obj = { foo: {} }; Object.freeze(obj); - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj.foo)).to.be.false; }); @@ -46,20 +46,20 @@ describe('u.freeze', () => { it('does not freeze in production', () => { process.env.NODE_ENV = 'production'; const obj = {}; - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj)).to.be.false; }); it('handles null objects', () => { const obj = { foo: null }; - freeze(obj); + u.freeze(obj); expect(Object.isFrozen(obj)).to.be.true; }); it('returns the same object', () => { const obj = {}; - const result = freeze(obj); + const result = u.freeze(obj); expect(result).to.equal(obj); }); }); diff --git a/test/if-spec.js b/test/if-spec.js new file mode 100644 index 0000000..194a976 --- /dev/null +++ b/test/if-spec.js @@ -0,0 +1,36 @@ +import { expect } from 'chai'; +import u from '../lib'; + +describe('u.if', () => { + it('does not update if the predicate is false', () => { + const obj = { a: 0 }; + const result = u.if(false, { b: 1 }, obj); + expect(result).to.eql(obj); + }); + + it('does update if the predicate is true', () => { + const obj = { a: 0 }; + const result = u.if(true, { b: 1 }, obj); + expect(result).to.eql({ a: 0, b: 1 }); + }); + + it('will use the result of a function passed as a predicate', () => { + const obj = { a: 0 }; + const aIsThree = x => x.a === 3; + const result = u.if(aIsThree, { b: 1 }, obj); + + expect(result).to.eql({ a: 0 }); + }); + + it('can be partially applied', () => { + const obj = { a: 2 }; + const isEven = x => x % 2 === 0; + const inc = x => x + 1; + + const result = u({ + a: u.if(isEven, inc), + }, obj); + + expect(result).to.eql({ a: 3 }); + }); +}); diff --git a/test/in-spec.js b/test/in-spec.js index 96cc4cb..f54e495 100644 --- a/test/in-spec.js +++ b/test/in-spec.js @@ -1,35 +1,35 @@ import { expect } from 'chai'; -import updateIn from '../lib/updateIn'; +import u from '../lib'; describe('u.in', () => { it('can update a single path described with a string', () => { const obj = { a: { b: 0 } }; - const result = updateIn('a.b', 3, obj); + const result = u.in('a.b', 3, obj); expect(result).to.eql({ a: { b: 3 } }); }); it('can update a single path described with a string with a function', () => { const inc = x => x + 1; const obj = { a: { b: 0 } }; - const result = updateIn('a.b', inc, obj); + const result = u.in('a.b', inc, obj); expect(result).to.eql({ a: { b: 1 } }); }); it('can update a single path described with an array', () => { const obj = { a: { b: 0 } }; - const result = updateIn(['a', 'b'], 3, obj); + const result = u.in(['a', 'b'], 3, obj); expect(result).to.eql({ a: { b: 3 } }); }); it('can update arrays', () => { const obj = { a: [0, 0, 0] }; - const result = updateIn('a.1', 3, obj); + const result = u.in('a.1', 3, obj); expect(result).to.eql({ a: [0, 3, 0] }); }); it('can be partially applied', () => { const obj = { a: { b: 0 } }; - const result = updateIn('a.b')(3)(obj); + const result = u.in('a.b')(3)(obj); expect(result).to.eql({ a: { b: 3 } }); }); }); diff --git a/test/updeep-spec.js b/test/updeep-spec.js index a1e5cdf..c50383d 100644 --- a/test/updeep-spec.js +++ b/test/updeep-spec.js @@ -116,6 +116,7 @@ describe('updeep', () => { it('has additional functions', () => { expect(u.freeze).to.be.a('function'); + expect(u.if).to.be.a('function'); expect(u.in).to.be.a('function'); expect(u.omit).to.be.a('function'); expect(u.withDefault).to.be.a('function');