Skip to content

Commit

Permalink
add patch
Browse files Browse the repository at this point in the history
  • Loading branch information
mattstyles committed Mar 23, 2017
1 parent c7a48f1 commit bf4f861
Show file tree
Hide file tree
Showing 4 changed files with 134 additions and 0 deletions.
52 changes: 52 additions & 0 deletions examples/patch/index.js
Original file line number Diff line number Diff line change
@@ -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 (
<View>
<Main>
<Button onClick={dispatch(actions.foo)}>Click me</Button>
</Main>
<Code>
<pre>{JSON.stringify(state, null, ' ')}</pre>
</Code>
</View>
)
}

// signal.register(patch('patched', update))
signal.register(patch('patched')(update))

signal.observe(state => {
render(
<App state={state} />,
element
)
})
57 changes: 57 additions & 0 deletions packages/raid-addons/spec/patch.test.js
Original file line number Diff line number Diff line change
@@ -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')
})
1 change: 1 addition & 0 deletions packages/raid-addons/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
24 changes: 24 additions & 0 deletions packages/raid-addons/src/patch.js
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit bf4f861

Please sign in to comment.