From 2047e7400b7431e9729be4e686387b445eb9d45b Mon Sep 17 00:00:00 2001 From: "Erik Bryn and James A. Rosen" Date: Mon, 29 Jul 2013 11:51:25 -0700 Subject: [PATCH] Backport warnings and errors for 1.0's Ember.Object.create() behaviour. Closes #2. --- README.md | 35 +---- doc/object_create.md | 32 +++++ .../ember-runtime/lib/system/core_object.js | 28 ++++ .../tests/backports/create_test.js | 124 ++++++++++++++++++ 4 files changed, 186 insertions(+), 33 deletions(-) create mode 100644 doc/object_create.md create mode 100644 packages/ember-runtime/tests/backports/create_test.js diff --git a/README.md b/README.md index 029ec8cef39..fe89420409c 100644 --- a/README.md +++ b/README.md @@ -37,37 +37,6 @@ non-dotted paths, just as in 1.0. See [issue #1](https://github.com/zendesk/ember.js/issues/1) for more information. -## `Ember.Object.create` +## Transitions -This backports the `create` and `createWithMixins` functionality from Ember 1.0 -to Ember 0.9. In Ember 0.9.8.1, the following is perfectly valid: - -```javascript -Ember.Object.create(Ember.Mixin.create(), { - someProperty: function() { return 'some value'; }.property(), - someFunction: function() { return this._super(); } -}); -``` - -In Ember 1.0, that same code throws three exceptions: - - * Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead. - * mber.Object.create no longer supports defining computed properties. - * Ember.Object.create no longer supports defining methods that call _super. - -This helps those migrating from Ember 0.9 to 1.0 by backporting the new -behavior, conditional on a flag, `ENV.CREATE_WITH_MIXINS`, which -has four possible values: - - * `"0.9"` (the default): Ember 0.9.8.1 compatibility; `Ember.Object.create` - accepts `Ember.Mixin`s and `Object`s that contain - `Ember.ComputedProperty`s or `Function`s that call `_super`. - * `"0.9+warn"`: Ember 0.9.8.1 compatibility with warnings. - * `"0.9+deprecate"`: Ember 0.9.8.1 compatibility with deprecation warnings - (errors if `ENV.RAISE_ON_DEPRECATION` is `true`) - * `"1.0"`: Ember 1.0 compatibility; `Ember.Obect.create` will throw an - exception if passed an `Ember.Mixin` or an object that contains an - `Ember.ComputedProperty` or `Function` that calls `_super`. - -See [issue #2](https://github.com/zendesk/ember.js/issues/2) for more -information. + * [Ember.Object.create](doc/object_create.md) diff --git a/doc/object_create.md b/doc/object_create.md new file mode 100644 index 00000000000..03d8e0de2a6 --- /dev/null +++ b/doc/object_create.md @@ -0,0 +1,32 @@ +# `Ember.Object.create` + +This backports the `create` and `createWithMixins` functionality from Ember 1.0 +to Ember 0.9. In Ember 0.9.8.1, the following is perfectly valid: + +```javascript +Ember.Object.create(Ember.Mixin.create(), { + someProperty: function() { return 'some value'; }.property(), + someFunction: function() { return this._super(); } +}); +``` + +In Ember 1.0, that same code throws three exceptions: + + * Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead. + * Ember.Object.create no longer supports defining computed properties. + * Ember.Object.create no longer supports defining methods that call _super. + +This helps those migrating from Ember 0.9 to 1.0 by backporting the new +behavior, conditional on a flag, `ENV.CREATE_WITH_MIXINS`, which +has four possible values: + + * `null` (the default): Ember 0.9.8.1 compatibility; `Ember.Object.create` + accepts `Ember.Mixin`s and `Object`s that contain + `Ember.ComputedProperty`s or `Function`s that call `_super`. + * `"warn"`: Ember 0.9.8.1 compatibility with warnings. + * `"error"`: Ember 1.0 compatibility; `Ember.Object.create` will throw an + exception if passed an `Ember.Mixin` or an object that contains an + `Ember.ComputedProperty` or `Function` that calls `_super`. + +See [issue #2](https://github.com/zendesk/ember.js/issues/2) for more +information. diff --git a/packages/ember-runtime/lib/system/core_object.js b/packages/ember-runtime/lib/system/core_object.js index e16e301d740..4da556ec8ba 100644 --- a/packages/ember-runtime/lib/system/core_object.js +++ b/packages/ember-runtime/lib/system/core_object.js @@ -19,6 +19,26 @@ var o_create = Ember.platform.create, a_slice = Array.prototype.slice, meta = Ember.meta; +function checkForDeprecations(initMixins) { + var level = Ember.ENV.CREATE_WITH_MIXINS, + op = {warn: Ember.warn, error: Ember.error}[level]; + if (!level || level === '0.9') { return; } + + var currentMixin, currentValue; + for (var i = 0, l = initMixins.length; i < l; i++) { + currentMixin = initMixins[i]; + op("Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead.", !(currentMixin instanceof Ember.Mixin)); + + for (var key in currentMixin) { + currentValue = currentMixin[key]; + op("Ember.Object.create no longer supports defining computed properties.", !(currentValue instanceof Ember.ComputedProperty)); + + var usesSuper = typeof currentValue === 'function' && currentValue.toString().indexOf('._super') !== -1; + op("Ember.Object.create no longer supports defining methods that call _super.", !usesSuper); + } + } +} + /** @private */ function makeCtor() { @@ -31,6 +51,8 @@ function makeCtor() { var Class = function() { if (!wasApplied) { Class.proto(); } // prepare prototype... if (initMixins) { + checkForDeprecations(initMixins); + this.reopen.apply(this, initMixins); initMixins = null; rewatch(this); // always rewatch just in case @@ -191,6 +213,12 @@ var ClassMixin = Ember.Mixin.create({ return new C(); }, + createWithMixins: function() { + var C = this; + if (arguments.length>0) { this._initMixins(arguments); } + return new C(); + }, + reopen: function() { this.willReopen(); var PrototypeMixin = this.PrototypeMixin; diff --git a/packages/ember-runtime/tests/backports/create_test.js b/packages/ember-runtime/tests/backports/create_test.js new file mode 100644 index 00000000000..63a163d5dca --- /dev/null +++ b/packages/ember-runtime/tests/backports/create_test.js @@ -0,0 +1,124 @@ +module("Ember.Object.createWithMixins"); + +test("it exists", function() { + ok(Ember.Object.createWithMixins); +}); + +test("it instantiates objects", function() { + var obj = Ember.Object.createWithMixins({ foo: 'bar' }); + ok(obj); + equal(obj.get('foo'), 'bar'); +}); + +test('it works on subclasses', function() { + var Klass = Ember.Object.extend({ + foo: 'bar' + }); + var obj = Klass.createWithMixins({ foo: 'baz' }); + equal(obj.get('foo'), 'baz'); +}); + +var originalFlag, originalWarn, warnings; + +module("Backported Ember.Object.create", { + setup: function() { + originalFlag = Ember.ENV.CREATE_WITH_MIXINS; + originalWarn = Ember.Logger.warn; + warnings = []; + Ember.Logger.warn = function(msg) { + warnings.push(msg.replace("WARNING: ", "")); + }; + }, + teardown: function() { + Ember.ENV.CREATE_WITH_MIXINS = originalFlag; + Ember.Logger.warn = originalWarn; + } +}); + +test("passing a mixin with warnings off", function() { + Ember.ENV.CREATE_WITH_MIXINS = null; + Ember.Object.create(Ember.Mixin.create()); + equal(warnings.length, 0); +}); + +test("passing a mixin with warnings on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'warn'; + + Ember.Object.create(Ember.Mixin.create()); + equal(warnings.length, 1); + equal(warnings[0], "Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead."); +}); + +test("passing a mixin with errors on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'error'; + raises(function() { + Ember.Object.create(Ember.Mixin.create()); + }, "Ember.Object.create no longer supports mixing in other definitions, use createWithMixins instead."); +}); + +test("passing computed properties with warnings off", function() { + Ember.ENV.CREATE_WITH_MIXINS = null; + + Ember.Object.create({ + aProp: Ember.computed(function() { return 'three'; }) + }); + equal(warnings.length, 0); +}); + +test("passing computed properties with warnings on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'warn'; + + Ember.Object.create({ + aProp: Ember.computed(function() { return 'three'; }) + }); + equal(warnings.length, 1); + equal(warnings[0], "Ember.Object.create no longer supports defining computed properties."); +}); + +test("passing a computed property with errors on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'error'; + raises(function() { + Ember.Object.create({ + aProp: Ember.computed(function() { return 'three'; }) + }); + }, "Ember.Object.create no longer supports defining computed properties."); +}); + +test("passing methods that use _super with warnings off", function() { + Ember.ENV.CREATE_WITH_MIXINS = null; + + Ember.Object.create({ + aProp: function() { return this._super(); } + }); + equal(warnings.length, 0); +}); + +test("passing methods that use _super with warnings on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'warn'; + + Ember.Object.create({ + aProp: function() { return this._super(); } + }); + equal(warnings.length, 1); + equal(warnings[0], "Ember.Object.create no longer supports defining methods that call _super."); +}); + +test("passing methods that *don't* use _super with warnings on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'warn'; + + Ember.Object.create({ + aProp: function() { return this._notSuper(); } + }); + equal(warnings.length, 0); +}); + +test("passing methods that use _super with errors on", function() { + Ember.ENV.CREATE_WITH_MIXINS = 'error'; + + raises(function() { + Ember.Object.create({ + aProp: function() { return this._super(); } + }); + }); +}); +