tunnckoCore / blankr

:heart: tasks, todos, ideas, streaks, WIP, etc
https://i.am.charlike.online
4 stars 1 forks source link

boom #39

Closed tunnckoCore closed 9 years ago

tunnckoCore commented 9 years ago

Berck and Kock, almost ready


'use strict'

var co = require('co')
var bach = require('bach')
var assert = require('assert')
var isGenFn = require('is-es6-generators').fn

function Berck (context) {
  if (!(this instanceof Berck)) {
    return new Berck(context)
  }

  this.ctx = context || {}
  this.fns = []
  return this
}

Berck.prototype.use = function (fn) {
  if (fn instanceof Berck) {
    return this.use(fn.fns)
  }

  if (Array.isArray(fn)) {
    var len = fn.length
    var i = 0

    while (i < len) {
      this.use(fn[i++])
    }
    return this
  }
  assert(typeof fn === 'function', 'middleware should be function')
  if (isGenFn(fn)) {
    fn = co.wrap(fn)
  }
  this.fns.push(fn.bind(this.ctx))
  return this
}

Berck.prototype.series = function (callback) {
  bach.series(this.fns)(callback)
}
Berck.prototype.parallel = function (callback) {
  bach.parallel(this.fns)(callback)
}
Berck.prototype.settleSeries = function (callback) {
  bach.settleSeries(this.fns)(callback)
}
Berck.prototype.parallelSeries = function (callback) {
  bach.parallelSeries(this.fns)(callback)
}

var fs = require('fs')
var mzfs = require('mz/fs')
var thunky = require('always-thunk')
var readFile = thunky(fs.readFile)

// var app = new Berck({foo: 'bar'})

// app
// .use(function callbackFn (next) {
//   console.log(this.foo)
//   next(null, 1)
// })
// .use(function callbackThunk (next) {
//   console.log(this.foo)
//   readFile('./pkg.json', 'utf8')(next)
// })
// .use(function promiseFn () {
//   console.log(this.foo)
//   return Promise.resolve(123)
// })
// .use(function * promiseGen () {
//   console.log(this.foo)
//   return yield mzfs.readFile('./pkg.json', 'utf8')
// })
// .use(function * genThunk () {
//   console.log(this.foo)
//   return yield readFile('./pkg.json', 'utf8')
// })
// .series(function (err, res) {
//   console.log(err, res)
// })

var handleCallback = require('handle-callback')
var handleArguments = require('handle-arguments')
var alwaysPromise = require('always-promise')
var asyncDone = require('async-done')

function bindArray (fn, thisArg, args) {
  return fn.bind.apply(fn, [thisArg].concat(args))
}
function kock (fn) {
  return function () {
    var argz = handleArguments(arguments)
    var _fnc = isGenFn(fn) ? co.wrap(fn) : fn
    var func = bindArray(_fnc, this, argz.args)

    var promise = alwaysPromise(asyncDone)(func)

    if (argz.callback) {
      promise = handleCallback(promise, argz.callback)
    }
    return promise
  }
}

// kock(function callbackFn (fp, next) {
//   return fs.readFile(fp, 'utf8', next)
// })('./pkg.json', console.log)

// kock(function callbackThunk (fp, next) {
//   readFile(fp, 'utf8')(next)
// })('./pkg.json', console.log)

// kock(function promiseFn (val) {
//   return Promise.resolve(123 + val)
// })(123, console.log) //=> 246

// kock(function * promiseGen (fp, next) {
//   return yield mzfs.readFile(fp, 'utf8')
// })('./pkg.json', console.log)

kock(function * genThunk (fp, next) {
  return yield readFile(fp, 'utf8')
})('./pkg.json', function (err, res) {
  console.log('callback:', err, res)
})
.then(function (res) {
  console.log('promise:', res)
})
.catch(function (res) {
  console.log('promise:', res)
})
tunnckoCore commented 9 years ago

updates: NOW BOTH ARE ABSOLUTELY ROBUST AND AWESOME


'use strict'

var co = require('co')
var assert = require('assert')
var nal = require('now-and-later')
var extend = require('extend-shallow')
var asyncDone = require('async-done')
var handleArguments = require('handle-arguments')
var isGenFn = require('is-es6-generators').fn

function Berck (context) {
  if (!(this instanceof Berck)) {
    return new Berck(context)
  }

  this.ctx = context || {}
  this.fns = []
  return this
}

Berck.prototype.use = function (fn) {
  if (fn instanceof Berck) {
    return this.use(fn.fns)
  }

  if (Array.isArray(fn)) {
    var len = fn.length
    var i = 0

    while (i < len) {
      this.use(fn[i++])
    }
    return this
  }
  assert(typeof fn === 'function', 'middleware should be function')

  this.fns.push(fn)
  return this
}
function run (method) {
  return function () {
    var argz = handleArguments(arguments)
    var ctx = this.ctx

    argz.args.forEach(function (arg) {
      if (!Array.isArray(arg) && typeof arg === 'object') {
        ctx = extend({}, ctx, arg)
      }
    })
    nal[method](this.fns, function (fn, next) {
      if (isGenFn(fn)) {
        fn = co.wrap(fn)
      }
      fn = fn.bind(ctx)
      asyncDone(fn, next)
    }, {}, argz.callback)
  }
}

Berck.prototype.run = run('mapSeries')
Berck.prototype.series = run('mapSeries')
Berck.prototype.parallel = run('map')

var fs = require('fs')
var assert = require('assert')
var wait = require('co-wait')
var mzfs = require('mz/fs')
var thunky = require('always-thunk')
var readFile = thunky(fs.readFile)

var app = new Berck({foo: 'bar'})

app
.use(function callbackFn (next) {
  var self = this
  setTimeout(function () {
    self.data = true
    console.log(1, self)
    next(null, 123)
  }, Math.random() * 2000)
})
.use(function callbackThunk (next) {
  assert(this.data === true)
  console.log(2, this)
  this.data = 345
  readFile('./pkg.json', 'utf8')(next)
})
.use(function promiseFn () {
  assert(this.data === 345)
  console.log(3, this)
  this.data = 'foo'
  return Promise.resolve(555)
})
.use(function * promiseGen () {
  yield wait(Math.random() * 10000)
  assert(this.data === 'foo')
  var content = yield mzfs.readFile('./pkg.json', 'utf8')
  console.log(4, this)
  this.data = 'hello'
  return content
})
.use(function * genThunk () {
  assert(this.data === 'hello')
  console.log(5, this)
  return yield readFile('./pkg.json', 'utf8')
})
// .series({baz: 'qux'}, {hello: 'world'}, console.log)

/** kock - control flow *******************
 ******************************************/

var handleCallback = require('handle-callback')
var handleArguments = require('handle-arguments')
var manageArguments = require('manage-arguments')
var alwaysPromise = require('always-promise')
var asyncDone = require('async-done')

function arrayify (val) {
  return !Array.isArray(val) ? [val] : val
}
function bindArray (fn, thisArg, args) {
  return fn.bind.apply(fn, [thisArg].concat(args))
}
function kock (fn) {
  fn = arrayify(fn)

  function lastCallback (ctx, done) {
    return function lastCb_ () {
      var args = manageArguments(arguments)
      var err = args[0]
      var results = args.slice(1).shift()

      if (kock.lastOnly === true || kock.lastonly === true) {
        var last = results[results.length - 1]
        return done.call(ctx, err, last)
      }
      if (kock.unflatten === true || kock.flatten === false) {
        return done.apply(ctx, [err].concat(results))
      }
      return done.call(ctx, err, results)
    }
  }

  return function (cb) {
    var argz = handleArguments(arguments)
    var self = this || {}
    var results = []
    var i = 0

    self._ = argz.arguments

    nal.mapSeries(fn, function (_fnc, next) {
      _fnc = isGenFn(_fnc) ? co.wrap(_fnc) : _fnc
      _fnc = i === 0 ? bindArray(_fnc, self, argz.args) : bindArray(_fnc, self, results.shift())

      asyncDone(_fnc, function (err) {
        i++
        if (err) {
          return next(err)
        }
        var args = manageArguments(arguments).slice(1)
        results.push(args)

        next.apply(null, [null].concat(args))
      })
    }, lastCallback(self, argz.callback))
  }
}

// kock(function callbackFn (fp, next) {
//   return fs.readFile(fp, 'utf8', next)
// })('./pkg.json', console.log)

// kock(function callbackThunk (fp, next) {
//   readFile(fp, 'utf8')(next)
// })('./pkg.json', console.log)

// kock(function promiseFn (val) {
//   return Promise.resolve(123 + val)
// })(123, console.log) //=> 246

// kock(function * promiseGen (fp, next) {
//   return yield mzfs.readFile(fp, 'utf8')
// })('./pkg.json', console.log)

// var ko = kock([
//   function * genThunk (fp, next) {
//     console.log(this)
//     return yield readFile(fp, 'utf8')
//   },
//   function promiseFn (fp) {
//     console.log(this)
//     return Promise.resolve(123 + fp)
//   }
// ])
// ko.call({foo: 'bar'}, './pkg.json', console.log)

// var cheerio = require('cheerio')
// var got = require('then-got')

// kock.unflatten = true
// kock([
//   function (hello) {
//     this.hello = this._[0] // this._  is all given arguments as array
//     this.start = 123
//     return got('http://lapwinglabs.com')
//   },
//   function (lapwinglabs, callback) {
//     var self = this
//     var body = lapwinglabs[0]
//     var $ = cheerio.load(body)
//     this.title = $('title').text()
//     callback(null, this.title, 555)
//   },
//   function (lapwingTitle, num) {
//     assert(this.title === lapwingTitle) // Lapwing Labs
//     assert(this.hello === 'hello world')
//     return got('http://leveredreturns.com')
//   }
// ])('hello world', {foo: 'bar'}, function (er, lapwinglabs, lapwingTitle, leveredreturns) {
//   // [0] is body, [1] is stream
//   console.log(er)
//   console.log(lapwinglabs[1].req._headers)
//   console.log(lapwingTitle)
//   console.log(leveredreturns[1].req._headers)
//   console.log(this)
//   console.log('end')
// })

// var got = require('got')
// var cheerio = require('cheerio')

// function get (url, cb) {
//   var self = this
//   got(url, function (err, body, stream) {
//     if (err) {
//       return cb(err)
//     }
//     self.foo = 123
//     cb(null, body)
//   })
// }

// function title (text, cb) {
//   this.bar = 456
//   var $ = cheerio.load(text)
//   cb(null, $('title').text())
// }

// // kock.unflatten = true
// // kock.flatten = false

// // kock.lastonly = true
// // kock.lastOnly = true
// kock([get, title])('http://lapwinglabs.com', function (err, res) {
//   console.log(this) // {foo: 123, bar: 456}
//   console.log(err, res)
//   console.log('end')
// })
tunnckoCore commented 9 years ago

need tests

tunnckoCore commented 9 years ago
/*!
 * kock <https://github.com/tunnckoCore/kock>
 *
 * Copyright (c) 2015 Charlike Mike Reagent <@tunnckoCore> (http://www.tunnckocore.tk)
 * Released under the MIT license.
 */

'use strict'

var util = require('util')
var kindOf = require('kind-of')
var Options = require('option-cache')
var isGenFn = require('is-es6-generator-function')
var isPromise = require('is-promise')
var asyncDone = require('async-done')
var nowAndLater = require('now-and-later')
var handleArguments = require('handle-arguments')
var manageArguments = require('manage-arguments')

/**
 * utils
 */

function bindify (fn, thisArg, args) {
  return fn.bind.apply(fn, [thisArg].concat(args))
}

function arrayify (val) {
  return !Array.isArray(val) ? [val] : val
}

function wrapify (promise) {
  return function () {
    return promise
  }
}

/**
 * Expose `Kock`
 */

module.exports = Kock

/**
 * Create a new instance of `Kock`.
 *
 * @param {Object} `options` Initialize with default options.
 * @api public
 */

function Kock (options) {
  if (!(this instanceof Kock)) {
    return new Kock(options)
  }
  Options.call(this, options)
  this._defaultOptions()
}

util.inherits(Kock, Options)

Kock.prototype._defaultOptions = function () {
  if (!this.hasOption('context')) {
    this.option('context', {})
  }
  if (!this.hasOption('done') || kindOf(this.option('done')) !== 'function') {
    this.option('done', function noop () {})
  }
  if (!this.hasOption('promise') || !this.isBoolean('promise')) {
    this.option('promise', false)
  }
  if (!this.hasOption('flatten') || !this.isBoolean('flatten')) {
    this.option('flatten', true)
  }
  if (!this.hasOption('onlylast') || !this.isBoolean('onlylast')) {
    this.option('onlylast', false)
  }
  if (!this.hasOption('promisify') || kindOf(this.option('promisify')) !== 'function') {
    this.option('promisify', require('hybridify'))
  }
  if (!this.hasOption('generatorify') || kindOf(this.option('generatorify')) !== 'function') {
    this.option('generatorify', require('co').wrap)
  }
  return this
}

Kock.prototype.series = factory('mapSeries')
Kock.prototype.parallel = factory('map')

function factory (method) {
  return function _factory_ (fns, extensions) {
    if (kindOf(fns) === 'function') {
      fns = [fns]
    }
    if (kindOf(fns) !== 'array' && kindOf(fns) !== 'object') {
      throw new TypeError('kock: series expect `fns` to be array or an object')
    }
    var self = this
    extensions = this.option('extensions', extensions)

    function complete () {
      var argz = handleArguments(arguments)
      var ctx = self.option('context')
      var results = []
      var index = 0

      function iterator (fn, next) {
        var res = index === 0 ? argz.args : results.shift()
        fn = isPromise(fn) ? wrapify(fn) : fn
        fn = isGenFn(fn) ? self.option('generatorify')(fn) : fn
        fn = bindify(fn, ctx, res)

        asyncDone(fn, function (err, res) {
          index++
          if (err) {
            return next(err)
          }

          var args = manageArguments(arguments).slice(1)
          results.push(args)
          next.apply(null, [null].concat(args))
        })
      }

      nowAndLater[method](fns, iterator, extensions, lastCallback(ctx, argz.callback))
    }

    function lastCallback (ctx, done) {
      done = done || self.option('done')
      return function lastCb () {
        var args = manageArguments(arguments)
        var err = args[0]
        var res = args.slice(1).shift()
        var last = res[res.length - 1]

        if (self.enabled('flatten') && fns.length === 1) {
          self.disable('flatten')
        }
        if (self.enabled('onlylast')) {
          return done.call(ctx, err, last)
        }
        if (self.disabled('flatten')) {
          return done.apply(ctx, [err].concat(res))
        }
        return done.call(ctx, err, res)
      }
    }

    if (this.enabled('promise')) {
      return this.option('promisify')(complete)
    }
    return complete
  }
}
tunnckoCore commented 9 years ago

https://github.com/tunnckoCore/benz https://github.com/tunnckoCore/merz (upcoming) https://github.com/tunnckoCore/vez