Permalink
Browse files

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

…tion
  • Loading branch information...
1 parent fe16d83 commit 8c4da6243a7312adac85e301f87e3f6e062d25df @vic committed Aug 15, 2012
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.