Comparing version 0.0.4 to 1.0.0
108
index.js
module.exports = chainit; | ||
function chainit(Constructor) { | ||
var instances = []; | ||
var fns = []; | ||
var Chain = function Chain() { | ||
instances.push(this); | ||
fns[instances.indexOf(this)] = {}; | ||
function Chain() { | ||
Constructor.apply(this, arguments); | ||
}; | ||
} | ||
@@ -59,78 +55,66 @@ Chain.prototype = Object.create(Constructor.prototype); | ||
var statics = Object.keys(Constructor).forEach(function(name) { | ||
Chain[name] = new Function(Constructor[name]); | ||
}); | ||
// static methods, not chained | ||
Object.keys(Constructor) | ||
.forEach(function(name) { | ||
Chain[name] = new Function(Constructor[name]); | ||
}); | ||
var methods = Object.keys(Constructor.prototype); | ||
methods.forEach(function(name) { | ||
var original = Constructor.prototype[name]; | ||
// prototype methods, chained | ||
Object | ||
.keys(Constructor.prototype) | ||
.forEach(function(fnName) { | ||
Chain.prototype[fnName] = makeChain(fnName, Constructor.prototype[fnName]); | ||
}); | ||
var chained = makeChain(); | ||
function makeChain(fnName, fn) { | ||
function makeChain(fn) { | ||
return function chained() { | ||
var ctx = this; | ||
var args = Array.prototype.slice.call(arguments); | ||
var customCb; | ||
if (typeof args[args.length - 1] === 'function') { | ||
customCb = args.pop(); | ||
} | ||
return function chained() { | ||
var ctx = this; | ||
var args = Array.prototype.slice.call(arguments); | ||
var customCb; | ||
if (typeof args[args.length - 1] === 'function') { | ||
customCb = args.pop(); | ||
} | ||
var ldepth = currentDepth; | ||
var ldepth = currentDepth; | ||
if (currentDepth > 0 && queues[currentDepth - 1].concurrency > 0) { | ||
queues[currentDepth - 1].concurrency = 0; | ||
} | ||
if (currentDepth > 0 && queues[currentDepth - 1].concurrency > 0) { | ||
queues[currentDepth - 1].concurrency = 0; | ||
} | ||
var task = function(cb) { | ||
currentDepth = ldepth + 1; | ||
var task = function(cb) { | ||
currentDepth = ldepth + 1; | ||
args.push(function() { | ||
var cbArgs = arguments; | ||
args.push(function() { | ||
var cbArgs = arguments; | ||
if (customCb) { | ||
customCb.apply(ctx, cbArgs); | ||
} | ||
if (customCb) { | ||
customCb.apply(ctx, cbArgs); | ||
} | ||
cb(); | ||
}); | ||
cb(); | ||
}); | ||
fn.apply(ctx, args); | ||
} | ||
if (typeof fn === 'function') { | ||
fn.apply(ctx, args); | ||
} else { | ||
original.apply(ctx, args); | ||
} | ||
} | ||
pushTo(currentDepth, task); | ||
return this; | ||
} | ||
pushTo(currentDepth, task); | ||
return this; | ||
} | ||
} | ||
Object.defineProperty(Chain.prototype, name, { | ||
set: function(func) { | ||
if (this === Chain.prototype) { | ||
original = func; | ||
} else { | ||
fns[instances.indexOf(this)][name] = makeChain(func); | ||
} | ||
}, | ||
get: function() { | ||
if (this === Chain.prototype || !fns[instances.indexOf(this)][name]) { | ||
return chained; | ||
} else { | ||
return fns[instances.indexOf(this)][name]; | ||
} | ||
} | ||
}); | ||
Chain.prototype.__addToChain = function(fnName, fn) { | ||
this[fnName] = makeChain(fnName, fn); | ||
} | ||
}); | ||
return Chain; | ||
} | ||
chainit.add = function add(to, fnName, fn) { | ||
to.__addToChain(fnName, fn); | ||
} | ||
function hasPending(queue) { | ||
return queue.length >= 1; | ||
} |
{ | ||
"name": "chainit", | ||
"version": "0.0.4", | ||
"version": "1.0.0", | ||
"description": "Turn an asynchronous JavaScript api into an asynchronous chainable JavaScript api.", | ||
@@ -5,0 +5,0 @@ "main": "index.js", |
[![Build Status](https://travis-ci.org/vvo/chainit.png)](https://travis-ci.org/vvo/chainit) | ||
[![Selenium Test Status](https://saucelabs.com/browser-matrix/chainitvvo.svg)](https://saucelabs.com/u/chainitvvo) | ||
# chainit | ||
@@ -27,14 +29,10 @@ | ||
## Overriding methods | ||
## Adding or overriding methods | ||
You can override methods: | ||
* at the `.prototype` level | ||
* at the instance level | ||
Adding and overriding methods works at both prototype level and instance level. | ||
And still benefits from the chain. | ||
You must use `chainit.add(chain, methodName, method)`, | ||
you can't do direct assignation (`chain.methodName = method`) because | ||
`object.observe` is not yet ready. | ||
You can also keep references to the original methods to set them back later. | ||
This is possible because we do not touch the | ||
`MyApi` original `constructor` nor `prototype`. | ||
```js | ||
@@ -49,3 +47,6 @@ function MyApi() {} | ||
MyChainApi.prototype.method1 = function(cb) {cb()} | ||
// override instance method | ||
chainit.add(MyChainApi, 'method1', function(cb) { | ||
cb() | ||
}); | ||
@@ -58,17 +59,9 @@ var obj = new MyChainApi(); | ||
MyChainApi.prototype.method1 = original1; | ||
// revert original method | ||
chainit.add(MyChainApi, 'method1', original1); | ||
obj | ||
.method1() // calls the original method | ||
.method2(); | ||
original1 = obj.method1; | ||
obj.method1 = function(cb) {cb()} | ||
obj | ||
.method1() // calls the newly added method1 | ||
.method2(); | ||
obj.method1 = original1; | ||
// override prototype method | ||
chainit.add(MyChainApi.prototype, 'method1', function(cb) { | ||
cb() | ||
}); | ||
``` | ||
@@ -88,8 +81,5 @@ | ||
* supports methods redifinition | ||
* fully tested! `npm test` | ||
* supports adding new methods | ||
* fully tested! local: `npm install -g mocha && mocha`, saucelabs: `npm test` | ||
## examples | ||
See [examples](examples/). | ||
## tests | ||
@@ -103,4 +93,8 @@ | ||
## async/sync apis | ||
## examples | ||
See [examples](examples/). | ||
## mixing async/sync apis | ||
There is no easy way to mix sync/async chainable | ||
@@ -128,8 +122,7 @@ apis because there is no way to differenciate sync/async calls. | ||
This module was done easily thanks to | ||
[jessetane/queue](https://github.com/jessetane/queue). | ||
This module is using [jessetane/queue](https://github.com/jessetane/queue). | ||
A chainable api is just queueing methods and reordering calls. | ||
A chainable api is queueing methods and reordering calls, so we use a queue. | ||
This module was built to replace the chainable api from | ||
[webdriverjs](https://github.com/camme/webdriverjs/tree/v0.8.0). | ||
[webdriverjs](https://github.com/camme/webdriverjs). |
@@ -218,6 +218,6 @@ describe('chaining an Api', function() { | ||
ChainApi.prototype.concat = function concat(sub, cb) { | ||
chainit.add(ChainApi.prototype, 'concat', function concat(sub, cb) { | ||
this.s = this.s.concat(sub + '#'); | ||
setTimeout(cb, ChainApi.getRandomArbitrary(5, 20)); | ||
} | ||
}); | ||
@@ -232,10 +232,10 @@ o2.concat('re'); | ||
assert.equal(this.s, 're#de#fi1-#fi2-#fi3-#nition#'); | ||
ChainApi.prototype.concat = original; | ||
chainit.add(ChainApi.prototype, 'concat', original); | ||
o.concat('BOUH-', function() { | ||
ChainApi.prototype.concat = function (sub, cb) { | ||
chainit.add(ChainApi.prototype, 'concat', function concat(sub, cb) { | ||
this.s = this.s.concat(sub + '!!'); | ||
setTimeout(cb, ChainApi.getRandomArbitrary(5, 20)); | ||
}; | ||
}); | ||
o.concat('hello', function() { | ||
ChainApi.prototype.concat = Api.prototype.concat; | ||
chainit.add(ChainApi.prototype, 'concat', Api.prototype.concat); | ||
o.concat('-ah', function() { | ||
@@ -257,6 +257,6 @@ o2.concat('def', function() { | ||
o.concat = function(sub, cb) { | ||
chainit.add(o, 'concat', function concat(sub, cb) { | ||
this.s += sub + '#' | ||
setTimeout(cb, ChainApi.getRandomArbitrary(5, 20)); | ||
} | ||
}); | ||
@@ -271,3 +271,3 @@ o | ||
o2.concat('hey').concat('ho', function() { | ||
o.concat = original; | ||
chainit.add(o, 'concat',original); | ||
o.concat('YO!', function() { | ||
@@ -289,6 +289,22 @@ assert.equal(this.s, 'one#two#three#four1-#four2-#four3-#YO!'); | ||
xit('supports adding new methods', function() { | ||
it('supports adding new methods', function(done) { | ||
function newMethod(sub, cb) { | ||
this.s += sub + 'NEW!-' | ||
setTimeout(cb, ChainApi.getRandomArbitrary(5, 20)); | ||
} | ||
assert.equal(typeof o.newMethod, 'undefined'); | ||
chainit.add(o, 'newMethod', newMethod); | ||
assert.equal(typeof o.newMethod, 'function'); | ||
o | ||
.newMethod('thiis') | ||
.newMethod('amazing', function() { | ||
this.concat('allo', function() { | ||
assert.equal(this.s, 'thiisNEW!-amazingNEW!-allo'); | ||
done() | ||
}) | ||
}) | ||
}); | ||
}); |
Sorry, the diff of this file is not supported yet
No v1
QualityPackage is not semver >=1. This means it is not stable and does not support ^ ranges.
Found 1 instance in 1 package
18219
14
1
123