Permalink
Browse files

Add: expose 'filterchain' to the window if running in the browser

  • Loading branch information...
1 parent aee553c commit 02b71473658502e3a9198299081cd95cfed2ba8b @tmpvar committed Nov 18, 2011
Showing with 124 additions and 48 deletions.
  1. +56 −15 README.md
  2. +41 −33 index.js
  3. +27 −0 test.js
View
@@ -10,9 +10,28 @@ This also means that errors will not stop the chain of events here, you must spe
## Learn by example
+The basic operation of filterchain goes something like this:
+
+```javascript
+var chain = require('filterchain').createChain([
+ function(data, next, cancel) {
+ // forward to the next layer
+ next('override');
+ } // you can add more functions here
+]);
+
+chain('initial data', function(data) {
+ console.log(data); // outputs 'override'
+});
+
+```
+
+and here is the outer api
+
+
```javascript
// Create a chain with no layers and no core function
-var chain = require('filterchain').createChain(/* layers */, /* core */);
+var chain = filterchain.createChain(/* layers */, /* core */);
```
Where `chain` is a function that accepts an optional `data` and a optional `callback` with the arguments `errors` and `data`. The `callback` is called after the filter chain has been executed.
@@ -64,10 +83,12 @@ chain(false, function(errors, data) {
```
-## What does it do?
+## What (else) does it do?
In a sense, filter chains are similar to onions. Passing data into the outer husk causes it to flow down through each layer toward the core. Each function (aka: layer) along the path as a chance to either manipulate or validate the data before forwarding it onto the next layer or canceling it.
+### Manipulate and forward data
+
```javascript
var chain = require('filterchain').createChain([
function(data, next, cancel) {
@@ -83,6 +104,8 @@ chain(function(errors, data) {
});
```
+### Cancel + bubble
+
Cancelling causes the flow of the chain to be reversed immediately.
```javascript
@@ -105,6 +128,8 @@ chain(function(errors, data) {
```
+### Post process data
+
Passing a function as the second argument to `next` will cause the filter chain to call that method during the bubble phase
```javascript
@@ -127,22 +152,36 @@ chain('initial value', function(errors, data) {
The first argument to `done` is an error and the second is the data that will be bubbled back out to the outer husk of the filter chain.
-## Basic Usage
-
-The basic operation of filterchain goes something like this:
+### Compose filter chains
```javascript
-var fc = require('filterchain');
-var chain = fc.createChain([
- function(data, next, cancel) {
- next('override');
- } // you can add more functions here
-]);
-chain('initial data', function(data) {
- console.log(data); // outputs 'override'
+var inner = require('filterchain').createChain([
+ function(data, next) {
+ next(data + ' (inner capture ->', function(outgoingData, done) {
+ done(null, outgoingData + ' inner bubble)');
+ });
+ }
+], function(data, fn) {
+ fn(null, data + '[inner core] ->')
+})
+
+var outer = require('filterchain').createChain([
+ function(data, next) {
+ next(data + 'outer capture ->', function(outgoingData, done) {
+ done(null, outgoingData + ' outer bubble');
+ });
+ },
+ inner, // add a filterchain into the filterchain.. oh my!
+
+], function(data, fn) {
+ fn(null, data + ' [outer core] ->')
});
+outer('run: ', function(errors, data) {
+ // outputs: 'run: outer capture -> (inner capture ->[inner core] -> inner bubble) [outer core] -> outer bubble'
+ console.log(data);
+})
```
## Contrived Use Cases
@@ -156,7 +195,7 @@ var createUser = require('filterchain').createChain([
if (err) {
cancel(err);
} else if (result === true) {
- cancel(new Error('sorry, that username already exists'))
+ cancel('sorry, that username already exists')
} else {
next(username);
}
@@ -178,6 +217,8 @@ createUser('tmpvar-not-taken', function(errors, data) {
### Calculated attriutes in backbone
+__note__: this is purely conceptual
+
```javascript
var Rectangle = Backbone.Model.extend({
@@ -225,4 +266,4 @@ console.log(a.get('area')); // outputs '40'
### Browser
-works with a plain ol' script tag, [browserify](https://github.com/substack/node-browserify) or [require.js](http://requirejs.org/)
+works with a plain ol' script tag or [browserify](https://github.com/substack/node-browserify)
View
@@ -1,14 +1,14 @@
-(function() {
- module.exports = {
- createChain : function(layers, coreFn) {
+(function (hasWindow, nop) {
+ var expose = {
+ createChain : function (layers, coreFn) {
if (typeof layers === 'function' && !coreFn) {
coreFn = layers;
layers = [];
} else {
layers = layers || [];
}
- var chainInstance = function(data, fn) {
+ var chainInstance = function (data, fn) {
if (typeof data === 'function' && !fn) {
fn = data;
data = null;
@@ -19,12 +19,34 @@
errors = [],
bubbles = [],
current,
- capture = function(data) {
- index++;
+ bubble = function (data) {
+
+ if (bubbles.length < 1) {
+ if (fn) {
+ fn((errors.length) ? errors : null, data);
+ }
+ } else {
+ var
+ bubbleFn = bubbles.pop(),
+ ret = bubbleFn(data, function done(err, data) {
+ if (err) {
+ errors.push(err);
+ }
+
+ bubble(data);
+ });
+
+ if (ret !== nop) {
+ bubble(ret);
+ }
+ }
+ },
+ capture = function (data) {
+ index+=1;
if (index>=layers.length) {
if (chainInstance.core) {
- chainInstance.core(data, function(err, data) {
+ chainInstance.core(data, function (err, data) {
if (err) {
errors.push(err);
}
@@ -42,51 +64,37 @@
// handle the case where flows are being composed
// data is the errors
if (data) {
- errors.push(err)
- return bubble(data);
+ errors.push(data);
+ return bubble(bubbleFn);
}
data = bubbleFn;
}
- capture(data)
+ capture(data);
}, function cancel(err, data) {
if (err) {
- errors.push(err)
+ errors.push(err);
}
bubble(data);
});
} else {
- errors.push(new Error('user error! A link in the layers was not a function'))
+ errors.push(new Error('user error! A link in the layers was not a function'));
bubble(data);
}
-
- }, bubble = function(data) {
-
- if (bubbles.length < 1) {
- if (fn) {
- fn((errors.length) ? errors : null, data);
- }
- } else {
- var bubbleFn = bubbles.pop();
- var ret = bubbleFn(data, function done(err, data) {
- if (err) { errors.push(err); }
- bubble(data);
- });
-
- if (typeof ret !== 'undefined') {
- bubble(ret);
- }
- }
};
capture(data);
};
chainInstance.layers = layers;
chainInstance.core = coreFn;
-
return chainInstance;
}
- }
+ };
-})();
+ if (hasWindow) {
+ window.filterchain = expose;
+ } else {
+ module.exports = expose;
+ }
+})(typeof window !== 'undefined');
View
27 test.js
@@ -152,3 +152,30 @@ var testHook = ''
var optionalCallback = fc.createChain();
optionalCallback();
+// chain with 2 cores
+var inner = fc.createChain([
+ function(data, next) {
+ next(data + 'icap,', function(outgoingData, done) {
+ done(null, outgoingData + 'ibub,');
+ });
+ }
+], function(data, fn) {
+ fn(null, data + 'icore,')
+})
+
+var outer = fc.createChain([
+ function(data, next) {
+ next(data + 'ocap,', function(outgoingData, done) {
+ done(null, outgoingData + 'obub');
+ });
+ },
+ inner, // add a filterchain into the filterchain.. oh my!
+
+], function(data, fn) {
+ fn(null, data + 'ocore,')
+});
+
+outer('', function(errors, data) {
+ equal('ocap,icap,icore,ibub,ocore,obub', data);
+});
+

0 comments on commit 02b7147

Please sign in to comment.