Permalink
Browse files

Allow wiring function to subscribe/unsubscribe cells to trigger execu…

…tion
  • Loading branch information...
vic committed Aug 15, 2012
1 parent fe16d83 commit 8c4da6243a7312adac85e301f87e3f6e062d25df
Showing with 99 additions and 36 deletions.
  1. +1 −2 examples/clock.js
  2. +48 −30 lib/NoR.js
  3. +50 −4 test/NoR_test.js
View
@@ -20,8 +20,7 @@ var counter = NoR(function(clock, count){
}, function(){
// mark the count cell so it doent
// trigger counter execution again
// mark it as an outputOnly cell.
this.count.isOutput = true
this.count.unsubscribe(this)
})
var c = clock(true, false, 600)
View
@@ -33,27 +33,51 @@
}
var addSubscriber = function(subscriber) {
if(subscriber.constructor === Gate) {
subscriber = subscriber.execute
}
if(subscriber === cell) { return }
var i = subscribers.indexOf(subscriber)
if(i < 0 ) { subscribers.push(subscriber) }
}
var removeSubscriber = function(subscriber) {
if(subscriber.constructor === Gate) {
subscriber = subscriber.execute
}
var i = subscribers.indexOf(subscriber)
if(i > -1) { subscribers[i] = null }
// TODO: clean list when too big
}
cell.constructor = Cell
cell.cellName = name
cell.toString = function() { return '{'+name+':'+value+'}' }
cell.subscribe = addSubscriber
cell.bind = function(other) {
var clearSubscribers = function(){
subscribers = []
}
var subscriberCount = function(){
subscribers.length
}
var bind = function(other) {
cell.subscribe(other)
other.subscribe(cell)
}
cell.clearSubscribers = function() { subscribers = [] }
cell.unSubscribe = removeSubscriber
var unbind = function(other){
cell.unsubscribe(other)
other.unsubscribe(cell)
}
Object.defineProperty(cell, 'constructor', {value: Cell})
Object.defineProperty(cell, 'cellName', {value: name})
Object.defineProperty(cell, 'subscribe', {value: addSubscriber})
Object.defineProperty(cell, 'unsubscribe', {value: removeSubscriber})
Object.defineProperty(cell, 'bind', {value: bind})
Object.defineProperty(cell, 'unbind', {value: unbind})
Object.defineProperty(cell, 'subscriberCount', {get: subscriberCount})
cell.toString = function() { return '{'+name+':'+value+'}' }
cell.shouldPropagate = function(){
return value !== arguments[0] || arguments.length > 1
}
@@ -65,8 +89,6 @@
var rest = Array.prototype.slice.apply(arguments, [4])
, impl = typeof impl === 'function' ? impl : function(){}
, names = {}
, cells = argCells(impl, names)
, self = names['self'] = cellWrap(Cell('self', _self))
, timeout
, execute = function() {
if(timeout) { clearTimeout(timeout) }
@@ -94,10 +116,16 @@
}])
return arguments.callee
}
, self = names['self'] = Cell('self', _self)
, cells = argCells(impl, names)
if(!create){ return clone }
invoke.clone = clone
invoke.self = self
invoke.length = cells.length
Object.defineProperty(invoke, 'constructor', {value: Gate})
Object.defineProperty(invoke, 'execute', {value: execute})
Object.defineProperty(invoke, 'clone', {value: clone})
Object.defineProperty(invoke, 'self', {value: self})
invoke.toString = function(){
var buff = []
cells.forEach(function(cell){
@@ -107,7 +135,10 @@
}
cells.forEach(function(cell, i){
invoke[cell.cellName] = invoke[i] = cell
Object.defineProperty(invoke, cell.cellName, {value: cell})
Object.defineProperty(invoke, i, {value: cell})
if( i < rest.length ) {
if(typeof rest[i] === 'function' && rest[i].constructor === Cell) {
cell( rest[i]() )
@@ -118,6 +149,9 @@
}
})
self.subscribe(execute)
cells.forEach(function(cell){cell.subscribe(execute)})
if(wire){
var wireCells = argCells(wire, names)
wireCells.forEach(function(cell, i){
@@ -134,35 +168,19 @@
wire.apply(invoke, wireCells)
}
[self].concat(cells).forEach(function(cell){
if(!cell.isOutput) {
cell.subscribe(execute)
}
})
return invoke
}
var ARGS_RE = /^function\s+\(([^\)]+)\)/, SEP_RE = /,?\s+/
var cellWrap = function(cell){
return cell // TODO wrap
var wrap = function(){
var self = this, args = arguments
return cell.apply(this, arguments)
}
wrap.cellName = cell.cellName
return wrap
}
var argCells = function(impl, store){
var names = impl.toString().match(ARGS_RE)
, names = names && names[1].split(SEP_RE) || []
, cells = []
, store = store || {}
names.forEach(function(name, i){
if(! store[name]) {
store[name] = cellWrap(Cell(name))
store[name] = Cell(name)
}
cells[i] = store[name]
})
View
@@ -58,7 +58,7 @@ describe("NoR", function(){
expect(x.length).to.equal(0)
})
it("is triggered when any of the gate arguments (cells) change", function(){
it("is triggered when any of the gate arguments (cells) change", function(done){
var x = 0
var n = new NoR(function(a, b, c){
x += 1
@@ -76,6 +76,8 @@ describe("NoR", function(){
n(1, 2, 3)
setTimeout(function(){
expect(x).to.equal(3)
done()
}, 1)
}, 1)
@@ -84,7 +86,7 @@ describe("NoR", function(){
describe("called as function", function(){
it("sets its exported gates to the given values", function(){
it("sets its exported gates to the given values", function(done){
var x = 0
var n = new NoR(function(a, b, c){
x = a() + b() + c()
@@ -93,6 +95,8 @@ describe("NoR", function(){
n(1, 2, 3)
setTimeout(function(){
expect(x).to.equal(6)
done()
}, 1)
})
@@ -128,13 +132,15 @@ describe("NoR", function(){
})
it("is executed having this set to the gate object", function(){
it("is executed having this set to the gate object", function(done){
var x
var n = new NoR(function(a){ x = this })
expect(x).to.be.undefined
n.a(99)
setTimeout(function(){
expect(x).to.equal(n)
done()
}, 1)
})
@@ -150,7 +156,7 @@ describe("NoR", function(){
expect(n.self()).to.equal(99)
})
it("on change triggers gate execution", function(){
it("on change triggers gate execution", function(done){
var x
var n = new NoR(function(){
x = this.self()
@@ -160,6 +166,8 @@ describe("NoR", function(){
n.self(88)
setTimeout(function(){
expect(x).to.equal(88)
done()
}, 1)
})
@@ -195,6 +203,44 @@ describe("NoR", function(){
expect(x).to.equal(10)
})
it("can bind a cell to execute the gate on change", function(done){
var x
var n = new NoR(function(){
x = this.b()
}, function(b) {
b.subscribe(this)
this.b = b
})
n.b(99)
setTimeout(function(){
expect(x).to.equal(99)
done()
}, 2)
})
it("can set a cell not to execute the gate on change", function(done){
var x = 0, y
var n = new NoR(function(a, b){
x += 1
y = a()
}, function(b) {
b.unsubscribe(this)
})
n.a(99)
setTimeout(function(){
expect(n.a()).to.equal(99)
expect(x).to.equal(1)
expect(y).to.equal(99)
n.b(10)
setTimeout(function(){
expect(x).to.equal(1)
expect(y).to.equal(99)
done()
}, 1)
}, 1)
})
})
})

0 comments on commit 8c4da62

Please sign in to comment.