diff --git a/packages/ember-metal/lib/alias.js b/packages/ember-metal/lib/alias.js index 9da59bbc283..91cf2762cb1 100644 --- a/packages/ember-metal/lib/alias.js +++ b/packages/ember-metal/lib/alias.js @@ -73,3 +73,22 @@ function AliasedProperty_oneWaySet(obj, keyName, value) { // Backwards compatibility with Ember Data AliasedProperty.prototype._meta = undefined; AliasedProperty.prototype.meta = ComputedProperty.prototype.meta; + +AliasedProperty.prototype.isCacheable = function(meta) { + var desc = meta.descs[this.altKey]; + return desc && desc.isCacheable(); +}; + +AliasedProperty.prototype.cacheGet = function(meta, key) { + var desc = meta.descs[this.altKey]; + return desc && desc.cacheGet(meta, this.altKey); +}; + +AliasedProperty.prototype.lazyGet = function(obj, meta, key) { + var desc = meta.descs[this.altKey]; + if (this.isCacheable(meta)) { + return desc.lazyGet(obj, meta, this.altKey); + } else { + return this.get(obj, this.altKey); + } +}; diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index 9e9e99a9633..a8a019c7db1 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -108,12 +108,8 @@ function lazyGet(obj, key) { // if a CP only return cached value var desc = meta && meta.descs[key]; - if (desc && desc._cacheable) { - if (key in meta.cache) { - return meta.cache[key]; - } else { - return undefined; - } + if (desc) { + return desc.lazyGet(obj, meta, key); } return get(obj, key); diff --git a/packages/ember-metal/lib/computed.js b/packages/ember-metal/lib/computed.js index 208f54f101f..72805899f2b 100644 --- a/packages/ember-metal/lib/computed.js +++ b/packages/ember-metal/lib/computed.js @@ -133,7 +133,29 @@ ComputedPropertyPrototype._dependentKeys = undefined; ComputedPropertyPrototype._suspended = undefined; ComputedPropertyPrototype._meta = undefined; -/** +ComputedPropertyPrototype.lazyGet = function(obj, meta, key) { + if (this.isCacheable(meta)) { + return this.cacheGet(meta, key); + } else { + return this.get(obj, key); + } +}; + + +ComputedPropertyPrototype.cacheGet = function(meta, key) { + var result = meta.cache[key]; + if (result === UNDEFINED) { + return undefined; + } else { + return result; + } +}; + +ComputedPropertyPrototype.isCacheable = function(meta) { + return this._cacheable; +}; + + /** Properties are cacheable by default. Computed property will automatically cache the return value of your function until one of the dependent keys changes. @@ -503,11 +525,19 @@ function computed(func) { */ function cacheFor(obj, key) { var meta = obj['__ember_meta__']; - var cache = meta && meta.cache; - var ret = cache && cache[key]; + if (meta) { + var descs = meta.descs; + var desc = descs && descs[key]; + if (desc) { + return desc.cacheGet(meta, key); + } else { + var cache = meta.cache; + var ret = cache && cache[key]; - if (ret === UNDEFINED) { return undefined; } - return ret; + if (ret === UNDEFINED) { return undefined; } + return ret; + } + } } cacheFor.set = function(cache, key, value) { diff --git a/packages/ember-metal/tests/alias_test.js b/packages/ember-metal/tests/alias_test.js index 3d60fac782f..77ef8176fb0 100644 --- a/packages/ember-metal/tests/alias_test.js +++ b/packages/ember-metal/tests/alias_test.js @@ -1,11 +1,18 @@ import { alias } from "ember-metal/alias"; -import { Descriptor, defineProperty } from "ember-metal/properties"; +import { + Descriptor, + defineProperty +} from "ember-metal/properties"; import { get } from 'ember-metal/property_get'; import { set } from 'ember-metal/property_set'; import { meta } from 'ember-metal/utils'; import { isWatching } from "ember-metal/watching"; -import { addObserver, removeObserver } from "ember-metal/observer"; +import { + addObserver, + removeObserver +} from "ember-metal/observer"; import { mixin, observer } from 'ember-metal/mixin'; +import { computed } from 'ember-metal/computed'; var obj, count; @@ -58,3 +65,39 @@ test('immediately sets up dependencies if already being watched', function() { set(obj, 'foo.faz', 'BAR'); equal(count, 1); }); + +test("Ember.cacheFor simple", function() { + defineProperty(obj, 'baz', computed(function() { + return 'quz'; + })); + defineProperty(obj, 'bar', alias('baz')); + equal(Ember.cacheFor(obj, 'bar'), undefined); + Ember.get(obj, 'bar'); + deepEqual(Ember.cacheFor(obj, 'bar'), 'quz'); +}); + +test("Ember.cacheFor nonCP", function() { + defineProperty(obj, 'bar', alias('foo')); + equal(Ember.cacheFor(obj, 'bar'), undefined); + Ember.get(obj, 'bar'); + equal(Ember.cacheFor(obj, 'bar'), undefined); +}); + +test("Ember.cacheFor non path CP", function() { + defineProperty(obj, 'bar', alias('foo.faz')); + equal(Ember.cacheFor(obj, 'bar'), undefined); + Ember.get(obj, 'bar'); + equal(Ember.cacheFor(obj, 'bar'), undefined); +}); + + +test("Ember.cacheFor path CP", function() { + obj.bro = { }; + defineProperty(obj.bro, 'bar', computed(function() { + return 'hombre'; + })); + defineProperty(obj, 'bar', alias('bro.bar')); + equal(Ember.cacheFor(obj, 'bar'), undefined); + equal(Ember.get(obj, 'bar'), 'hombre'); + equal(Ember.cacheFor(obj, 'bar'), 'hombre'); +}); diff --git a/packages/ember-metal/tests/observer_test.js b/packages/ember-metal/tests/observer_test.js index 8ca667b3836..1135bd224cf 100644 --- a/packages/ember-metal/tests/observer_test.js +++ b/packages/ember-metal/tests/observer_test.js @@ -35,7 +35,7 @@ import { } from "ember-metal/property_events"; import { get } from 'ember-metal/property_get'; import { set } from 'ember-metal/property_set'; - +import { alias } from 'ember-metal/alias'; // .......................................................... // ADD OBSERVER // @@ -904,10 +904,9 @@ QUnit.module('addObserver - dependentkey with chained properties', { } }); - testBoth('depending on a chain with a computed property', function (get, set){ defineProperty(obj, 'computed', computed(function () { - return {foo: 'bar'}; + return { foo: 'bar' }; })); var changed = 0; @@ -922,6 +921,23 @@ testBoth('depending on a chain with a computed property', function (get, set){ equal(changed, 1, 'should fire observer'); }); +testBoth('depending on a chain with Alias property of a cp does not computed the CP', function (get, set){ + defineProperty(obj, 'computed', computed(function () { + return { foo: 'bar' }; + })); + + defineProperty(obj, 'alias', alias('computed')); + + var changed = 0; + addObserver(obj, 'alias.foo', function () { + changed++; + }); + + equal(undefined, cacheFor(obj, 'alias'), 'addObserver should not compute CP'); + + set(obj, 'computed.foo', 'baz'); +}); + testBoth('depending on a simple chain', function(get, set) { var val ;