Skip to content
Browse files

Update API to match eventual-cljs better.

  • Loading branch information...
1 parent 07b276c commit f90e247ae0bfb55841ff1e550043275517a9a539 @Gozala committed Apr 23, 2012
Showing with 134 additions and 77 deletions.
  1. +111 −54 core.js
  2. +23 −23 tests/test-all.js
View
165 core.js
@@ -9,7 +9,9 @@ var protocol = require('protocol/core').protocol
var reflection = require('reflection/core'),
string = reflection.string, array = reflection.array,
object = reflection.object, fn = reflection.fn
+var nil
+function identity(value) { return value }
function attempt(f) {
/**
Returns wrapper function that delegates to `f`. If `f` throws then captures
@@ -22,82 +24,137 @@ function attempt(f) {
}
}
-var IEventual = protocol({
- deliver: [ protocol, 'value' ]
+var ISecure = protocol({
+ privates: [ protocol, 'accessor' ]
})
-exports.IEventual = IEventual
-exports.deliver = IEventual.deliver
+exports.ISecure = ISecure
+var privates = ISecure.privates
+var IPending = protocol({
+ isRealized: [ protocol ]
+})
+var isRealized = IPending.isRealized
-var IReactor = protocol({
- wait: [ protocol, 'deliver:Function', 'reject:Function' ],
+var IValue = protocol({
+ valueOf: [ protocol ]
})
-exports.IReactor = IReactor
+exports.IValue = IValue
+var valueOf = IValue.valueOf
-var wait = IReactor.wait
-exports.wait = wait
+var IDeferred = protocol({
+ realize: [ protocol, 'value' ]
+})
+exports.IDeferred = IDeferred
-IReactor(Object, {
- wait: function(reactor, deliver, reject) {
- return attempt(deliver)(reactor)
- }
+var IEventual = protocol({
+ then: [ protocol, 'realized:Function', 'rejected:Function' ],
+ when: [ protocol, 'realized:Function', 'rejected:Function' ]
})
+exports.IEventual = IEventual
+var then = IEventual.then, when = IEventual.when
-IReactor(Error, {
- wait: function(reactor, deliver, reject) {
- return attempt(reject)(reactor)
+IValue(Object, {
+ value: function($) {
+ return $.valueOf()
+ }
+})
+IEventual(Object, {
+ then: function(object, realized, rejected) {
+ var deferred = defer()
+ realized = attempt(realized || identity)
+ rejected = attempt(rejected || identity)
+ when(object, function($) {
+ realize(deferred, realized($))
+ }, function($) {
+ realize(deferred, rejected($))
+ })
+ return valueOf(deferred)
+ },
+ when: function(object, realize, _) {
+ realize(object)
}
})
-function valueOf(object) { return object.valueOf(valueOf) }
-function identity(value) { return value }
+IEventual(Error, {
+ when: function($, _, rejected) { attempt(rejected)($) }
+})
-function Reactor() {
- var state = { pending: [] }
- return Object.create(Reactor.prototype, {
- valueOf: { value: function($) {
- return $ === valueOf ? state : this
+var DeferredKey = {}
+function Deferred(state, observers) {
+ var privates = { state: state, observers: observers }
+ return Object.defineProperties(this, {
+ valueOf: { value: function(key) {
+ return key === DeferredKey ? privates : this
}}
})
}
-exports.Reactor = Reactor
-IEventual(Reactor, {
- deliver: function deliver(reactor, value) {
- var state = valueOf(reactor), pending = state.pending
- if (pending) {
- state.result = value
- while (pending.length) wait.apply(null, [value].concat(pending.shift()))
- state.pending = false
- }
+exports.Deferred = Deferred
+ISecure(Deferred, {
+ privates: function($) { return $.valueOf(DeferredKey) }
+})
+IPending(Deferred, {
+ isRealized: function($) { return privates($).state.done }
+})
+IValue(Deferred, {
+ valueOf: function($) { return isRealized($) ? privates($).state.value : $ }
+})
+IEventual(Deferred, {
+ when: function($, realized, rejected) {
+ if (isRealized($))
+ when(valueOf($), realized, rejected)
+ else
+ privates($).observers.push({ realize: realized, reject: rejected })
}
})
-IReactor(Reactor, {
- wait: function(reactor, deliver, reject) {
- var state = valueOf(reactor), pending = state.pending, result = state.result
- if (!pending) return wait(result, deliver, reject)
- result = Reactor()
- deliver = deliver ? attempt(deliver) : identity
- reject = reject ? attempt(reject) : identity
- pending.push([
- function delivered(value) { IEventual.deliver(result, deliver(value)) },
- function rejected(error) { IEventual.deliver(result, reject(error)) }
- ])
- return result
+IDeferred(Deferred, {
+ realize: function($, value) {
+ if (!isRealized($)) {
+ var internals = privates($)
+ internals.state = { done: true , value: value }
+ internals.observers.forEach(function(observer) {
+ when(value, observer.realize, observer.reject)
+ })
+ internals.observers = null
+ }
}
})
-function eventual(f) {
- return function() {
- var result = array.reduce(arguments, function(items, item) {
- return wait(item, function(value) {
- return wait(items, function(values) {
- return array.concat([ value ], values)
- })
+var realize = IDeferred.realize
+exports.realize = realize
+
+function defer() {
+ return new Deferred({ done: false }, [])
+}
+exports.defer = defer
+
+function group(promises) {
+ return array.reduce(promises, function(promises, promise) {
+ return then(promise, function(value) {
+ return then(promises, function(values) {
+ return array.concat(values, [ value ])
})
- }, [])
- return wait(result, function(args) {
- return f.apply(f, args);
})
+ }, [])
+}
+
+function go(f/*, rest */) {
+ return then(group(arguments), function(params) {
+ var f = params.shift()
+ return f.apply(f, params)
+ })
+}
+exports.go = go
+
+function recover(f, eventual) {
+ return then(eventual, identity, f)
+}
+exports.recover = recover
+
+function eventual(f) {
+ return function eventually() {
+ var params = array.slice(arguments)
+ params.unshift(f)
+ return go.apply(go, params)
}
}
exports.eventual = eventual
View
46 tests/test-all.js
@@ -9,17 +9,17 @@
var core = require('../core'),
eventual = core.eventual,
- deliver = core.deliver,
- wait = core.wait,
- Reactor = core.Reactor
+ realize = core.realize,
+ go = core.go,
+ defer = core.defer
var sum = eventual(function(a, b) { return a + b })
exports['test non-eventual values'] = function(assert) {
assert.equal(sum(2, 3), 5, 'call on non-eventuals returns value')
}
-exports['test wait non-eventual'] = function(assert) {
+exports['test go non-eventual'] = function(assert) {
;[
{ a: 1 },
[ 'b', 2 ],
@@ -31,20 +31,20 @@ exports['test wait non-eventual'] = function(assert) {
undefined,
null
].forEach(function(expected) {
- wait(expected, function(actual) {
- assert.equal(actual, expected, 'wait can be called on: ' + expected)
- })
+ go(function(actual) {
+ assert.equal(actual, expected, 'go can be called on: ' + expected)
+ }, expected)
})
}
exports['test delivered eventuals'] = function(assert) {
- var a = Reactor(), b = 3
- deliver(a, 1)
+ var a = defer(), b = 3
+ realize(a, 1)
assert.equal(sum(a, b), 4, 'call on delivered eventual returns value')
}
-exports['test wait on eventuals'] = function(assert) {
+exports['test go on eventuals'] = function(assert) {
;[
{ a: 1 },
[ 'b', 2 ],
@@ -56,36 +56,36 @@ exports['test wait on eventuals'] = function(assert) {
undefined,
null
].forEach(function(expected) {
- var value = Reactor()
- deliver(value, expected)
- wait(value, function(actual) {
- assert.equal(actual, expected, 'wait works with eventual: ' + expected)
- })
+ var value = defer()
+ realize(value, expected)
+ go(function(actual) {
+ assert.equal(actual, expected, 'go works with eventual: ' + expected)
+ }, value)
})
}
exports['test undelivered eventuals'] = function(assert) {
var expected = 7
- var a = Reactor()
+ var a = defer()
var b = sum(a, 1)
assert.ok(typeof(b) === 'object', 'call on non-delivered returns eventual')
var c = sum(b, 3)
- wait(a, function(value) {
+ go(function(value) {
assert.equal(value, expected, 'eventual resolved as expected')
- })
+ }, a)
- wait(b, function(value) {
+ go(function(value) {
assert.equal(value, expected + 1, 'eventual operation resolved as expected')
- })
+ }, b)
- wait(c, function(value) {
+ go(function(value) {
assert.equal(value, expected + 1 + 3, 'eventuals chain as expected')
- })
+ }, c)
- deliver(a, expected)
+ realize(a, expected)
}

0 comments on commit f90e247

Please sign in to comment.
Something went wrong with that request. Please try again.