Skip to content

Commit 9803c31

Browse files
committed
throw upon nested attributed with dependencies
1 parent 116e4a9 commit 9803c31

File tree

2 files changed

+60
-32
lines changed

2 files changed

+60
-32
lines changed

index.js

Lines changed: 23 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -8,18 +8,15 @@ var methods = {
88
return this(!this.value)
99
},
1010
change: function(fn) {
11-
if(fn) {
12-
this.on('change', fn) // setup observer
13-
}
14-
else { // force the change
15-
var val = this()
16-
this.emit('change', val, this.old)
17-
}
11+
fn
12+
? this.on('change', fn) // setup observer
13+
: this.emit('change', this(), this.old)
1814
return this
1915
},
2016
toString: function() {
21-
return "attr:"+JSON.stringify(this.value)
22-
}
17+
return "attr:" + JSON.stringify(this.value)
18+
},
19+
'constructor': Attr
2320
}
2421

2522
Emitter(methods)
@@ -34,10 +31,10 @@ function extend(a, b) {
3431

3532
var watcher = false
3633

37-
function Attr(arg, dependencies) {
34+
function Attr(arg, deps) {
3835

3936
// autocreate computed attr for function values
40-
if(Attr.autocompute && typeof arg =='function') return Attr.computed(arg, dependencies)
37+
if(Attr.autocompute && typeof arg == 'function') return Attr.computed(arg, deps)
4138

4239
function attr(v) {
4340
if(arguments.length) {
@@ -46,8 +43,9 @@ function Attr(arg, dependencies) {
4643
attr.value = v
4744

4845
attr.emit('change', attr.value, attr.old)
49-
} else {
50-
if(watcher) watcher(attr)
46+
}
47+
else {
48+
if(Dependencies.list) Dependencies.list.push(attr)
5149
}
5250
return attr.value
5351
}
@@ -67,28 +65,22 @@ function Attr(arg, dependencies) {
6765

6866
Attr.autocompute = true
6967

68+
function Dependencies(fn) {
69+
if(Dependencies.list) throw 'nested dependencies'
7070

71-
var lastValue = null
72-
73-
Attr.dependencies = function(fn) {
74-
var deps = []
75-
// watches for simple attr reads
76-
watcher = function(attr) {
77-
deps.push(attr)
78-
}
79-
lastValue = fn()
80-
watcher = false
71+
var deps = Dependencies.list = []
72+
Dependencies.lastValue = fn()
73+
delete Dependencies.list
8174
return deps
8275
}
8376

84-
85-
77+
Attr.dependencies = Dependencies
8678

8779
/*
8880
* computed attribute
8981
*/
9082

91-
Attr.computed = function(fn, dependencies) {
83+
Attr.computed = function(fn, deps) {
9284
function attr() {
9385
// nb - there is no setter
9486
attr.old = attr.value
@@ -101,16 +93,16 @@ Attr.computed = function(fn, dependencies) {
10193
extend(attr, methods)
10294

10395
// setup dependencies
104-
if(dependencies) {
96+
if(deps) {
10597
attr.value = fn() // set to initial value
10698
} else {
107-
dependencies = Attr.dependencies(fn)
108-
attr.value = lastValue
99+
deps = Dependencies(fn)
100+
attr.value = Dependencies.lastValue
109101
}
110102

111-
attr.dependencies = dependencies
103+
attr.dependencies = deps
112104

113-
dependencies.forEach(function(dep) {
105+
deps.forEach(function(dep) {
114106
dep.on('change', changeFn)
115107
})
116108

test/test.attr.js

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
var attr = require('attr')
22
, assert = require('component-assert')
33

4+
45
describe('attr()', function(){
56

67
it('should return an attr', function(){
@@ -209,6 +210,41 @@ describe('attr()', function(){
209210
assert(a() == returnsOne )
210211
})
211212

213+
it('should throw if handle nested dependencies', function() {
214+
attr.autocompute = true
215+
216+
217+
var x = attr(1)
218+
, y = attr(2)
219+
, fn
220+
, fn2
221+
222+
assertThrows(function() {
223+
fn = attr(function() {
224+
x()
225+
fn2 = attr(function() {
226+
y()
227+
})
228+
})
229+
})
230+
231+
})
212232
})
233+
234+
213235

214-
})
236+
})
237+
238+
239+
function assertThrows(fn) {
240+
var thrown = false
241+
242+
try {
243+
fn()
244+
}
245+
catch(e) {
246+
thrown = true
247+
}
248+
249+
assert(thrown)
250+
}

0 commit comments

Comments
 (0)