Created
June 9, 2012 21:44
-
-
Save anonymous/2902693 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
diff --git a/packages/ember-metal/lib/accessors.js b/packages/ember-metal/lib/accessors.js | |
index d4d7e6f..48930dd 100644 | |
--- a/packages/ember-metal/lib/accessors.js | |
+++ b/packages/ember-metal/lib/accessors.js | |
@@ -34,18 +34,41 @@ var basicGet = function get(obj, keyName) { | |
} | |
}; | |
+var watchedSet = function(obj, keyName, value) { | |
+ meta(obj).values[keyName] = value; | |
+}; | |
+ | |
+// if there are no getters, keep the raw property up to date | |
+if (!Ember.platform.hasPropertyAccessors) { | |
+ watchedSet = function(obj, keyName, value, values) { | |
+ obj[keyName] = value; | |
+ meta(obj).values[keyName] = value; | |
+ }; | |
+} | |
+ | |
+var META_KEY = Ember.META_KEY; | |
+ | |
/** @private */ | |
var basicSet = function set(obj, keyName, value) { | |
var isObject = 'object' === typeof obj; | |
var hasProp = isObject && !(keyName in obj); | |
+ var changed; | |
// setUnknownProperty is called if `obj` is an object, | |
// the property does not already exist, and the | |
// `setUnknownProperty` method exists on the object | |
- var unknownProp = hasProp && 'function' === typeof obj.setUnknownProperty; | |
+ var unknownProp = hasProp && 'function' === typeof obj.setUnknownProperty, | |
+ meta = obj[META_KEY]; | |
if (unknownProp) { | |
obj.setUnknownProperty(keyName, value); | |
+ } else if (meta && meta.watching[keyName]) { | |
+ // only trigger a change if the value has changed | |
+ if (value !== obj[keyName]) { | |
+ Ember.propertyWillChange(obj, keyName); | |
+ watchedSet(obj, keyName, value); | |
+ Ember.propertyDidChange(obj, keyName); | |
+ } | |
} else { | |
obj[keyName] = value; | |
} | |
diff --git a/packages/ember-metal/lib/mixin.js b/packages/ember-metal/lib/mixin.js | |
index e194ac0..7040419 100644 | |
--- a/packages/ember-metal/lib/mixin.js | |
+++ b/packages/ember-metal/lib/mixin.js | |
@@ -117,7 +117,6 @@ function mergeMixins(mixins, m, descs, values, base) { | |
value = baseValue ? baseValue.concat(value) : Ember.makeArray(value); | |
} | |
- descs[key] = Ember.SIMPLE_PROPERTY; | |
values[key] = value; | |
} | |
} | |
@@ -200,7 +199,7 @@ function applyMixin(obj, mixins, partial) { | |
// | |
// * Handle concatenated properties | |
// * Set up _super wrapping if necessary | |
- // * Set up descriptors (simple, watched or computed properties) | |
+ // * Set up computed property descriptors | |
// * Copying `toString` in broken browsers | |
mergeMixins(mixins, meta(obj), descs, values, obj); | |
@@ -209,8 +208,8 @@ function applyMixin(obj, mixins, partial) { | |
didApply = values.didApplyProperty || obj.didApplyProperty; | |
} | |
- for(key in descs) { | |
- if (!descs.hasOwnProperty(key)) { continue; } | |
+ for(key in values) { | |
+ if (!values.hasOwnProperty(key)) { continue; } | |
desc = descs[key]; | |
value = values[key]; | |
@@ -225,7 +224,7 @@ function applyMixin(obj, mixins, partial) { | |
req[key] = true; | |
} | |
} else { | |
- while (desc instanceof Alias) { | |
+ while (desc && desc instanceof Alias) { | |
var altKey = desc.methodName; | |
if (descs[altKey]) { | |
value = values[altKey]; | |
@@ -235,12 +234,13 @@ function applyMixin(obj, mixins, partial) { | |
value = desc.val(obj, altKey); | |
} else { | |
value = obj[altKey]; | |
- desc = Ember.SIMPLE_PROPERTY; | |
} | |
} | |
if (willApply) { willApply.call(obj, key); } | |
+ // If an observer replaces an existing superclass observer, | |
+ // remove the superclass observers. | |
var observerPaths = getObserverPaths(value), | |
curObserverPaths = observerPaths && getObserverPaths(obj[key]), | |
beforeObserverPaths = getBeforeObserverPaths(value), | |
diff --git a/packages/ember-metal/lib/properties.js b/packages/ember-metal/lib/properties.js | |
index ce00a17..c43a1c7 100644 | |
--- a/packages/ember-metal/lib/properties.js | |
+++ b/packages/ember-metal/lib/properties.js | |
@@ -12,10 +12,10 @@ require('ember-metal/accessors'); | |
var USE_ACCESSORS = Ember.USE_ACCESSORS, | |
GUID_KEY = Ember.GUID_KEY, | |
META_KEY = Ember.META_KEY, | |
- meta = Ember.meta, | |
+ EMPTY_META = Ember.EMPTY_META, | |
+ metaFor = Ember.meta, | |
o_create = Ember.create, | |
- objectDefineProperty = Ember.platform.defineProperty, | |
- SIMPLE_PROPERTY, WATCHED_PROPERTY; | |
+ objectDefineProperty = Ember.platform.defineProperty; | |
// .......................................................... | |
// DESCRIPTOR | |
@@ -23,6 +23,7 @@ var USE_ACCESSORS = Ember.USE_ACCESSORS, | |
/** | |
@private | |
+ EMPTY_META = Ember.EMPTY_META, | |
@constructor | |
Objects of this type can implement an interface to responds requests to | |
@@ -32,227 +33,11 @@ var USE_ACCESSORS = Ember.USE_ACCESSORS, | |
*/ | |
var Descriptor = Ember.Descriptor = function() {}; | |
-var setup = Descriptor.setup = function(obj, keyName, value) { | |
- objectDefineProperty(obj, keyName, { | |
- writable: true, | |
- configurable: true, | |
- enumerable: true, | |
- value: value | |
- }); | |
-}; | |
- | |
-var DescriptorPrototype = Ember.Descriptor.prototype; | |
- | |
-/** | |
- Called whenever we want to set the property value. Should set the value | |
- and return the actual set value (which is usually the same but may be | |
- different in the case of computed properties.) | |
- | |
- @param {Object} obj | |
- The object to set the value on. | |
- | |
- @param {String} keyName | |
- The key to set. | |
- | |
- @param {Object} value | |
- The new value | |
- | |
- @returns {Object} value actual set value | |
-*/ | |
-DescriptorPrototype.set = function(obj, keyName, value) { | |
- obj[keyName] = value; | |
- return value; | |
-}; | |
- | |
-/** | |
- Called whenever we want to get the property value. Should retrieve the | |
- current value. | |
- | |
- @param {Object} obj | |
- The object to get the value on. | |
- | |
- @param {String} keyName | |
- The key to retrieve | |
- | |
- @returns {Object} the current value | |
-*/ | |
-DescriptorPrototype.get = function(obj, keyName) { | |
- return get(obj, keyName, obj); | |
-}; | |
- | |
-/** | |
- This is called on the descriptor to set it up on the object. The | |
- descriptor is responsible for actually defining the property on the object | |
- here. | |
- | |
- The passed `value` is the transferValue returned from any previous | |
- descriptor. | |
- | |
- @param {Object} obj | |
- The object to set the value on. | |
- | |
- @param {String} keyName | |
- The key to set. | |
- | |
- @param {Object} value | |
- The transfer value from any previous descriptor. | |
- | |
- @returns {void} | |
-*/ | |
-DescriptorPrototype.setup = setup; | |
- | |
-/** | |
- This is called on the descriptor just before another descriptor takes its | |
- place. This method should at least return the 'transfer value' of the | |
- property - which is the value you want to passed as the input to the new | |
- descriptor's setup() method. | |
- | |
- It is not generally necessary to actually 'undefine' the property as a new | |
- property descriptor will redefine it immediately after this method returns. | |
- | |
- @param {Object} obj | |
- The object to set the value on. | |
- | |
- @param {String} keyName | |
- The key to set. | |
- | |
- @returns {Object} transfer value | |
-*/ | |
-DescriptorPrototype.teardown = function(obj, keyName) { | |
- return obj[keyName]; | |
-}; | |
- | |
-DescriptorPrototype.val = function(obj, keyName) { | |
- return obj[keyName]; | |
-}; | |
- | |
// .......................................................... | |
// SIMPLE AND WATCHED PROPERTIES | |
// | |
-// The exception to this is that any objects managed by Ember but not a descendant | |
-// of Ember.Object will not throw an exception, instead failing silently. This | |
-// prevent errors with other libraries that may attempt to access special | |
-// properties on standard objects like Array. Usually this happens when copying | |
-// an object by looping over all properties. | |
-// | |
-// QUESTION: What is this scenario exactly? | |
-var mandatorySetter = Ember.Descriptor.MUST_USE_SETTER = function() { | |
- if (this instanceof Ember.Object) { | |
- if (this.isDestroyed) { | |
- Ember.assert('You cannot set observed properties on destroyed objects', false); | |
- } else { | |
- Ember.assert('Must use Ember.set() to access this property', false); | |
- } | |
- } | |
-}; | |
- | |
-var WATCHED_DESC = { | |
- configurable: true, | |
- enumerable: true, | |
- set: mandatorySetter | |
-}; | |
- | |
/** @private */ | |
-function rawGet(obj, keyName, values) { | |
- var ret = values[keyName]; | |
- if (ret === undefined && obj.unknownProperty) { | |
- ret = obj.unknownProperty(keyName); | |
- } | |
- return ret; | |
-} | |
- | |
-function get(obj, keyName) { | |
- return rawGet(obj, keyName, obj); | |
-} | |
- | |
-var emptyObject = {}; | |
- | |
-function watchedGet(obj, keyName) { | |
- return rawGet(obj, keyName, meta(obj, false).values || emptyObject); | |
-} | |
- | |
-var hasGetters = Ember.platform.hasPropertyAccessors, rawSet; | |
- | |
-rawSet = function(obj, keyName, value, values) { | |
- values[keyName] = value; | |
-}; | |
- | |
-// if there are no getters, keep the raw property up to date | |
-if (!Ember.platform.hasPropertyAccessors) { | |
- rawSet = function(obj, keyName, value, values) { | |
- obj[keyName] = value; | |
- values[keyName] = value; | |
- }; | |
-} | |
- | |
-/** @private */ | |
-function watchedSet(obj, keyName, value) { | |
- var m = meta(obj), | |
- values = m.values, | |
- changed = value !== values[keyName]; | |
- | |
- if (changed) { | |
- Ember.propertyWillChange(obj, keyName); | |
- rawSet(obj, keyName, value, m.values); | |
- Ember.propertyDidChange(obj, keyName); | |
- } | |
- | |
- return value; | |
-} | |
- | |
-/** @private */ | |
-function makeWatchedGetter(keyName) { | |
- return function() { | |
- return watchedGet(this, keyName); | |
- }; | |
-} | |
- | |
-/** @private */ | |
-function makeWatchedSetter(keyName) { | |
- return function(value) { | |
- return watchedSet(this, keyName, value); | |
- }; | |
-} | |
- | |
-/** | |
- @private | |
- | |
- Private version of simple property that invokes property change callbacks. | |
-*/ | |
-WATCHED_PROPERTY = new Ember.Descriptor(); | |
-WATCHED_PROPERTY.get = watchedGet ; | |
-WATCHED_PROPERTY.set = watchedSet ; | |
- | |
-WATCHED_PROPERTY.setup = function(obj, keyName, value) { | |
- objectDefineProperty(obj, keyName, { | |
- configurable: true, | |
- enumerable: true, | |
- set: mandatorySetter, | |
- get: makeWatchedGetter(keyName) | |
- }); | |
- | |
- meta(obj).values[keyName] = value; | |
-}; | |
- | |
-WATCHED_PROPERTY.teardown = function(obj, keyName) { | |
- var ret = meta(obj).values[keyName]; | |
- delete meta(obj).values[keyName]; | |
- return ret; | |
-}; | |
- | |
-/** | |
- The default descriptor for simple properties. Pass as the third argument | |
- to Ember.defineProperty() along with a value to set a simple value. | |
- | |
- @static | |
- @default Ember.Descriptor | |
-*/ | |
-Ember.SIMPLE_PROPERTY = new Ember.Descriptor(); | |
-SIMPLE_PROPERTY = Ember.SIMPLE_PROPERTY; | |
- | |
-SIMPLE_PROPERTY.unwatched = WATCHED_PROPERTY.unwatched = SIMPLE_PROPERTY; | |
-SIMPLE_PROPERTY.watched = WATCHED_PROPERTY.watched = WATCHED_PROPERTY; | |
// .......................................................... | |
// DEFINING PROPERTIES API | |
@@ -264,6 +49,18 @@ function hasDesc(descs, keyName) { | |
else return !!descs[keyName]; | |
} | |
+var extractValue = function(obj, keyName, watching) { | |
+ if (watching) { | |
+ var values = metaFor(obj).values, | |
+ ret = values[keyName]; | |
+ | |
+ delete values[keyName]; | |
+ return ret; | |
+ } else { | |
+ return obj[keyName]; | |
+ } | |
+}; | |
+ | |
/** | |
@private | |
@@ -299,45 +96,60 @@ function hasDesc(descs, keyName) { | |
}).property('firstName', 'lastName').cacheable()); | |
*/ | |
Ember.defineProperty = function(obj, keyName, desc, val) { | |
- var m = meta(obj, false), | |
- descs = m.descs, | |
- watching = m.watching[keyName]>0, | |
+ var meta = obj[META_KEY] || EMPTY_META, | |
+ descs = meta && meta.descs, | |
+ watching = meta.watching[keyName], | |
+ descriptor = desc instanceof Ember.Descriptor, | |
override = true; | |
- if (val === undefined) { | |
+ var existingDesc = hasDesc(descs, keyName); | |
+ | |
+ if (val === undefined && descriptor) { | |
// if a value wasn't provided, the value is the old value | |
// (which can be obtained by calling teardown on a property | |
// with a descriptor). | |
override = false; | |
- val = hasDesc(descs, keyName) ? descs[keyName].teardown(obj, keyName) : obj[keyName]; | |
- } else if (hasDesc(descs, keyName)) { | |
+ | |
+ if (existingDesc) { val = descs[keyName].teardown(obj, keyName); } | |
+ else { val = extractValue(obj, keyName, watching); } | |
+ | |
+ } else if (existingDesc) { | |
// otherwise, tear down the descriptor, but use the provided | |
// value as the new value instead of the descriptor's current | |
// value. | |
descs[keyName].teardown(obj, keyName); | |
} | |
- if (!desc) { | |
- desc = SIMPLE_PROPERTY; | |
- } | |
- | |
- if (desc instanceof Ember.Descriptor) { | |
- m = meta(obj, true); | |
- descs = m.descs; | |
+ if (descriptor) { | |
+ meta = metaFor(obj); | |
+ descs = meta.descs; | |
- desc = (watching ? desc.watched : desc.unwatched) || desc; | |
descs[keyName] = desc; | |
- desc.setup(obj, keyName, val, watching); | |
+ desc.setup(obj, keyName, val); | |
- // compatibility with ES5 | |
} else { | |
- if (descs[keyName]) meta(obj).descs[keyName] = null; | |
- objectDefineProperty(obj, keyName, desc); | |
+ if (descs[keyName]) { metaFor(obj).descs[keyName] = null; } | |
+ | |
+ if (desc === undefined) { | |
+ if (existingDesc) { | |
+ objectDefineProperty(obj, keyName, { | |
+ enumerable: true, | |
+ configurable: true, | |
+ writable: true, | |
+ value: val | |
+ }); | |
+ } else { | |
+ obj[keyName] = val; | |
+ } | |
+ } else { | |
+ // compatibility with ES5 | |
+ objectDefineProperty(obj, keyName, desc); | |
+ } | |
} | |
// if key is being watched, override chains that | |
// were initialized with the prototype | |
- if (override && watching) Ember.overrideChains(obj, keyName, m); | |
+ if (override && watching) { Ember.overrideChains(obj, keyName, meta); } | |
return this; | |
}; | |
diff --git a/packages/ember-metal/lib/utils.js b/packages/ember-metal/lib/utils.js | |
index bec0bf4..49be05f 100644 | |
--- a/packages/ember-metal/lib/utils.js | |
+++ b/packages/ember-metal/lib/utils.js | |
@@ -137,6 +137,8 @@ var EMPTY_META = { | |
watching: {} | |
}; | |
+Ember.EMPTY_META = EMPTY_META; | |
+ | |
if (Object.freeze) Object.freeze(EMPTY_META); | |
var createMeta = Ember.platform.defineProperty.isSimulated ? o_create : (function(meta) { return meta; }); | |
diff --git a/packages/ember-metal/lib/watching.js b/packages/ember-metal/lib/watching.js | |
index 77a23a7..8f2da28 100644 | |
--- a/packages/ember-metal/lib/watching.js | |
+++ b/packages/ember-metal/lib/watching.js | |
@@ -13,7 +13,7 @@ require('ember-metal/observer'); | |
require('ember-metal/array'); | |
var guidFor = Ember.guidFor, | |
- meta = Ember.meta, | |
+ metaFor = Ember.meta, | |
get = Ember.get, | |
set = Ember.set, | |
normalizeTuple = Ember.normalizeTuple.primitive, | |
@@ -92,7 +92,7 @@ function dependentKeysDidChange(obj, depKey, meta) { | |
/** @private */ | |
function addChainWatcher(obj, keyName, node) { | |
if (!obj || ('object' !== typeof obj)) return; // nothing to do | |
- var m = meta(obj); | |
+ var m = metaFor(obj); | |
var nodes = m.chainWatchers; | |
if (!nodes || nodes.__emberproto__ !== obj) { | |
nodes = m.chainWatchers = { __emberproto__: obj }; | |
@@ -106,7 +106,7 @@ function addChainWatcher(obj, keyName, node) { | |
/** @private */ | |
function removeChainWatcher(obj, keyName, node) { | |
if (!obj || 'object' !== typeof obj) { return; } // nothing to do | |
- var m = meta(obj, false), | |
+ var m = metaFor(obj, false), | |
nodes = m.chainWatchers; | |
if (!nodes || nodes.__emberproto__ !== obj) { return; } //nothing to do | |
if (nodes[keyName]) { delete nodes[keyName][guidFor(node)]; } | |
@@ -132,7 +132,7 @@ function flushPendingChains() { | |
/** @private */ | |
function isProto(pvalue) { | |
- return meta(pvalue, false).proto === pvalue; | |
+ return metaFor(pvalue, false).proto === pvalue; | |
} | |
// A ChainNode watches a single key on an object. If you provide a starting | |
@@ -368,7 +368,7 @@ ChainNodePrototype.didChange = function(suppressEvent) { | |
// the current object. | |
/** @private */ | |
function chainsFor(obj) { | |
- var m = meta(obj), ret = m.chains; | |
+ var m = metaFor(obj), ret = m.chains; | |
if (!ret) { | |
ret = m.chains = new ChainNode(null, null, obj); | |
} else if (ret.value() !== obj) { | |
@@ -410,7 +410,56 @@ function chainsDidChange(obj, keyName, m) { | |
// WATCH | |
// | |
-var WATCHED_PROPERTY = Ember.SIMPLE_PROPERTY.watched; | |
+ | |
+// The exception to this is that any objects managed by Ember but not a descendant | |
+// of Ember.Object will not throw an exception, instead failing silently. This | |
+// prevent errors with other libraries that may attempt to access special | |
+// properties on standard objects like Array. Usually this happens when copying | |
+// an object by looping over all properties. | |
+// | |
+// QUESTION: What is this scenario exactly? | |
+var mandatorySetter = Ember.Descriptor.MUST_USE_SETTER = function() { | |
+ if (Ember.Object && this instanceof Ember.Object) { | |
+ if (this.isDestroyed) { | |
+ Ember.assert('You cannot set observed properties on destroyed objects', false); | |
+ } else { | |
+ Ember.assert('Must use Ember.set() to access this property', false); | |
+ } | |
+ } | |
+}; | |
+ | |
+var switchToWatched = function(obj, keyName, meta) { | |
+ var value = obj[keyName]; | |
+ meta.values[keyName] = value; | |
+ | |
+ if (Ember.platform.hasPropertyAccessors) { | |
+ var desc = { | |
+ configurable: true, | |
+ enumerable: true, | |
+ set: mandatorySetter, | |
+ get: function(key) { | |
+ return meta.values[keyName]; | |
+ } | |
+ }; | |
+ | |
+ Ember.platform.defineProperty(obj, keyName, desc); | |
+ } | |
+}; | |
+ | |
+var switchToUnwatched = function(obj, keyName, meta) { | |
+ var value = obj[keyName]; | |
+ delete meta.values[keyName]; | |
+ | |
+ if (Ember.platform.hasPropertyAccessors) { | |
+ var desc = { | |
+ configurable: true, | |
+ enumerable: true, | |
+ value: value | |
+ }; | |
+ | |
+ Ember.platform.defineProperty(obj, keyName, desc); | |
+ } | |
+}; | |
/** | |
@private | |
@@ -425,7 +474,7 @@ Ember.watch = function(obj, keyName) { | |
// can't watch length on Array - it is special... | |
if (keyName === 'length' && Ember.typeOf(obj) === 'array') { return this; } | |
- var m = meta(obj), watching = m.watching, desc; | |
+ var m = metaFor(obj), watching = m.watching, desc; | |
// activate watching first time | |
if (!watching[keyName]) { | |
@@ -435,9 +484,7 @@ Ember.watch = function(obj, keyName) { | |
obj.willWatchProperty(keyName); | |
} | |
- desc = m.descs[keyName]; | |
- desc = desc ? desc.watched : WATCHED_PROPERTY; | |
- if (desc) { Ember.defineProperty(obj, keyName, desc); } | |
+ if (!desc) { switchToWatched(obj, keyName, m); } | |
} else { | |
chainsFor(obj).add(keyName); | |
} | |
@@ -449,7 +496,7 @@ Ember.watch = function(obj, keyName) { | |
}; | |
Ember.isWatching = function(obj, keyName) { | |
- return !!meta(obj).watching[keyName]; | |
+ return !!metaFor(obj).watching[keyName]; | |
}; | |
Ember.watch.flushPending = flushPendingChains; | |
@@ -459,14 +506,15 @@ Ember.unwatch = function(obj, keyName) { | |
// can't watch length on Array - it is special... | |
if (keyName === 'length' && Ember.typeOf(obj) === 'array') { return this; } | |
- var watching = meta(obj).watching, desc, descs; | |
+ var watching = metaFor(obj).watching, desc, descs; | |
if (watching[keyName] === 1) { | |
watching[keyName] = 0; | |
if (isKeyName(keyName)) { | |
- desc = meta(obj).descs[keyName]; | |
- desc = desc ? desc.unwatched : SIMPLE_PROPERTY; | |
- if (desc) { Ember.defineProperty(obj, keyName, desc); } | |
+ var meta = metaFor(obj); | |
+ desc = meta.descs[keyName]; | |
+ | |
+ if (!desc) { switchToUnwatched(obj, keyName, meta); } | |
if ('function' === typeof obj.didUnwatchProperty) { | |
obj.didUnwatchProperty(keyName); | |
@@ -490,7 +538,7 @@ Ember.unwatch = function(obj, keyName) { | |
safe to call multiple times. | |
*/ | |
Ember.rewatch = function(obj) { | |
- var m = meta(obj, false), chains = m.chains, bindings = m.bindings, key, b; | |
+ var m = metaFor(obj, false), chains = m.chains, bindings = m.bindings, key, b; | |
// make sure the object has its own guid. | |
if (GUID_KEY in obj && !obj.hasOwnProperty(GUID_KEY)) { | |
@@ -527,7 +575,7 @@ Ember.rewatch = function(obj) { | |
@returns {void} | |
*/ | |
function propertyWillChange(obj, keyName, value) { | |
- var m = meta(obj, false), | |
+ var m = metaFor(obj, false), | |
watching = m.watching[keyName] > 0 || keyName === 'length', | |
proto = m.proto, | |
desc = m.descs[keyName]; | |
@@ -562,7 +610,7 @@ Ember.propertyWillChange = propertyWillChange; | |
@returns {void} | |
*/ | |
function propertyDidChange(obj, keyName) { | |
- var m = meta(obj, false), | |
+ var m = metaFor(obj, false), | |
watching = m.watching[keyName] > 0 || keyName === 'length', | |
proto = m.proto, | |
desc = m.descs[keyName]; | |
diff --git a/packages/ember-metal/tests/binding/connect_test.js b/packages/ember-metal/tests/binding/connect_test.js | |
index 081ddb0..88d1aab 100644 | |
--- a/packages/ember-metal/tests/binding/connect_test.js | |
+++ b/packages/ember-metal/tests/binding/connect_test.js | |
@@ -38,6 +38,8 @@ function performTest(binding, a, b, get, set, connect) { | |
equal(get(b, 'bar'), 'BARF', 'a should have changed'); | |
} | |
+module("Ember.Binding"); | |
+ | |
testBoth('Connecting a binding between two properties', function(get, set) { | |
var a = { foo: 'FOO', bar: 'BAR' }; | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment