From 5868df395fdcd66f7f44f558b4a5aa619a20a8a3 Mon Sep 17 00:00:00 2001 From: Kris Selden Date: Wed, 5 Aug 2015 02:46:49 -0700 Subject: [PATCH] [PERF beta] `@each` should remain a stable node for chains. `@each` was designed for chaining, the special cased eager behavior + it invalidating for array changes meant that the EachProxy and chains were rebuilt every array change, instead of the leaves just changing. Conflicts: packages/ember-runtime/lib/system/each_proxy.js packages/ember-runtime/tests/mixins/array_test.js --- packages/ember-metal/lib/chains.js | 17 +- packages/ember-metal/lib/expand_properties.js | 2 +- .../tests/expand_properties_test.js | 5 +- packages/ember-runtime/lib/mixins/array.js | 27 +-- .../ember-runtime/lib/system/each_proxy.js | 227 +++++------------- .../ember-runtime/tests/mixins/array_test.js | 20 -- .../tests/suites/mutable_array/addObject.js | 2 +- .../tests/suites/mutable_array/clear.js | 2 +- .../tests/suites/mutable_array/insertAt.js | 24 +- .../tests/suites/mutable_array/popObject.js | 4 +- .../tests/suites/mutable_array/pushObject.js | 4 +- .../tests/suites/mutable_array/removeAt.js | 10 +- .../suites/mutable_array/removeObject.js | 2 +- .../tests/suites/mutable_array/replace.js | 10 +- .../suites/mutable_array/reverseObjects.js | 2 +- .../tests/suites/mutable_array/setObjects.js | 4 +- .../tests/suites/mutable_array/shiftObject.js | 4 +- .../suites/mutable_array/unshiftObject.js | 6 +- .../suites/mutable_array/unshiftObjects.js | 6 +- 19 files changed, 116 insertions(+), 262 deletions(-) diff --git a/packages/ember-metal/lib/chains.js b/packages/ember-metal/lib/chains.js index 0111e832ead..290845f7bd9 100644 --- a/packages/ember-metal/lib/chains.js +++ b/packages/ember-metal/lib/chains.js @@ -192,15 +192,6 @@ function ChainNode(parent, key, value) { addChainWatcher(this._object, this._key, this); } } - - // Special-case: the EachProxy relies on immediate evaluation to - // establish its observers. - // - // TODO: Replace this with an efficient callback that the EachProxy - // can implement. - if (this._parent && this._parent._key === '@each') { - this.value(); - } } function lazyGet(obj, key) { @@ -216,7 +207,7 @@ function lazyGet(obj, key) { } // Use `get` if the return value is an EachProxy or an uncacheable value. - if (key === '@each' || isVolatile(obj[key])) { + if (isVolatile(obj[key])) { return get(obj, key); // Otherwise attempt to get the cached value of the computed property } else { @@ -374,12 +365,6 @@ ChainNode.prototype = { addChainWatcher(obj, this._key, this); } this._value = undefined; - - // Special-case: the EachProxy relies on immediate evaluation to - // establish its observers. - if (this._parent && this._parent._key === '@each') { - this.value(); - } } // then notify chains... diff --git a/packages/ember-metal/lib/expand_properties.js b/packages/ember-metal/lib/expand_properties.js index 1d426d728ee..e7fe1fa3e5d 100644 --- a/packages/ember-metal/lib/expand_properties.js +++ b/packages/ember-metal/lib/expand_properties.js @@ -22,7 +22,7 @@ var SPLIT_REGEX = /\{|\}/; Ember.expandProperties('{foo,bar}', echo); //=> 'foo', 'bar' Ember.expandProperties('foo.{bar,baz}', echo); //=> 'foo.bar', 'foo.baz' Ember.expandProperties('{foo,bar}.baz', echo); //=> 'foo.baz', 'bar.baz' - Ember.expandProperties('foo.{bar,baz}.@each', echo) //=> 'foo.bar.@each', 'foo.baz.@each' + Ember.expandProperties('foo.{bar,baz}.[]', echo) //=> 'foo.bar.[]', 'foo.baz.[]' Ember.expandProperties('{foo,bar}.{spam,eggs}', echo) //=> 'foo.spam', 'foo.eggs', 'bar.spam', 'bar.eggs' Ember.expandProperties('{foo}.bar.{baz}') //=> 'foo.bar.baz' ``` diff --git a/packages/ember-metal/tests/expand_properties_test.js b/packages/ember-metal/tests/expand_properties_test.js index 3e27a999e94..6f5b4df5e9c 100644 --- a/packages/ember-metal/tests/expand_properties_test.js +++ b/packages/ember-metal/tests/expand_properties_test.js @@ -17,9 +17,10 @@ QUnit.test('Properties without expansions are unaffected', function() { expandProperties('a', addProperty); expandProperties('a.b', addProperty); - expandProperties('a.b.@each', addProperty); + expandProperties('a.b.[]', addProperty); + expandProperties('a.b.@each.c', addProperty); - deepEqual(['a', 'a.b', 'a.b.@each'].sort(), foundProperties.sort()); + deepEqual(['a', 'a.b', 'a.b.[]', 'a.b.@each.c'].sort(), foundProperties.sort()); }); QUnit.test('A single expansion at the end expands properly', function() { diff --git a/packages/ember-runtime/lib/mixins/array.js b/packages/ember-runtime/lib/mixins/array.js index 8998bf58574..2fe6be3fbb7 100644 --- a/packages/ember-runtime/lib/mixins/array.js +++ b/packages/ember-runtime/lib/mixins/array.js @@ -26,7 +26,7 @@ import { sendEvent, hasListeners } from 'ember-metal/events'; -import { isWatching } from 'ember-metal/watching'; +import EachProxy from 'ember-runtime/system/each_proxy'; function arrayObserversHelper(obj, target, opts, operation, notify) { var willChange = (opts && opts.willChange) || 'arrayWillChange'; @@ -422,13 +422,13 @@ export default Mixin.create(Enumerable, { } } - // Make sure the @each proxy is set up if anyone is observing @each - if (isWatching(this, '@each')) { - get(this, '@each'); + if (this.__each) { + this.__each.arrayWillChange(this, startIdx, removeAmt, addAmt); } sendEvent(this, '@array:before', [this, startIdx, removeAmt, addAmt]); + if (startIdx >= 0 && removeAmt >= 0 && get(this, 'hasEnumerableObservers')) { removing = []; lim = startIdx + removeAmt; @@ -489,6 +489,11 @@ export default Mixin.create(Enumerable, { } this.enumerableContentDidChange(removeAmt, adding); + + if (this.__each) { + this.__each.arrayDidChange(this, startIdx, removeAmt, addAmt); + } + sendEvent(this, '@array:change', [this, startIdx, removeAmt, addAmt]); var length = get(this, 'length'); @@ -508,10 +513,6 @@ export default Mixin.create(Enumerable, { return this; }, - // .......................................................... - // ENUMERATED PROPERTIES - // - /** Returns a special object that can be used to observe individual properties on the array. Just get an equivalent property on this object and it will @@ -525,15 +526,11 @@ export default Mixin.create(Enumerable, { @public */ '@each': computed(function() { + // TODO use Symbol or add to meta if (!this.__each) { - // ES6TODO: GRRRRR - var EachProxy = requireModule('ember-runtime/system/each_proxy')['EachProxy']; - - this.__each = new EachProxy({ - content: this - }); + this.__each = new EachProxy(this); } return this.__each; - }) + }).volatile() }); diff --git a/packages/ember-runtime/lib/system/each_proxy.js b/packages/ember-runtime/lib/system/each_proxy.js index e2bf3cbc43b..15f9ac0cf59 100644 --- a/packages/ember-runtime/lib/system/each_proxy.js +++ b/packages/ember-runtime/lib/system/each_proxy.js @@ -1,101 +1,16 @@ -/** -@module ember -@submodule ember-runtime -*/ - import Ember from 'ember-metal/core'; // Ember.assert - import { get } from 'ember-metal/property_get'; -import { guidFor } from 'ember-metal/utils'; -import { typeOf } from 'ember-runtime/utils'; -import EmberArray from 'ember-runtime/mixins/array'; // ES6TODO: WAT? Circular dep? -import EmberObject from 'ember-runtime/system/object'; -import { computed } from 'ember-metal/computed'; import { - addObserver, _addBeforeObserver, _removeBeforeObserver, + addObserver, removeObserver } from 'ember-metal/observer'; -import { watchedEvents } from 'ember-metal/events'; -import { defineProperty } from 'ember-metal/properties'; import { - beginPropertyChanges, propertyDidChange, - propertyWillChange, - endPropertyChanges, - changeProperties + propertyWillChange } from 'ember-metal/property_events'; - -var EachArray = EmberObject.extend(EmberArray, { - - init(attr) { - this._super(...arguments); - this._keyName = attr.keyName; - this._owner = attr.owner; - this._content = attr.content; - }, - - objectAt(idx) { - var item = this._content.objectAt(idx); - return item && get(item, this._keyName); - }, - - length: computed(function() { - var content = this._content; - return content ? get(content, 'length') : 0; - }) - -}); - -var IS_OBSERVER = /^.+:(before|change)$/; - -function addObserverForContentKey(content, keyName, proxy, idx, loc) { - var objects = proxy._objects; - var guid; - if (!objects) { - objects = proxy._objects = {}; - } - - while (--loc >= idx) { - var item = content.objectAt(loc); - if (item) { - Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', typeOf(item) === 'instance' || typeOf(item) === 'object'); - _addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); - addObserver(item, keyName, proxy, 'contentKeyDidChange'); - - // keep track of the index each item was found at so we can map - // it back when the obj changes. - guid = guidFor(item); - if (!objects[guid]) { - objects[guid] = []; - } - - objects[guid].push(loc); - } - } -} - -function removeObserverForContentKey(content, keyName, proxy, idx, loc) { - var objects = proxy._objects; - if (!objects) { - objects = proxy._objects = {}; - } - - var indices, guid; - - while (--loc >= idx) { - var item = content.objectAt(loc); - if (item) { - _removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); - removeObserver(item, keyName, proxy, 'contentKeyDidChange'); - - guid = guidFor(item); - indices = objects[guid]; - indices[indices.indexOf(loc)] = null; - } - } -} +import EmptyObject from 'ember-metal/empty_object'; /** This is the object instance returned when you get the `@each` property on an @@ -104,38 +19,15 @@ function removeObserverForContentKey(content, keyName, proxy, idx, loc) { @class EachProxy @private */ -var EachProxy = EmberObject.extend({ - init(attrs) { - this._super(...arguments); - this._content = attrs.content; - - this._content.addArrayObserver(this); - - // in case someone is already observing some keys make sure they are - // added - watchedEvents(this).forEach((eventName) => { - this.didAddListener(eventName); - }); - }, +function EachProxy(content) { + this._content = content; + this._keys = undefined; + this.__ember_meta__ = undefined; +} - /** - You can directly access mapped properties by simply requesting them. - The `unknownProperty` handler will generate an EachArray of each item. - - @method unknownProperty - @param keyName {String} - @param value {*} - @private - */ - unknownProperty(keyName, value) { - var ret = new EachArray({ - content: this._content, - keyName: keyName, - owner: this - }); - defineProperty(this, keyName, null, ret); - this.beginObservingContentKey(keyName); - return ret; +EachProxy.prototype = { + __defineNonEnumerable(property) { + this[property.name] = property.descriptor.value; }, // .......................................................... @@ -143,56 +35,37 @@ var EachProxy = EmberObject.extend({ // Invokes whenever the content array itself changes. arrayWillChange(content, idx, removedCnt, addedCnt) { - var keys = this._keys; - var key, lim; - - lim = removedCnt > 0 ? idx + removedCnt : -1; - beginPropertyChanges(this); - - for (key in keys) { - if (!keys.hasOwnProperty(key)) { continue; } - - if (lim > 0) { removeObserverForContentKey(content, key, this, idx, lim); } - + let keys = this._keys; + let lim = removedCnt > 0 ? idx + removedCnt : -1; + for (let key in keys) { + if (lim > 0) { + removeObserverForContentKey(content, key, this, idx, lim); + } propertyWillChange(this, key); } - - propertyWillChange(this._content, '@each'); - endPropertyChanges(this); }, arrayDidChange(content, idx, removedCnt, addedCnt) { - var keys = this._keys; - var lim; - - lim = addedCnt > 0 ? idx + addedCnt : -1; - changeProperties(function() { - for (var key in keys) { - if (!keys.hasOwnProperty(key)) { continue; } - - if (lim > 0) { addObserverForContentKey(content, key, this, idx, lim); } - - propertyDidChange(this, key); + let keys = this._keys; + let lim = addedCnt > 0 ? idx + addedCnt : -1; + for (let key in keys) { + if (lim > 0) { + addObserverForContentKey(content, key, this, idx, lim); } - - propertyDidChange(this._content, '@each'); - }, this); + propertyDidChange(this, key); + } }, // .......................................................... // LISTEN FOR NEW OBSERVERS AND OTHER EVENT LISTENERS // Start monitoring keys based on who is listening... - didAddListener(eventName) { - if (IS_OBSERVER.test(eventName)) { - this.beginObservingContentKey(eventName.slice(0, -7)); - } + willWatchProperty(property) { + this.beginObservingContentKey(property); }, - didRemoveListener(eventName) { - if (IS_OBSERVER.test(eventName)) { - this.stopObservingContentKey(eventName.slice(0, -7)); - } + didUnwatchProperty(property) { + this.stopObservingContentKey(property); }, // .......................................................... @@ -200,15 +73,15 @@ var EachProxy = EmberObject.extend({ // Actual watch keys on the source content. beginObservingContentKey(keyName) { - var keys = this._keys; + let keys = this._keys; if (!keys) { - keys = this._keys = {}; + keys = this._keys = new EmptyObject(); } if (!keys[keyName]) { keys[keyName] = 1; - var content = this._content; - var len = get(content, 'length'); + let content = this._content; + let len = get(content, 'length'); addObserverForContentKey(content, keyName, this, 0, len); } else { @@ -217,10 +90,10 @@ var EachProxy = EmberObject.extend({ }, stopObservingContentKey(keyName) { - var keys = this._keys; - if (keys && (keys[keyName] > 0) && (--keys[keyName]<=0)) { - var content = this._content; - var len = get(content, 'length'); + let keys = this._keys; + if (keys && (keys[keyName] > 0) && (--keys[keyName] <= 0)) { + let content = this._content; + let len = get(content, 'length'); removeObserverForContentKey(content, keyName, this, 0, len); } @@ -233,9 +106,27 @@ var EachProxy = EmberObject.extend({ contentKeyDidChange(obj, keyName) { propertyDidChange(this, keyName); } -}); - -export { - EachArray, - EachProxy }; + +function addObserverForContentKey(content, keyName, proxy, idx, loc) { + while (--loc >= idx) { + let item = content.objectAt(loc); + if (item) { + Ember.assert('When using @each to observe the array ' + content + ', the array must return an object', typeof item === 'object'); + _addBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + addObserver(item, keyName, proxy, 'contentKeyDidChange'); + } + } +} + +function removeObserverForContentKey(content, keyName, proxy, idx, loc) { + while (--loc >= idx) { + let item = content.objectAt(loc); + if (item) { + _removeBeforeObserver(item, keyName, proxy, 'contentKeyWillChange'); + removeObserver(item, keyName, proxy, 'contentKeyDidChange'); + } + } +} + +export default EachProxy; diff --git a/packages/ember-runtime/tests/mixins/array_test.js b/packages/ember-runtime/tests/mixins/array_test.js index eedf5cd94fa..5e98cead3c3 100644 --- a/packages/ember-runtime/tests/mixins/array_test.js +++ b/packages/ember-runtime/tests/mixins/array_test.js @@ -327,26 +327,6 @@ QUnit.module('EmberArray.@each support', { } }); -QUnit.test('adding an object should notify (@each)', function() { - var called = 0; - - var observerObject = EmberObject.create({ - wasCalled() { - called++; - } - }); - - // get(ary, '@each'); - addObserver(ary, '@each', observerObject, 'wasCalled'); - - ary.addObject(EmberObject.create({ - desc: 'foo', - isDone: false - })); - - equal(called, 1, 'calls observer when object is pushed'); -}); - QUnit.test('adding an object should notify (@each.isDone)', function() { var called = 0; diff --git a/packages/ember-runtime/tests/suites/mutable_array/addObject.js b/packages/ember-runtime/tests/suites/mutable_array/addObject.js index 35620d8efd2..c4cd085dcde 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/addObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/addObject.js @@ -29,7 +29,7 @@ suite.test('[A,B].addObject(C) => [A,B,C] + notify', function() { if (observer.isEnabled) { equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/clear.js b/packages/ember-runtime/tests/suites/mutable_array/clear.js index bfc1de4c417..0617c577cd1 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/clear.js +++ b/packages/ember-runtime/tests/suites/mutable_array/clear.js @@ -41,7 +41,7 @@ suite.test('[X].clear() => [] + notify', function () { equal(Ember.get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/insertAt.js b/packages/ember-runtime/tests/suites/mutable_array/insertAt.js index ef1402017b9..274b3f7c4ba 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/insertAt.js +++ b/packages/ember-runtime/tests/suites/mutable_array/insertAt.js @@ -21,13 +21,13 @@ suite.test('[].insertAt(0, X) => [X] + notify', function() { equal(observer.timesCalledBefore('[]'), 1, 'should have notified [] will change once'); - equal(observer.timesCalledBefore('@each'), 1, 'should have notified @each will change once'); + equal(observer.timesCalledBefore('@each'), 0, 'should not have notified @each will change once'); equal(observer.timesCalledBefore('length'), 1, 'should have notified length will change once'); equal(observer.timesCalledBefore('firstObject'), 1, 'should have notified firstObject will change once'); equal(observer.timesCalledBefore('lastObject'), 1, 'should have notified lastObject will change once'); equal(observer.timesCalled('[]'), 1, 'should have notified [] did change once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each did change once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each did change once'); equal(observer.timesCalled('length'), 1, 'should have notified length did change once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject did change once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject did change once'); @@ -59,13 +59,13 @@ suite.test('[A].insertAt(0, X) => [X,A] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalledBefore('[]'), 1, 'should have notified [] will change once'); - equal(observer.timesCalledBefore('@each'), 1, 'should have notified @each will change once'); + equal(observer.timesCalledBefore('@each'), 0, 'should not have notified @each will change once'); equal(observer.timesCalledBefore('length'), 1, 'should have notified length will change once'); equal(observer.timesCalledBefore('firstObject'), 1, 'should have notified firstObject will change once'); equal(observer.timesCalledBefore('lastObject'), 0, 'should NOT have notified lastObject will change once'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); @@ -89,13 +89,13 @@ suite.test('[A].insertAt(1, X) => [A,X] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalledBefore('[]'), 1, 'should have notified [] will change once'); - equal(observer.timesCalledBefore('@each'), 1, 'should have notified @each will change once'); + equal(observer.timesCalledBefore('@each'), 0, 'should not have notified @each will change once'); equal(observer.timesCalledBefore('length'), 1, 'should have notified length will change once'); equal(observer.timesCalledBefore('firstObject'), 0, 'should NOT have notified firstObject will change once'); equal(observer.timesCalledBefore('lastObject'), 1, 'should have notified lastObject will change once'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -128,13 +128,13 @@ suite.test('[A,B,C].insertAt(0,X) => [X,A,B,C] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalledBefore('[]'), 1, 'should have notified [] will change once'); - equal(observer.timesCalledBefore('@each'), 1, 'should have notified @each will change once'); + equal(observer.timesCalledBefore('@each'), 0, 'should not have notified @each will change once'); equal(observer.timesCalledBefore('length'), 1, 'should have notified length will change once'); equal(observer.timesCalledBefore('firstObject'), 1, 'should have notified firstObject will change once'); equal(observer.timesCalledBefore('lastObject'), 0, 'should NOT have notified lastObject will change once'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); @@ -158,13 +158,13 @@ suite.test('[A,B,C].insertAt(1,X) => [A,X,B,C] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalledBefore('[]'), 1, 'should have notified [] will change once'); - equal(observer.timesCalledBefore('@each'), 1, 'should have notified @each will change once'); + equal(observer.timesCalledBefore('@each'), 0, 'should not have notified @each will change once'); equal(observer.timesCalledBefore('length'), 1, 'should have notified length will change once'); equal(observer.timesCalledBefore('firstObject'), 0, 'should NOT have notified firstObject will change once'); equal(observer.timesCalledBefore('lastObject'), 0, 'should NOT have notified lastObject will change once'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); @@ -188,13 +188,13 @@ suite.test('[A,B,C].insertAt(3,X) => [A,B,C,X] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalledBefore('[]'), 1, 'should have notified [] will change once'); - equal(observer.timesCalledBefore('@each'), 1, 'should have notified @each will change once'); + equal(observer.timesCalledBefore('@each'), 0, 'should not have notified @each will change once'); equal(observer.timesCalledBefore('length'), 1, 'should have notified length will change once'); equal(observer.timesCalledBefore('firstObject'), 0, 'should NOT have notified firstObject will change once'); equal(observer.timesCalledBefore('lastObject'), 1, 'should have notified lastObject will change once'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/popObject.js b/packages/ember-runtime/tests/suites/mutable_array/popObject.js index 41efc4cf9df..2cdc5918984 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/popObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/popObject.js @@ -39,7 +39,7 @@ suite.test('[X].popObject() => [] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -61,7 +61,7 @@ suite.test('[A,B,C].popObject() => [A,B] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/pushObject.js b/packages/ember-runtime/tests/suites/mutable_array/pushObject.js index 983ff3508a7..5123772151c 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/pushObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/pushObject.js @@ -26,7 +26,7 @@ suite.test('[].pushObject(X) => [X] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -48,7 +48,7 @@ suite.test('[A,B,C].pushObject(X) => [A,B,C,X] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/removeAt.js b/packages/ember-runtime/tests/suites/mutable_array/removeAt.js index 688247ecaa2..b89795e78ee 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/removeAt.js +++ b/packages/ember-runtime/tests/suites/mutable_array/removeAt.js @@ -20,7 +20,7 @@ suite.test('[X].removeAt(0) => [] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -48,7 +48,7 @@ suite.test('[A,B].removeAt(0) => [B] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); @@ -70,7 +70,7 @@ suite.test('[A,B].removeAt(1) => [A] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -92,7 +92,7 @@ suite.test('[A,B,C].removeAt(1) => [A,C] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); @@ -114,7 +114,7 @@ suite.test('[A,B,C,D].removeAt(1,2) => [A,D] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/removeObject.js b/packages/ember-runtime/tests/suites/mutable_array/removeObject.js index a2871790cca..0575c3627e1 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/removeObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/removeObject.js @@ -28,7 +28,7 @@ suite.test('[A,B,C].removeObject(B) => [A,C] + notify', function() { if (observer.isEnabled) { equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/replace.js b/packages/ember-runtime/tests/suites/mutable_array/replace.js index 02d5d1231e9..7b8793c7232 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/replace.js +++ b/packages/ember-runtime/tests/suites/mutable_array/replace.js @@ -16,7 +16,7 @@ suite.test('[].replace(0,0,\'X\') => [\'X\'] + notify', function() { deepEqual(this.toArray(obj), exp, 'post item results'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -38,7 +38,7 @@ suite.test('[A,B,C,D].replace(1,2,X) => [A,X,D] + notify', function() { deepEqual(this.toArray(obj), after, 'post item results'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); @@ -61,7 +61,7 @@ suite.test('[A,B,C,D].replace(1,2,[X,Y]) => [A,X,Y,D] + notify', function() { deepEqual(this.toArray(obj), after, 'post item results'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.validate('length'), false, 'should NOT have notified length'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); @@ -84,7 +84,7 @@ suite.test('[A,B].replace(1,0,[X,Y]) => [A,X,Y,B] + notify', function() { deepEqual(this.toArray(obj), after, 'post item results'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject once'); @@ -106,7 +106,7 @@ suite.test('[A,B,C,D].replace(2,2) => [A,B] + notify', function() { deepEqual(this.toArray(obj), after, 'post item results'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/reverseObjects.js b/packages/ember-runtime/tests/suites/mutable_array/reverseObjects.js index 907e3456d44..c153afc1423 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/reverseObjects.js +++ b/packages/ember-runtime/tests/suites/mutable_array/reverseObjects.js @@ -20,7 +20,7 @@ suite.test('[A,B,C].reverseObjects() => [] + notify', function () { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 0, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/setObjects.js b/packages/ember-runtime/tests/suites/mutable_array/setObjects.js index 93d5c75da84..a465a8efb85 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/setObjects.js +++ b/packages/ember-runtime/tests/suites/mutable_array/setObjects.js @@ -20,7 +20,7 @@ suite.test('[A,B,C].setObjects([]) = > [] + notify', function() { equal(Ember.get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -41,7 +41,7 @@ suite.test('[A,B,C].setObjects([D, E, F, G]) = > [D, E, F, G] + notify', functio equal(Ember.get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/shiftObject.js b/packages/ember-runtime/tests/suites/mutable_array/shiftObject.js index c7d3bcabb53..3d575255e22 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/shiftObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/shiftObject.js @@ -42,7 +42,7 @@ suite.test('[X].shiftObject() => [] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -63,7 +63,7 @@ suite.test('[A,B,C].shiftObject() => [B,C] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js b/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js index b55d917199b..02cfaa50086 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js +++ b/packages/ember-runtime/tests/suites/mutable_array/unshiftObject.js @@ -28,7 +28,7 @@ suite.test('[].unshiftObject(X) => [X] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -50,7 +50,7 @@ suite.test('[A,B,C].unshiftObject(X) => [X,A,B,C] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); @@ -73,7 +73,7 @@ suite.test('[A,B,C].unshiftObject(A) => [A,A,B,C] + notify', function() { equal(get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject'); diff --git a/packages/ember-runtime/tests/suites/mutable_array/unshiftObjects.js b/packages/ember-runtime/tests/suites/mutable_array/unshiftObjects.js index 0385bddf16e..ec9544c1207 100644 --- a/packages/ember-runtime/tests/suites/mutable_array/unshiftObjects.js +++ b/packages/ember-runtime/tests/suites/mutable_array/unshiftObjects.js @@ -26,7 +26,7 @@ suite.test('[].unshiftObjects([A,B,C]) => [A,B,C] + notify', function() { equal(Ember.get(obj, 'length'), items.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); equal(observer.timesCalled('lastObject'), 1, 'should have notified lastObject once'); @@ -48,7 +48,7 @@ suite.test('[A,B,C].unshiftObjects([X,Y]) => [X,Y,A,B,C] + notify', function() { equal(Ember.get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.timesCalled('firstObject'), 1, 'should have notified firstObject once'); @@ -71,7 +71,7 @@ suite.test('[A,B,C].unshiftObjects([A,B]) => [A,B,A,B,C] + notify', function() { equal(Ember.get(obj, 'length'), after.length, 'length'); equal(observer.timesCalled('[]'), 1, 'should have notified [] once'); - equal(observer.timesCalled('@each'), 1, 'should have notified @each once'); + equal(observer.timesCalled('@each'), 0, 'should not have notified @each once'); equal(observer.timesCalled('length'), 1, 'should have notified length once'); equal(observer.validate('firstObject'), false, 'should NOT have notified firstObject');