Comparing version 2.1.0 to 2.1.1
21
index.js
@@ -114,3 +114,2 @@ var is = require('./is') | ||
if (is.function(resolve)) { | ||
// resolver callback | ||
return function (err, result) { | ||
@@ -127,17 +126,11 @@ if (err) return next(err) | ||
ctx.emit.apply(ctx, args) | ||
} else if (index < size) { | ||
return | ||
} | ||
if (index < size) { | ||
var fn = pipe[index] | ||
index++ | ||
var val = fn.call(self, ctx, next) | ||
if (val && is.function(val.then)) { | ||
// thenable: handle promise | ||
val.then(function (res) { | ||
if (res === undefined) next() // next | ||
else next(null, res) // result | ||
}, next) | ||
} else if (fn.length < 2) { | ||
// args without next() | ||
if (val === undefined) next() // no return, next | ||
else next(null, val) // result | ||
} | ||
fn.call(self, ctx, next) | ||
// args without next() | ||
if (fn.length < 2) next() | ||
} else { | ||
@@ -144,0 +137,0 @@ // trigger empty callback if no more pipe |
{ | ||
"name": "ginga", | ||
"version": "2.1.0", | ||
"version": "2.1.1", | ||
"description": "Middleware framework for JavaScript functions", | ||
@@ -5,0 +5,0 @@ "scripts": { |
@@ -27,2 +27,5 @@ # Ginga.js | ||
#### app.define(name, [pre...], invoke) | ||
#### app.use(name, [hook...]) | ||
`define()` and `use()` a method with `pre`, `hook`, `invoke` middleware functions. | ||
@@ -34,5 +37,15 @@ `pre` middlewares initiate and batch operations where `invoke` commits result. | ||
#### app.define(name, [pre...], invoke) | ||
#### app.use(name, [hook...]) | ||
### Middleware | ||
Middleware turns asynchronous functions into encapsulated, reusable set of building blocks. | ||
Upon calling a method, Ginga method goes through a sequence of middleware functions, with following arguments: | ||
* `ctx` - context event emitter object: | ||
* Maintains state throughout the method call, while encapsulated from `this` object. | ||
* A middleware can make changes to context object, or access changes made by previous middleware. | ||
* Emits end event `ctx.on('end', fn)` on callback with error and result arguments. | ||
* `next` - callback function: | ||
* `next()` to pass control to the next middleware. | ||
* `next(err, result)` to end the sequence and callback with error or result. | ||
```js | ||
@@ -42,3 +55,3 @@ var ginga = require('ginga') | ||
// defining method | ||
// define method | ||
app.define('test', function (ctx, next) { | ||
@@ -55,6 +68,6 @@ ctx.logs = ['pre'] | ||
ctx.logs.push('hook') | ||
next() | ||
setTimeout(next, 10) // async next | ||
}) | ||
// method callback | ||
// method call with callback function | ||
app.test(function (err, res) { | ||
@@ -64,3 +77,3 @@ console.log(res) // ['pre', 'hook', 'invoke'] | ||
// no callback function: returns Promise | ||
// method call with promise | ||
app.test().then(function (res) { | ||
@@ -71,21 +84,24 @@ console.log(res) // ['pre', 'hook', 'invoke'] | ||
### Middleware | ||
shortcuts for callback functions: | ||
Middleware turns asynchronous function into encapsulated, reusable set of building blocks. | ||
```js | ||
function (ctx, next) { | ||
task(function (err, res) { | ||
if (err) return next(err) | ||
// do stuff | ||
next() | ||
}) | ||
} | ||
// equivalent to | ||
function (ctx, next) { | ||
task(next(function (res) { | ||
// do stuff | ||
})) | ||
} | ||
``` | ||
Upon calling a method, Ginga goes through a sequence of functions `middleware`. A middleware consists of arguments: | ||
* `ctx` - context event emitter object. Emits `.on('end', fn)` event on callback with error and result arguments. | ||
* `next` - callback function, invoke with `next()` or `next(err, result)` or `asyncFn(next(resolveFn))` | ||
The context object `ctx` maintains state throughout the method call, while encapsulated from `this` object. | ||
A middleware can make changes to context object, or access changes made by previous middleware functions. | ||
Given next argument, current middleware must call `next()` to pass control to the next middleware, or `next(err, result)` to end the sequence and callback with error or result. | ||
Otherwise the method will be left hanging. | ||
#### ginga.params([param...]) | ||
Ginga built in `ginga.params` middleware for parsing method arguments. Supports optional parameters and type-checking. | ||
`param` is a string in form | ||
`param` is string in form of | ||
@@ -106,3 +122,3 @@ `name[:type][?]` | ||
app.define('test', params('a', 'b:number?', 'c:string?'), function (ctx, done) { | ||
done(null, ctx.params) | ||
done(null, ctx.params) | ||
}) | ||
@@ -109,0 +125,0 @@ |
@@ -5,4 +5,4 @@ var tape = require('tape') | ||
function invoke (ctx) { | ||
return ctx.params | ||
function invoke (ctx, done) { | ||
return done(null, ctx.params) | ||
} | ||
@@ -31,3 +31,6 @@ var obj = ginga() | ||
t.deepEqual(res, { a: '1', b: '2' }, 'promise resolve') | ||
}).catch(t.error) | ||
}) | ||
.catch(function (err) { | ||
t.error(err, 'no promise error') | ||
}) | ||
@@ -37,6 +40,11 @@ obj.f1('1', 167) | ||
t.deepEqual(res, { a: '1', c: 167 }, 'promise resolve') | ||
}).catch(t.error) | ||
}) | ||
.catch(function (err) { | ||
t.error(err, 'no promise error') | ||
}) | ||
obj.f2('1') | ||
.then(t.error) | ||
.then(function (res) { | ||
t.error(res, 'error no resolve') | ||
}) | ||
.catch(function (err) { | ||
@@ -43,0 +51,0 @@ t.equal(err.message, 'Too few arguments. Expected at least 2') |
var tape = require('tape') | ||
var ginga = require('../') | ||
var Promise = require('pinkie-promise') | ||
tape('ginga prototype', function (t) { | ||
t.plan(10) | ||
t.plan(12) | ||
@@ -21,3 +20,3 @@ function Clock () { | ||
next(function (result) { | ||
t.equal(result, 167199, 'callback resolver') | ||
t.equal(result, 167199, 'resolver result') | ||
})(null, 167199) | ||
@@ -29,10 +28,5 @@ } | ||
} | ||
function end (ctx) { | ||
function end (ctx, done) { | ||
ctx.logs.push('done') | ||
// then result | ||
return new Promise(function (resolve) { | ||
setTimeout(function () { | ||
resolve(ctx.logs) | ||
}, 10) | ||
}) | ||
done(null, ctx.logs) | ||
} | ||
@@ -44,17 +38,20 @@ var C = ginga(Clock.prototype) | ||
clock2.use('tick', function (ctx) { | ||
// return thenable | ||
return new Promise(function (resolve) { | ||
setTimeout(function () { | ||
ctx.logs.push('more') | ||
resolve() // no value, should do next | ||
}, 10) | ||
}) | ||
}, function (ctx) { | ||
ctx.logs.push('and more tick') | ||
}) | ||
clock2.use('tock', function (ctx, next) { | ||
// resolver callback err | ||
next(t.error)('booooom') | ||
}) | ||
clock2.use( | ||
'tick', | ||
function (ctx) { | ||
ctx.logs.push('more') | ||
}, | ||
function (ctx) { | ||
ctx.logs.push('and more tick') | ||
} | ||
) | ||
clock2.use( | ||
'tock', | ||
function (ctx, next) { | ||
// resolver function err | ||
next(function (res) { | ||
t.error('resolver called') | ||
})('booooom') | ||
} | ||
) | ||
@@ -70,6 +67,6 @@ C.define('tick', end) | ||
}) | ||
clock1.tock().then(function (res) { | ||
clock1.tock(function (err, res) { | ||
t.notOk(err, 'no error') | ||
t.deepEqual(res, ['clock', 'tick', 'tock', 'done']) | ||
}).catch(t.error) | ||
}) | ||
clock2.tick(function (err, res) { | ||
@@ -79,5 +76,6 @@ t.notOk(err, 'no error') | ||
}) | ||
clock2.tock().then(t.error).catch(function (err) { | ||
clock2.tock(function (err, res) { | ||
t.notOk(res, 'no result') | ||
t.equal(err, 'booooom', 'return error') | ||
}) | ||
}) |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
216
18647
462