Open tunnckoCore opened 8 years ago
new
// letta - co@4 simplest
// voa - co@4 on top of always-done
// merz - similiar to co@4 and voa/letta, on top of always-callback/always-done
// always-promise - executes and returns promise
// always-done - co@4 - handle additional things
// always-callback - on top of letta -> always-done, but callbacks
// always-thunk - similiar to co@3 style, strictly accepts only callback
// coone - co@3
// letta (fn, foo, bar, baz)-> promise.then()
// voa (fn, foo, bar, baz, callback)
// alwa (fn, foo, bar, baz)-> thunk(callback)
//
// alwaysDone (val, foo, bar, baz)-> promise.then()
// coone (val, foo, bar, baz)-> thunk(callback)
// alwaysCallback (val, foo, bar, baz, callback)
//
// alwaysPromise (val)-> fn(foo, bar, baz)-> promise.then()
// alwaysThunk (val)-> fn(foo, bar, baz)-> thunk(callback)
// merz (val)-> fn(foo, bar, baz, callback)
// redolent (fn)-> fn(foo, bar, baz[, callback]) -> promise.then()
//
// alwaysGenerator (val)-> fn*(foo, bar, baz)-> promise.then()
additional descs
// always-done
// always-thunk - thunkify everything
// always-promise - promisify everything
// always-generator - generatorify everything
// always-callback - pass 100% of `async-done`
// then-callback - accepts promise and returns promis with modified `.then`
// make-callback - creates callback api fro sync fn, but throws if not sync
// create-callback - creates callback api for sync fn, but dont throws if async
// handle-callback - accepts promise and callback, return promise
// handle-errors
// handle-arguments - handles `arguments` object and return object with `args` and `cb`
// manage-arguments - similiar to `sliced` and `array-slice`
// bind-arguments - bind context (optional) and multiple arguments to function
// bind-context - bind context to the given function and preserves her name.
// useware-context - passing custom context
// useware - useful for `.use` methods
// merz - pass 100% of `co@4` and adds generators to always-done, changes signature
// benz - adds options and `.series/.parallel` and `.compose` methods
// vez - on top of `benz`, middleware composition at new level
// voa
// voala - testing runner on top of vez/merz/benz
// coone - cpass 100% of `co@3`
// letta - accepts only sync/async/callback functions, executes and return promise
// letta-value - extends `letta` by adding handling of streams, child processes, promises
// redolent - promisify sync/async/callback function
// native-promise - gets native promise or falsey value if it native promise not available
// native-or-another - always get promise, native or bluebird/custom only when needed
// hybridify - classic hybrid, use callback and promise api in same time
// hybridify-all - hybridify objects
temp
function alwaysDone (val) {
var lettaValue = require('letta-value')
if (typeof val === 'function') {
return require('letta').apply(this, arguments).then(lettaValue)
}
return lettaValue(val)
}
function alwaysCallback (val) {
var argz = require('handle-arguments')(arguments)
if (!argz.callback) {
throw new TypeError('always-callback: expect last argument to be callback function')
}
var promise = require('always-done').apply(this, [val].concat(argz.args))
require('then-callback')(promise).then(argz.callback)
}
function alwaysPromise (val) {
var self = this
return function promisify () {
var args = require('sliced')(arguments)
return require('always-done').apply(self || this, [val].concat(args))
}
}
function alwaysGenerator (val) {
var self = this
return function generatorify () {
var ctx = self || this
var args = require('sliced')(arguments)
return function * alwaysGeneratorFunction () {
return require('always-done').apply(this, [val].concat(args))
}
}
}
function alwaysThunk (val) {
var self = this
return function thunkify () {
var ctx = self || this
var args = require('sliced')(arguments)
return function (done) {
var promise = require('always-done').apply(ctx || this, [val].concat(args))
return require('then-callback')(promise).then(done)
}
}
}
function merz (val) {
var self = this
return function () {
var args = require('sliced')(arguments)
require('always-callback').apply(self || this, [val].concat(args))
}
}
function coone (val) {
var self = this
var args = require('sliced')(arguments, 1)
return function (done) {
require('merz').call(self || this, val).apply(self || this, args.concat(done))
}
}
/**
* Follow `Don't Repeat Yourself`.
*
* Handles if given value is Stream, Child Process,
* RX Observable, Error or just a value of sync function
*/
// @todo `letta-value` or `handle-value`
// to handles different values and always returning promise
function lettaValue (val) {
if (isNodeStream(val) || isChildProcess(val)) {
return letta(onStreamEnd, streamExhaust(val))
}
if (val && typeof val.subscribe === 'function') {
if (val.value) return letta(function () {
return val.value
})
return letta(subscribe, val)
}
if (isError(val)) {
return letta(function () {
throw val
})
}
return letta(function () {
return val
})
}
/**
* Callback-style wrapper for `rx.subscribe`
*/
function subscribe (val, each, callback) {
if (typeof val !== 'object' && arguments.length <= 1) {
throw new TypeError('expect `val` to be object / expect atleast 2 arguments')
}
callback = arguments.length === 2 ? each : callback
each = arguments.length === 3 ? each : function noop () {}
val.subscribe(each, callback, function onComplete () {
callback.apply(this, [null].concat(sliced(arguments)))
}.bind(this))
}
and the new way :lollipop: redike, redike-all, updated redolent, plus exampels
// @package `redike`
function redike (fn) {
var Prome = require('native-or-another')(redike.promise)
if (typeof fn !== 'function') {
return Prome.reject(new TypeError('redike expect a function'))
}
// var utils = require('./utils')
var argz = require('handle-arguments')(arguments)
var self = this
argz.args = argz.args.slice(1)
if (argz.callback && !require('is-async-function')(argz.callback)) {
argz.args = argz.args.concat(argz.callback)
}
var promise = new Prome(function prome (resolve, reject) {
var isAsync = require('is-async-function')(fn)
if (isAsync) {
argz.args = argz.args.concat(function cb (err, res) {
if (err) return reject(err)
if (arguments.length > 2) res = require('sliced')(arguments, 1)
resolve(res)
})
}
var syncResult = fn.apply(self, argz.args)
if (!isAsync) {
resolve(syncResult)
}
})
promise.Prome = Prome
promise.___customPromise = Prome.___customPromise
promise.___bluebirdPromise = Prome.___bluebirdPromise
return promise
}
// @package `redike-all`
function redikeAll (val) {
redike.promise = redikeAll.promise
var args = require('sliced')(arguments)
if (typeof val !== 'function') {
return redike.apply(this, [function () {
if (Array.isArray(args) && args.length === 1) {
return args[0]
}
return args
}])
}
return redike.apply(this, args)
}
// @package `redolent`
function redolent (val, Prome) {
var self = this
return function promisifyFn () {
var ctx = self || this
var args = require('sliced')(arguments)
redikeAll.promise = Prome || redolent.promise || promisifyFn.promise
return redikeAll.apply(ctx, [val].concat(args))
}
}
var fs = require('fs')
// redike({a: 'b'}).then(console.log, console.error) // => err: redike expect a function
// redike(123, 'foo', {a: 'b'}).then(console.log, console.error) // => err: redike expect a function
// redike(fs.readFile, './foo.js').then(console.log, console.error) // => Buffer
// redike(fs.readFileSync, './foo.js').then(console.log, console.error) // => Buffer
// redike(fs.readFile, 'not exist').then(console.log, console.error) // => err: ENOENT
// redike(fs.readFileSync, 'not exist').then(console.log, console.error) // => err: ENOENT
// redikeAll({a: 'b'}).then(console.log, console.error) // => {a: 'b'}
// redikeAll(123, 'foo', {a: 'b'}).then(console.log, console.error) // => [123, 'foo', {a: 'b'}]
// redikeAll(fs.readFile, './foo.js').then(console.log, console.error) // => Buffer
// redikeAll(fs.readFileSync, './foo.js').then(console.log, console.error) // => Buffer
// redikeAll(fs.readFile, 'not exist').then(console.log, console.error) // => err: ENOENT
// redikeAll(fs.readFileSync, 'not exist').then(console.log, console.error) // => err: ENOENT
// redolent({a: 'b'})().then(console.log, console.error) // => {a: 'b'}
// redolent({a: 'b'})(234).then(console.log, console.error) // => [{a: 'b'}, 234]
// redolent(123, 'foo', {a: 'b'})().then(console.log, console.error) // => [123, 'foo', {a: 'b'}]
// redolent('bar', 123)(555).then(console.log, console.error) // => ['bar', 123, 555]
// redolent(fs.readFile)('./foo.js').then(console.log, console.error) // => Buffer
// redolent(fs.readFileSync)('./foo.js').then(console.log, console.error) // => Buffer
// redolent(fs.readFile)('not exist').then(console.log, console.error) // => err: ENOENT
// redolent(fs.readFileSync)('not exist').then(console.log, console.error) // => err: ENOENT
.series
, .parallel
, .settleSeries
, .settleParallel
aka hybridables/benz
'use strict'
var fs = require('fs')
var async = require('async')
var letta = require('letta')
var settle = false
async.map([
function test1 () {
return 123
},
function test2 () {
throw new Error('foo')
},
function test3 (cb) {
cb(null, 456)
},
function test4 (cb) {
fs.readFile('packfdsf', cb)
}
], function (fn, next) {
var nextSettle = settle ? function settle (err) {
next(null, err)
} : next
letta(fn, nextSettle).then(function (res) {
next(null, res)
}, nextSettle)
}, function done (err, res) {
console.log('err', err)
console.log('res', res)
})
The New Benz
'use strict'
var control = require('async')
var letta = require('letta')
function Benz (options) {
if (!(this instanceof Benz)) {
return new Benz(options)
}
this.options = typeof options === 'object' ? options : {settle: false}
}
Benz.prototype.compose = function compose (flow) {
if (!flow && typeof flow !== 'string') {
throw new TypeError('benz#compose expect string')
}
var self = this
flow = flow === 'series' ? 'mapSeries' : flow
flow = flow === 'parallel' ? 'map' : flow
if (['mapSeries', 'map'].indexOf(flow) === -1) {
throw new TypeError('benz#compose expect only `series` or `parallel` string')
}
return function factory (val, done) {
var ctx = self || this
if (typeof val === 'function') {
val = [val]
}
control[flow](val, function iterator (fn, next) {
next = self.options.settle ? function settleNext (err) {
next(null, err)
} : next
letta(fn.bind(ctx), next).then(function (res) {
next(null, res)
}, next)
}, done)
return self
}
}
Benz.prototype.series = function series (val, done) {
return this.compose('series')(val, done)
}
Benz.prototype.settleSeries = function settleSeries (val, done) {
this.options.settle = true
return this.compose('series')(val, done)
}
Benz.prototype.parallel = function parallel (val, done) {
return this.compose('parallel')(val, done)
}
Benz.prototype.settleParallel = function settleParallel (val, done) {
this.options.settle = true
return this.compose('parallel')(val, done)
}
test
var fs = require('fs')
var benz = Benz()
// benz.series(function|array|object, done)
// benz.parallel(function|array|object, done)
// benz.settleSeries(function|array|object, done)
// benz.settleParallel(function|array|object, done)
benz.settleSeries([
function test1 () {
return 123
},
function test2 () {
throw new Error('foo')
},
function test3 (cb) {
cb(null, 456)
},
function test4 (cb) {
fs.readFile('packfdsf', cb)
}
], function (err, res) {
console.log('err', err)
console.log('res', res)
})
hybrids redefined as of 4 feb, 2015.
async-control
.iterator
, .compose
, .series
and .parallel
methods/*!
* async-control <https://github.com/hybridables/async-control>
*
* Copyright (c) 2016 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
* Released under the MIT license.
*/
'use strict'
var control = require('async')
var isObject = require('is-extendable')
var delegate = require('delegate-properties')
var methods = {
compose: compose,
series: compose('series'),
parallel: compose('parallel'),
iterator: iterator
}
module.exports = function asyncControl (app) {
if (isObject(app)) {
delegate(app, methods)
return app
}
return module.exports
}
delegate(module.exports, methods)
function compose (flow, fn) {
if (typeof flow !== 'string') {
throw new TypeError('asyncControl.compose expect a string')
}
flow = flow === 'series' ? 'mapSeries' : flow
flow = flow === 'parallel' ? 'map' : flow
if (['mapSeries', 'map'].indexOf(flow) === -1) {
throw new TypeError('async-control.compose: expect only strings: "series" or "parallel".')
}
return factory(flow, this)
}
function factory (flow, self) {
return function _factory_ (val, done) {
if (typeof val === 'function') {
val = [val]
}
if (typeof val !== 'object' && typeof val !== 'function') {
throw new TypeError('async-control methods expect array, object or function')
}
self = self || this
self.iterator = self.iterator.call(self, self)
if (typeof done !== 'function') {
return function doneCallback (done) {
control[flow](val, self.iterator, done)
}
}
control[flow](val, self.iterator, done)
}
}
function iterator (app) {
app = app || this
var opts = typeof app.options === 'object' ? app.options : {}
var settle = typeof app.settle === 'boolean' ? app.settle : false
opts.settle = typeof opts.settle === 'boolean' ? !!opts.settle : !!settle
return function defaultIterator (fn, next) {
function done (err, res) {
if (err instanceof Error) {
err.fn = fn
return opts.settle ? next(null, err) : next(err)
}
next(null, res)
}
var res = null
try {
res = fn.call(app, done)
} catch (err) {
res = err
}
return res instanceof Error ? done(res) : (res ? done(null, res) : null)
}
}
and merz
/*!
* merz <https://github.com/hybridables/merz>
*
* Copyright (c) 2016 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
* Released under the MIT license.
*/
/* jshint asi:true */
'use strict'
var flow = require('./index')
flow.iterator = function iterator (app) {
var opts = typeof app.options === 'object' ? app.options : {}
var settle = typeof app.settle === 'boolean' ? app.settle : false
opts.settle = typeof opts.settle === 'boolean' ? !!opts.settle : !!settle
return function lettaIterator (fn, next) {
require('letta').call(app, fn).then(function (res) {
next.apply(app, [null].concat(res))
}, function (err) {
err.fn = fn
if (opts.settle) {
return next.call(app, null, err)
}
next.call(app, err)
})
}
}
module.exports = flow