From bf4f86104ab0438cb07fa61182009564c00d21e0 Mon Sep 17 00:00:00 2001 From: Matt Styles Date: Thu, 23 Mar 2017 06:33:39 +0000 Subject: [PATCH] add patch --- examples/patch/index.js | 52 ++++++++++++++++++++++ packages/raid-addons/spec/patch.test.js | 57 +++++++++++++++++++++++++ packages/raid-addons/src/index.js | 1 + packages/raid-addons/src/patch.js | 24 +++++++++++ 4 files changed, 134 insertions(+) create mode 100644 examples/patch/index.js create mode 100644 packages/raid-addons/spec/patch.test.js create mode 100644 packages/raid-addons/src/patch.js diff --git a/examples/patch/index.js b/examples/patch/index.js new file mode 100644 index 0000000..8c1e6b9 --- /dev/null +++ b/examples/patch/index.js @@ -0,0 +1,52 @@ + +import {render} from 'inferno-dom' + +import {Signal} from 'raid/src' +import patch from 'raid-addons/src/patch' + +import element from '../_common/element' +import Button from '../_common/actionButton' +import {View, Main, Code} from '../_common/layout' + +const signal = new Signal({ + patched: { + foo: 'bar' + } +}) + +const actions = { + 'foo': 'bar' +} + +const dispatch = type => payload => signal.emit({type, payload}) + +const update = (state, event) => { + const {foo} = state + return { + ...state, + foo: foo === 'bar' ? 'quux' : 'bar' + } +} + +const App = ({state}) => { + return ( + +
+ +
+ +
{JSON.stringify(state, null, '  ')}
+
+
+ ) +} + +// signal.register(patch('patched', update)) +signal.register(patch('patched')(update)) + +signal.observe(state => { + render( + , + element + ) +}) diff --git a/packages/raid-addons/spec/patch.test.js b/packages/raid-addons/spec/patch.test.js new file mode 100644 index 0000000..a9c7e2f --- /dev/null +++ b/packages/raid-addons/spec/patch.test.js @@ -0,0 +1,57 @@ + +import {namespace} from './utils' + +import {patch} from '../src' + +const test = namespace(__filename) + +const createState = (key, value) => ({ + foo: 'bar', + [key]: value +}) + +test('Should return a function to be used as an update', t => { + t.plan(3) + + const single = patch('key') + const double = patch('key', () => {}) + const addFn = single(() => {}) + + t.equal(typeof single, 'function', 'Single argument returns a function') + t.equal(typeof double, 'function', 'Two arguments returns a function') + t.equal(typeof addFn, 'function', 'Using fixed arity returns a function') +}) + +test('Should throw if a key is not supplied', t => { + t.plan(1) + + t.throws(patch, 'Key must be supplied') +}) + +test('Should pass through the specified keys value as state', t => { + t.plan(1) + + const key = 'bar' + const value = { + baz: 'quux' + } + const state = createState(key, value) + const update = patch(key, state => { + t.deepEqual(state, value, 'Passes the key through') + }) + + update(state) +}) + +test('Should apply the update to correct key', t => { + t.plan(2) + + const state = createState('bar', {baz: 'quux'}) + const expected = createState('bar', {baz: 'fred'}) + const update = state => ({baz: 'fred'}) + const patched = patch('bar', update) + const fixedArity = patch('bar')(update) + + t.deepEqual(patched(state), expected, 'Changes applied correctly') + t.deepEqual(fixedArity(state), expected, 'Changes applied correctly') +}) diff --git a/packages/raid-addons/src/index.js b/packages/raid-addons/src/index.js index cb12590..b1ca689 100644 --- a/packages/raid-addons/src/index.js +++ b/packages/raid-addons/src/index.js @@ -7,6 +7,7 @@ export {default as hook} from './hook' export {default as safe} from './safe' export {default as squash} from './squash' export {default as sin} from './sin' +export {default as patch} from './patch' // var addons = { // adaptor, diff --git a/packages/raid-addons/src/patch.js b/packages/raid-addons/src/patch.js new file mode 100644 index 0000000..824d50e --- /dev/null +++ b/packages/raid-addons/src/patch.js @@ -0,0 +1,24 @@ + +// Provides selected key to update and applies back to state +const select = (key, update) => (state, event) => ({ + ...state, + [key]: update(state[key], event) +}) + +// Returns a function accepting an update +const createPatch = key => update => select(key, update) + +// Allow fixed arity for easier composition +const patch = (key, update) => { + if (!key) { + throw new Error('[raid:patch] key must be supplied') + } + + if (!update || typeof update !== 'function') { + return createPatch(key) + } + + return select(key, update) +} + +export default patch