keep the darkside away: practical functional mixins for lodash/fp to make code more readable, maintainable & composable
Warning: Experimental
- functional programming in javascript has 2 categories: the good stuff..and there's the other stuff :)
_.flow
and_.compose
is good stuff- composition of promises and functions should be hasslefree
- nested ifs/elses and early function returns, invite powers of dark side (see anti-if-campaign)
So..what does code looks like when using this library?
engine.getOrCreateUser = _.flow(
_.either( engine.getUser, engine.createUser ),
_.maybe( _.log("user ok") )
)
engine.init = _.flow(
_.when( getOrCreateUser, _.lensOver( 'user', getOrCreateUser ) ),
_.when( engine.isInited, _.lensOver('inited', => true) ),
_.when( engine.isNotInited, _.error("something went wrong") ),
)
engine.init( _.clone(engine) )
see full example here
this will execute function b only when function a returns false/null/undefined
example: _.either(getUserByEmail,createUserEmail)("[email protected]")
this will execute function fn only when there's input. this comes in handy when its unsure whether the previous function was succesful in a chain/flow/composed function.(){}
example: .flow( getOrCreateUser, maybe(.log("user ok")) )
hipster if statement, only execute function g when function f does not return null/false/undefined
example: _.when( _.isString, console.log )("foo")
improved version of _.flow, which also supports automatic resolving of promises
example: _.flow( new Promise(.....), alert )("[email protected]")
lens over allows i/o for a nested property
example: var updateBar = _.flow( -> 123, _.log ) _.lensOver( "foo.bar", updateBar )({foo:{bar:0}}) // sets 'foo.bar' to 123 (and prints in console)
simple es6 templates for in the browser
example: _.template_es6('${foo}', {foo:"bar"}) // outputs 'bar'
simple way to prefix a function which outputs a string
example: _.error = _.prefix("error: ", _.log)
simple way to postfix a function which outputs a string
example: _.flow( _.get('.length'), _.prefix("items", _.log) )([1, 2, 3])
simple log function (which forwards input to output)
example: _.flow( doFoo, _log, doBar )({input:"foo"})
simple error function (which forwards input to output)
example: _.when( !hasFoo, _.prefix("something went wrong:", _error ) )({input:"foo"})
trigger simply executes a function OR promise, but forwards original input as output. this comes in handy when you don't want to break a flow/chain
example: _.flow( doSomethingWithInput, _.trigger( alert ), doSomethingElseWithInput )({foo:"bar"})
calls cb(data, next) for each element in arr, and continues loop based on next()-calls (last element propagates done()). Perfect to iterate over an array synchronously, while performing async operations inbetween the elements.
example: _.mapAsync([1, 2, 3], alert, (data, next) => next() )