Skip to content

Commit

Permalink
Merge pull request #12609 from dgeb/fake-container
Browse files Browse the repository at this point in the history
[FEATURE ember-container-inject-owner] Inject fake container with deprecations.
  • Loading branch information
rwjblue committed Nov 16, 2015
2 parents 04ec1c6 + 869d0d7 commit f434c9f
Show file tree
Hide file tree
Showing 3 changed files with 101 additions and 8 deletions.
29 changes: 22 additions & 7 deletions packages/container/lib/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { assert, deprecate } from 'ember-metal/debug';
import dictionary from 'ember-metal/dictionary';
import isEnabled from 'ember-metal/features';
import { setOwner } from './owner';
import { buildFakeContainerWithDeprecations } from 'ember-runtime/mixins/container_proxy';

/**
A container used to instantiate and cache objects.
Expand All @@ -23,6 +24,10 @@ function Container(registry, options) {
this.cache = dictionary(options && options.cache ? options.cache : null);
this.factoryCache = dictionary(options && options.factoryCache ? options.factoryCache : null);
this.validationCache = dictionary(options && options.validationCache ? options.validationCache : null);

if (isEnabled('ember-container-inject-owner')) {
this._fakeContainerToInject = buildFakeContainerWithDeprecations(this);
}
}

Container.prototype = {
Expand Down Expand Up @@ -243,8 +248,11 @@ function factoryFor(container, fullName) {

var injectedFactory = factory.extend(injections);

// TODO - remove all `container` injections when Ember reaches v3.0.0
if (isEnabled('ember-container-inject-owner')) {
injectDeprecatedContainer(injectedFactory.prototype, container);
} else {
injectedFactory.prototype.container = container;
}

injectedFactory.reopenClass(factoryInjections);
Expand Down Expand Up @@ -273,12 +281,6 @@ function injectionsFor(container, fullName) {

setOwner(injections, container.owner);

// TODO - Inject a `FakeContainer` instead here. The `FakeContainer` will
// proxy all properties of the container with deprecations.
if (!isEnabled('ember-container-inject-owner')) {
injections.container = container;
}

return injections;
}

Expand Down Expand Up @@ -330,8 +332,21 @@ function instantiate(container, fullName) {
// assume the factory was extendable
// to create time injections
// TODO: support new'ing for instantiation and merge injections for pure JS Functions
obj = factory.create(injectionsFor(container, fullName));
let injections = injectionsFor(container, fullName);

// Ensure that a container is available to an object during instantiation.
// TODO - remove when Ember reaches v3.0.0
if (isEnabled('ember-container-inject-owner')) {
// This "fake" container will be replaced after instantiation with a
// property that raises deprecations every time it is accessed.
injections.container = container._fakeContainerToInject;
} else {
injections.container = container;
}

obj = factory.create(injections);

// TODO - remove when Ember reaches v3.0.0
if (isEnabled('ember-container-inject-owner')) {
injectDeprecatedContainer(obj, container);
}
Expand Down
50 changes: 49 additions & 1 deletion packages/container/tests/container_test.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import Ember from 'ember-metal/core';
import Registry from 'container/registry';
import factory from 'container/tests/test-helpers/factory';
import { getOwner } from 'container/owner';
import isEnabled from 'ember-metal/features';

var originalModelInjections;
Expand Down Expand Up @@ -519,7 +520,7 @@ QUnit.test('Lazy injection validations are cached', function() {
});

if (isEnabled('ember-container-inject-owner')) {
QUnit.test('A deprecated `container` property is appended to every instantiated object', function() {
QUnit.test('A deprecated `container` property is appended to every object instantiated from an extendable factory', function() {
let registry = new Registry();
let container = registry.container();
let PostController = factory();
Expand All @@ -535,6 +536,53 @@ if (isEnabled('ember-container-inject-owner')) {
strictEqual(c, container);
}, 'Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.');
});

QUnit.test('A deprecated `container` property is appended to every object instantiated from a non-extendable factory, and a fake container is available during instantiation.', function() {
expect(8);

let owner = {};
let registry = new Registry();
let container = registry.container({ owner });

// Define a simple non-extendable factory
let PostController = function() {};
PostController.create = function(options) {
ok(options.container, 'fake container has been injected and is available during `create`.');

expectDeprecation(function() {
options.container.lookup('abc:one');
}, 'Using the injected `container` is deprecated. Please use the `getOwner` helper to access the owner of this object and then call `lookup` instead.');

expectDeprecation(function() {
options.container.lookupFactory('abc:two');
}, 'Using the injected `container` is deprecated. Please use the `getOwner` helper to access the owner of this object and then call `_lookupFactory` instead.');

// non-deprecated usage of `lookup` and `_lookupFactory`
owner.lookup = function(fullName) {
equal(fullName, 'abc:one', 'lookup on owner called properly');
};
owner._lookupFactory = function(fullName) {
equal(fullName, 'abc:two', '_lookupFactory on owner called properly');
};
let foundOwner = getOwner(options);
foundOwner.lookup('abc:one');
foundOwner._lookupFactory('abc:two');

return new PostController(options);
};

registry.register('controller:post', PostController);
let postController = container.lookup('controller:post');

expectDeprecation(function() {
Ember.get(postController, 'container');
}, 'Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.');

expectDeprecation(function() {
let c = postController.container;
strictEqual(c, container, 'Injected container is now regular (not fake) container, but access is still deprecated.');
}, 'Using the injected `container` is deprecated. Please use the `getOwner` helper instead to access the owner of this object.');
});
} else {
QUnit.test('A `container` property is appended to every instantiated object', function() {
let registry = new Registry();
Expand Down
30 changes: 30 additions & 0 deletions packages/ember-runtime/lib/mixins/container_proxy.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
@submodule ember-runtime
*/
import run from 'ember-metal/run_loop';
import { deprecate } from 'ember-metal/debug';
import { Mixin } from 'ember-metal/mixin';


Expand Down Expand Up @@ -95,3 +96,32 @@ function containerAlias(name) {
return this.__container__[name](...arguments);
};
}

export function buildFakeContainerWithDeprecations(container) {
let fakeContainer = {};
let propertyMappings = {
lookup: 'lookup',
lookupFactory: '_lookupFactory'
};

for (let containerProperty in propertyMappings) {
fakeContainer[containerProperty] = buildFakeContainerFunction(container, containerProperty, propertyMappings[containerProperty]);
}

return fakeContainer;
}

function buildFakeContainerFunction(container, containerProperty, ownerProperty) {
return function() {
deprecate(
`Using the injected \`container\` is deprecated. Please use the \`getOwner\` helper to access the owner of this object and then call \`${ownerProperty}\` instead.`,
false,
{
id: 'ember-application.injected-container',
until: '3.0.0',
url: 'http://emberjs.com/deprecations/v2.x#toc_injected-container-access'
}
);
return container[containerProperty](...arguments);
};
}

0 comments on commit f434c9f

Please sign in to comment.