diff --git a/README.md b/README.md index cdf593b..bfe3458 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ attr ==== -Evented Property getter/setter component +Evented Property getter/setter component and automatic dependency calculation ## API @@ -66,9 +66,9 @@ name.on('change', function(new_name, old_name) { These have the same API, except no setter and a function is passed in and is run to determine the intial value -### attr.computed(fn) +### attr.computed(fn, dependencies) - Creates a computed attr: + Creates a computed attr. If dependencies is not set explicitly, they are automatically calculated ```javascript fullName = attr.computed(function() { @@ -78,20 +78,10 @@ fullName = attr.computed(function() { fullName() // => 'Homer Simpson' ``` -### attr.depends() +### attr.depencencies - Returns the current dependencies + Contains the current dependencies -### attr.depends(array) - - Set dependencies. attr is recalculated whenever a dependency changes - -```javascript -fullName.depends([firstName, surName]) -firstName('Bart') - -fullName.value // => 'Bart Simpson' -``` # Testing diff --git a/index.js b/index.js index 65c0aed..33a473f 100644 --- a/index.js +++ b/index.js @@ -32,17 +32,22 @@ function extend(a, b) { * simple attribute */ -function createAttr(arg) { +var watcher = false + +function Attr(arg) { // IDEA: autocreate computed attr for function values - // if(typeof arg =='function') return createAttr.computed(arg) + // if(typeof arg =='function') return Attr.computed(arg) function attr(v) { if(arguments.length) { // setter attr.old = attr.value attr.value = v + attr.emit('change', attr.value, attr.old) + } else { + if(watcher) watcher(attr) } return attr.value } @@ -56,11 +61,28 @@ function createAttr(arg) { return attr } + + +Attr.dependencies = function(fn) { + var deps = [] + // watches for simple attr reads + watcher = function(attr) { + deps.push(attr) + } + var val = fn() + watcher = false + return { + value: val, + depends: deps + } +} + + /* * computed attribute */ -createAttr.computed = function(fn) { +Attr.computed = function(fn, depends) { function attr() { // nb - there is no setter attr.old = attr.value @@ -72,31 +94,22 @@ createAttr.computed = function(fn) { // mixin common methods extend(attr, methods) - // set to initial value - attr.value = fn() - // setup dependencies - attr._depends = [] - - // dependency setter - attr.depends = function(deps) { - // getter - if(arguments.length == 0) return attr._depends - - // unbind old - attr._depends.forEach(function(dep) { - dep.off('change', changeFn) - }) - - attr._depends = deps - // bind new - deps.forEach(function(dep) { - dep.on('change', changeFn) - }) - return attr + if(depends) { + attr.value = fn() // set to initial value + } else { + var o = Attr.dependencies(fn) + depends = o.depends + attr.value = o.value } - // static change function for binding + attr.depends = depends + + depends.forEach(function(dep) { + dep.on('change', changeFn) + }) + + // static change function function changeFn() { attr.change() } @@ -104,4 +117,4 @@ createAttr.computed = function(fn) { return attr } -module.exports = createAttr \ No newline at end of file +module.exports = Attr \ No newline at end of file diff --git a/test/test.attr.js b/test/test.attr.js index feea894..f5f583b 100644 --- a/test/test.attr.js +++ b/test/test.attr.js @@ -136,20 +136,37 @@ describe('attr()', function(){ var fullName = attr.computed(function() {}) - assert(fullName.depends().length == 0) + assert(fullName.depends.length == 0) }) + it('has 2 dependencies calculated automatically', function(){ + + var firstName = attr('John') + var surName = attr('Bob') + + var fullName = attr.computed(function() { return firstName() + surName() }) + + assert(fullName.depends.length == 2) + }) + + it('has 1 dependencies when set explicitly', function(){ + + var firstName = attr('John') + var surName = attr('Bob') + + var fullName = attr.computed(function() { return firstName() + surName() }, [firstName]) + + assert(fullName.depends.length == 1) + }) - it('recalcs when a dependency changes', function(){ - var firstName = attr('John') + it('recalcs when a dependency changes', function(){ + var firstName = attr('John') var surName = attr('Bob') var fullName = attr.computed(function() { return firstName() + ' ' + surName() - }).depends([surName, firstName]) - - assert(fullName._depends.length == 2) + }) surName('Sandy')