Comparing version 0.2.0 to 0.3.0
33
index.js
(function() { | ||
"use strict"; | ||
var slice = [].slice; | ||
var DocBrown = {}; | ||
function isPromise(obj) { | ||
return typeof obj === "object" && | ||
typeof obj.then === "function" && | ||
typeof obj.catch === "function"; | ||
} | ||
function tryApply(obj, method, args) { | ||
if (typeof obj[method] !== "function") return; | ||
var res = obj[method].apply(obj, args); | ||
if (isPromise(res)) { | ||
res.then(function() { | ||
tryApply(obj, method + "Success", slice.call(arguments)); | ||
}, function() { | ||
tryApply(obj, method + "Error", slice.call(arguments)); | ||
}); | ||
} | ||
} | ||
function Dispatcher() { | ||
@@ -22,7 +41,5 @@ // format: {actionA: [storeA, storeB], actionB: [storeC]} | ||
dispatch: function(action) { | ||
var actionArgs = [].slice.call(arguments, 1); | ||
var actionArgs = slice.call(arguments, 1); | ||
(this.actionHandlers[action] || []).forEach(function(store) { | ||
if (typeof store[action] === "function") { | ||
store[action].apply(store, actionArgs); | ||
} | ||
tryApply(store, action, actionArgs); | ||
}); | ||
@@ -53,7 +70,7 @@ }, | ||
if (!arguments.length) return this; | ||
return DocBrown.createActions(dispatcher, [].slice.call(arguments)); | ||
return DocBrown.createActions(dispatcher, slice.call(arguments)); | ||
}; | ||
baseActions.drop = function() { | ||
if (!arguments.length) return this; | ||
var exclude = ["drop", "only"].concat([].slice.call(arguments)); | ||
var exclude = ["drop", "only"].concat(slice.call(arguments)); | ||
var actions = Object.keys(this).filter(function(name) { | ||
@@ -68,3 +85,3 @@ return exclude.indexOf(name) === -1; | ||
function merge(dest) { | ||
[].slice.call(arguments, 0).forEach(function(source) { | ||
slice.call(arguments, 0).forEach(function(source) { | ||
for (var prop in source) { | ||
@@ -88,3 +105,3 @@ if (prop !== "state") | ||
function BaseStore() { | ||
var args = [].slice.call(arguments); | ||
var args = slice.call(arguments); | ||
if (typeof this.initialize === "function") { | ||
@@ -91,0 +108,0 @@ this.initialize.apply(this, args); |
{ | ||
"name": "docbrown", | ||
"version": "0.2.0", | ||
"version": "0.3.0", | ||
"description": "Flux experiment.", | ||
@@ -10,2 +10,3 @@ "main": "index.js", | ||
"devDependencies": { | ||
"bluebird": "^2.9.6", | ||
"chai": "^1.10.0", | ||
@@ -12,0 +13,0 @@ "coveralls": "^2.11.2", |
@@ -87,6 +87,34 @@ DocBrown | ||
### Asynchronous actions | ||
### Promises support | ||
**There are no such things as async actions.** Let's keep the initial need simple and iron out the problem; an asynchronous operation should first call a sync action and then make the store triggering new actions dedicated to handle successes and failures: | ||
Store action handlers returning promises will execute `*Success` and `*Error` handlers, respectively on success and rejection: | ||
var TimeStore = DocBrown.createStore({ | ||
actions: [TimeActions], | ||
getInitialState: function() { | ||
return {year: 2015}; | ||
}, | ||
backward: function(years) { | ||
return new Promise(function(fulfill, reject) { | ||
setTimeout(function() { | ||
if (Math.random() > .5) { | ||
fulfill(years); // calls backwardSuccess | ||
} else { | ||
reject(new Error("Damn.")); // calls backwardError | ||
} | ||
}.bind(this), 50); | ||
}); | ||
}, | ||
backwardSuccess: function(years) { | ||
this.setState({years: this.state.years - years}); | ||
}, | ||
backwardError: function(error) { | ||
this.setState({error: error}); | ||
} | ||
}); | ||
Yeah, this is a little magic, though so convenient. I debated that. Anyway. | ||
If you're not working with Promise and want to deal with triggering store updates explicitely; note that this also allows to finely control any supplementary transition steps, while a little more verbose: | ||
```js | ||
@@ -93,0 +121,0 @@ var TimeActions = DocBrown.createActions(Dispatcher, [ |
44
test.js
var DocBrown = require("./"); | ||
var expect = require("chai").expect; | ||
var sinon = require("sinon"); | ||
var Promise = require("bluebird"); | ||
@@ -74,2 +75,45 @@ describe("DocBrown.createDispatcher()", function() { | ||
}); | ||
describe("on store handler returning a Promise", function() { | ||
var store; | ||
beforeEach(function() { | ||
store = { | ||
fulfillMe: function() { | ||
return new Promise(function(fulfill) { | ||
fulfill("ok"); | ||
}); | ||
}, | ||
fulfillMeSuccess: sinon.spy(), | ||
rejectMe: function() { | ||
return new Promise(function(fulfill, reject) { | ||
reject("error"); | ||
}); | ||
}, | ||
rejectMeError: sinon.spy() | ||
}; | ||
dispatcher.register("fulfillMe", store); | ||
dispatcher.register("rejectMe", store); | ||
}); | ||
it("should call a *Success handler next when fulfilled", function(done) { | ||
dispatcher.dispatch("fulfillMe"); | ||
setImmediate(function() { | ||
sinon.assert.calledOnce(store.fulfillMeSuccess); | ||
sinon.assert.calledWithExactly(store.fulfillMeSuccess, "ok"); | ||
done(); | ||
}); | ||
}); | ||
it("should call a *Error handler next when rejected", function(done) { | ||
dispatcher.dispatch("rejectMe"); | ||
setImmediate(function() { | ||
sinon.assert.calledOnce(store.rejectMeError); | ||
sinon.assert.calledWithExactly(store.rejectMeError, "error"); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
}); | ||
@@ -76,0 +120,0 @@ }); |
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
31582
631
244
7