Skip to content

Commit

Permalink
Merge pull request #246 from goatslacker/functional-tools
Browse files Browse the repository at this point in the history
Functional tools
  • Loading branch information
goatslacker committed May 30, 2015
2 parents e50047c + 8d5aa29 commit e3564d6
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 0 deletions.
48 changes: 48 additions & 0 deletions src/utils/fp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
const { push } = Array.prototype

// Disabling no-shadow so we can sanely curry
/*eslint-disable no-shadow*/
export function map(fn, stores) {
return stores
? stores.map(store => fn(store.getState()))
: stores => map(fn, stores)
}

export function filter(fn, stores) {
return stores
? stores.filter(store => fn(store.getState()))
: stores => filter(fn, stores)
}

export function reduce(fn, stores, acc = {}) {
return stores
? stores.reduce((acc, store) => fn(acc, store.getState()), acc)
: stores => reduce(fn, stores)
}

export function flatMap(fn, stores) {
if (!stores) return (stores) => flatMap(fn, stores)

return stores.reduce((result, store) => {
let value = fn(store.getState())
if (Array.isArray(value)) {
push.apply(result, value)
} else {
result.push(value)
}
return result
}, [])
}

export function zipWith(fn, a, b) {
if (!a && !b) {
return (a, b) => zipWith(fn, a, b)
}

const length = Math.min(a.length, b.length)
const result = Array(length)
for (let i = 0; i < length; i += 1) {
result[i] = fn(a[i].getState(), b[i].getState())
}
return result
}
102 changes: 102 additions & 0 deletions test/functional-tools-test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import { assert } from 'chai'
import Alt from '../'
import { createStore } from '../utils/decorators'
import { map, filter, reduce, flatMap, zipWith } from '../utils/fp'

const alt = new Alt()

@createStore(alt)
class Store1 {
constructor() {
this.a = 1
this.num = 1
this.arr = [1, 2, 3]
}
}

@createStore(alt)
class Store2 {
constructor() {
this.b = 2
this.num = 2
this.arr = [4, 5, 6]
}
}

@createStore(alt)
class Store3 {
constructor() {
this.c = 3
this.num = 3
this.arr = [7, 8, 9]
}
}

const collection = [Store1, Store2, Store3]

export default {
'functional tools': {
'currying'() {
const filterTwo = filter((state) => state.num !== 2)
assert.isFunction(filterTwo)
assert.isArray(filterTwo(collection))

const mapSquare = map((state) => state.num * state.num)
assert.isFunction(mapSquare)
assert.isArray(mapSquare(collection))

const replaceState = reduce((state, nextState) => nextState)
assert.isFunction(replaceState)
assert.isObject(replaceState(collection))

const flatten = flatMap(state => state.arr)
assert.isFunction(flatten)
assert.isArray(flatten(collection))

const zip = zipWith(state => state)
assert.isFunction(zip)
assert.isArray(zip(collection, collection))
},

'map'() {
const value = map((state) => {
return state.num * 2
}, collection)

assert.deepEqual(value, [2, 4, 6])
},

'filter'() {
const value = filter((state) => {
return state.num === 2
}, collection)

assert(value[0] === Store2)
},

'reduce'() {
const value = reduce((n, nextState) => {
return n + nextState.num
}, collection, 0)

assert(value === 6)
},

'zipWith'() {
const value = zipWith((a, b) => {
return a.arr.concat(b.arr).reduce((n, x) => n + x, 0)
}, [Store1], [Store2])

assert(value[0] === 21)
},

'flatMap'() {
const value = flatMap((state) => {
return state.num === 2
? state.num
: state.arr
}, collection)
assert.deepEqual(value, [1, 2, 3, 2, 7, 8, 9])
},
}
}

0 comments on commit e3564d6

Please sign in to comment.