You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ambari.apache.org by nc...@apache.org on 2015/12/01 19:19:53 UTC

[03/50] ambari git commit: AMBARI-14093. Add ability for some Em.computed macros to work with App.* keys (onechiporenko)

AMBARI-14093. Add ability for some Em.computed macros to work with App.* keys (onechiporenko)


Project: http://git-wip-us.apache.org/repos/asf/ambari/repo
Commit: http://git-wip-us.apache.org/repos/asf/ambari/commit/b19bf6ea
Tree: http://git-wip-us.apache.org/repos/asf/ambari/tree/b19bf6ea
Diff: http://git-wip-us.apache.org/repos/asf/ambari/diff/b19bf6ea

Branch: refs/heads/branch-dev-patch-upgrade
Commit: b19bf6eab3821de71c5ffcf8c1f87ea1b338a50b
Parents: 6c3cf49
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Fri Nov 27 11:45:06 2015 +0200
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Fri Nov 27 11:45:06 2015 +0200

----------------------------------------------------------------------
 ambari-web/app/utils/ember_computed.js       | 102 +++--
 ambari-web/test/utils/ember_computed_test.js | 496 +++++++++++++++++++++-
 2 files changed, 552 insertions(+), 46 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/b19bf6ea/ambari-web/app/utils/ember_computed.js
----------------------------------------------------------------------
diff --git a/ambari-web/app/utils/ember_computed.js b/ambari-web/app/utils/ember_computed.js
index c996f32..03ac4fc 100644
--- a/ambari-web/app/utils/ember_computed.js
+++ b/ambari-web/app/utils/ember_computed.js
@@ -24,26 +24,57 @@ var slice = [].slice;
 
 var dataUtils = require('utils/data_manipulation');
 
+/**
+ * Returns hash with values of name properties from the context
+ * If <code>propertyName</code> starts with 'App.', <code>App</code> is used as context, <code>self</code> used otherwise
+ * If some <code>propertyName</code> starts with '!' its value will be inverted
+ *
+ * @param {object} self current context
+ * @param {string[]} propertyNames needed properties
+ * @returns {object} hash with needed values
+ */
 function getProperties(self, propertyNames) {
   var ret = {};
   for (var i = 0; i < propertyNames.length; i++) {
     var propertyName = propertyNames[i];
-    var value;
-    if (propertyName.startsWith('!')) {
-      propertyName = propertyName.substring(1);
-      value = !get(self, propertyName);
-    }
-    else {
-      value = get(self, propertyName);
-    }
+    var shouldBeInverted = propertyName.startsWith('!');
+    propertyName = shouldBeInverted ? propertyName.substr(1) : propertyName;
+    var isApp = propertyName.startsWith('App.');
+    var name = isApp ? propertyName.replace('App.', '') : propertyName;
+    var context = isApp ? App : self;
+    var value = get(context, name);
+    value = shouldBeInverted ? !value : value;
     ret[propertyName] = value;
   }
   return ret;
 }
 
+/**
+ * Returns value of named property from the context
+ * If <code>propertyName</code> starts with 'App.', <code>App</code> is used as context, <code>self</code> used otherwise
+ *
+ * @param {object} self current context
+ * @param {string} propertyName needed property
+ * @returns {*} needed value
+ */
+function smartGet(self, propertyName) {
+  var isApp = propertyName.startsWith('App.');
+  var name = isApp ? propertyName.replace('App.', '') : propertyName;
+  var context = isApp ? App : self;
+  return get(context, name)
+}
+
+/**
+ * Returns list with values of name properties from the context
+ * If <code>propertyName</code> starts with 'App.', <code>App</code> is used as context, <code>self</code> used otherwise
+ *
+ * @param {object} self current context
+ * @param {string[]} propertyNames neded properties
+ * @returns {array} list of needed values
+ */
 function getValues(self, propertyNames) {
   return propertyNames.map(function (propertyName) {
-    return get(self, propertyName);
+    return smartGet(self, propertyName);
   });
 }
 
@@ -87,6 +118,7 @@ function generateComputedWithValues(macro) {
  *
  * A computed property that returns true if the provided dependent property
  * is equal to the given value.
+ * App.*-keys are supported
  * Example*
  * ```javascript
  * var Hamster = Ember.Object.extend({
@@ -108,12 +140,13 @@ function generateComputedWithValues(macro) {
  */
 computed.equal = function (dependentKey, value) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) === value;
+    return smartGet(this, dependentKey) === value;
   }).cacheable();
 };
 
 /**
  * A computed property that returns true if the provided dependent property is not equal to the given value
+ * App.*-keys are supported
  *
  * @method notEqual
  * @param {string} dependentKey
@@ -122,12 +155,13 @@ computed.equal = function (dependentKey, value) {
  */
 computed.notEqual = function (dependentKey, value) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) !== value;
+    return smartGet(this, dependentKey) !== value;
   });
 };
 
 /**
  * A computed property that returns true if provided dependent properties are equal to the each other
+ * App.*-keys are supported
  *
  * @method equalProperties
  * @param {string} dependentKey1
@@ -136,12 +170,13 @@ computed.notEqual = function (dependentKey, value) {
  */
 computed.equalProperties = function (dependentKey1, dependentKey2) {
   return computed(dependentKey1, dependentKey2, function () {
-    return get(this, dependentKey1) === get(this, dependentKey2);
+    return smartGet(this, dependentKey1) === smartGet(this, dependentKey2);
   });
 };
 
 /**
  * A computed property that returns true if provided dependent properties are not equal to the each other
+ * App.*-keys are supported
  *
  * @method notEqualProperties
  * @param {string} dependentKey1
@@ -150,7 +185,7 @@ computed.equalProperties = function (dependentKey1, dependentKey2) {
  */
 computed.notEqualProperties = function (dependentKey1, dependentKey2) {
   return computed(dependentKey1, dependentKey2, function () {
-    return get(this, dependentKey1) !== get(this, dependentKey2);
+    return smartGet(this, dependentKey1) !== smartGet(this, dependentKey2);
   });
 };
 
@@ -205,6 +240,7 @@ computed.rejectMany = function (collectionKey, propertyName, valuesToReject) {
 
 /**
  * A computed property that returns trueValue if dependent value is true and falseValue otherwise
+ * App.*-keys are supported
  *
  * @method ifThenElse
  * @param {string} dependentKey
@@ -214,7 +250,7 @@ computed.rejectMany = function (collectionKey, propertyName, valuesToReject) {
  */
 computed.ifThenElse = function (dependentKey, trueValue, falseValue) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) ? trueValue : falseValue;
+    return smartGet(this, dependentKey) ? trueValue : falseValue;
   });
 };
 
@@ -222,6 +258,7 @@ computed.ifThenElse = function (dependentKey, trueValue, falseValue) {
  * A computed property that is equal to the logical 'and'
  * Takes any number of arguments
  * Returns true if all of them are truly, false - otherwise
+ * App.*-keys are supported
  *
  * @method and
  * @param {...string} dependentKeys
@@ -242,6 +279,7 @@ computed.and = generateComputedWithProperties(function (properties) {
  * A computed property that is equal to the logical 'or'
  * Takes any number of arguments
  * Returns true if at least one of them is truly, false - otherwise
+ * App.*-keys are supported
  *
  * @method or
  * @param {...string} dependentKeys
@@ -261,6 +299,7 @@ computed.or = generateComputedWithProperties(function (properties) {
 /**
  * A computed property that returns sum on the dependent properties values
  * Takes any number of arguments
+ * App.*-keys are supported
  *
  * @method sumProperties
  * @param {...string} dependentKeys
@@ -278,6 +317,7 @@ computed.sumProperties = generateComputedWithProperties(function (properties) {
 
 /**
  * A computed property that returns true if dependent value is greater or equal to the needed value
+ * App.*-keys are supported
  *
  * @method gte
  * @param {string} dependentKey
@@ -286,12 +326,13 @@ computed.sumProperties = generateComputedWithProperties(function (properties) {
  */
 computed.gte = function (dependentKey, value) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) >= value;
+    return smartGet(this, dependentKey) >= value;
   });
 };
 
 /**
  * A computed property that returns true if first dependent property is greater or equal to the second dependent property
+ * App.*-keys are supported
  *
  * @method gteProperties
  * @param {string} dependentKey1
@@ -300,12 +341,13 @@ computed.gte = function (dependentKey, value) {
  */
 computed.gteProperties = function (dependentKey1, dependentKey2) {
   return computed(dependentKey1, dependentKey2, function () {
-    return get(this, dependentKey1) >= get(this, dependentKey2);
+    return smartGet(this, dependentKey1) >= smartGet(this, dependentKey2);
   });
 };
 
 /**
  * A computed property that returns true if dependent property is less or equal to the needed value
+ * App.*-keys are supported
  *
  * @method lte
  * @param {string} dependentKey
@@ -314,12 +356,13 @@ computed.gteProperties = function (dependentKey1, dependentKey2) {
  */
 computed.lte = function (dependentKey, value) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) <= value;
+    return smartGet(this, dependentKey) <= value;
   });
 };
 
 /**
  * A computed property that returns true if first dependent property is less or equal to the second dependent property
+ * App.*-keys are supported
  *
  * @method lteProperties
  * @param {string} dependentKey1
@@ -328,12 +371,13 @@ computed.lte = function (dependentKey, value) {
  */
 computed.lteProperties = function (dependentKey1, dependentKey2) {
   return computed(dependentKey1, dependentKey2, function () {
-    return get(this, dependentKey1) <= get(this, dependentKey2);
+    return smartGet(this, dependentKey1) <= smartGet(this, dependentKey2);
   });
 };
 
 /**
  * A computed property that returns true if dependent value is greater than the needed value
+ * App.*-keys are supported
  *
  * @method gt
  * @param {string} dependentKey
@@ -342,12 +386,13 @@ computed.lteProperties = function (dependentKey1, dependentKey2) {
  */
 computed.gt = function (dependentKey, value) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) > value;
+    return smartGet(this, dependentKey) > value;
   });
 };
 
 /**
  * A computed property that returns true if first dependent property is greater than the second dependent property
+ * App.*-keys are supported
  *
  * @method gtProperties
  * @param {string} dependentKey1
@@ -356,12 +401,13 @@ computed.gt = function (dependentKey, value) {
  */
 computed.gtProperties = function (dependentKey1, dependentKey2) {
   return computed(dependentKey1, dependentKey2, function () {
-    return get(this, dependentKey1) > get(this, dependentKey2);
+    return smartGet(this, dependentKey1) > smartGet(this, dependentKey2);
   });
 };
 
 /**
  * A computed property that returns true if dependent value is less than the needed value
+ * App.*-keys are supported
  *
  * @method lt
  * @param {string} dependentKey
@@ -370,12 +416,13 @@ computed.gtProperties = function (dependentKey1, dependentKey2) {
  */
 computed.lt = function (dependentKey, value) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey) < value;
+    return smartGet(this, dependentKey) < value;
   });
 };
 
 /**
  * A computed property that returns true if first dependent property is less than the second dependent property
+ * App.*-keys are supported
  *
  * @method gtProperties
  * @param {string} dependentKey1
@@ -384,7 +431,7 @@ computed.lt = function (dependentKey, value) {
  */
 computed.ltProperties = function (dependentKey1, dependentKey2) {
   return computed(dependentKey1, dependentKey2, function () {
-    return get(this, dependentKey1) < get(this, dependentKey2);
+    return smartGet(this, dependentKey1) < smartGet(this, dependentKey2);
   });
 };
 
@@ -503,6 +550,7 @@ computed.findBy = function (collectionKey, propertyName, neededValue) {
 /**
  * A computed property that returns value equal to the dependent
  * Should be used as 'short-name' for deeply-nested values
+ * App.*-keys are supported
  *
  * @method alias
  * @param {string} dependentKey
@@ -510,7 +558,7 @@ computed.findBy = function (collectionKey, propertyName, neededValue) {
  */
 computed.alias = function (dependentKey) {
   return computed(dependentKey, function () {
-    return get(this, dependentKey);
+    return smartGet(this, dependentKey);
   });
 };
 
@@ -548,6 +596,7 @@ computed.notExistsIn = function (dependentKey, neededValues) {
  * A computed property that returns result of calculation <code>(dependentProperty1/dependentProperty2 * 100)</code>
  * If accuracy is 0 (by default), result is rounded to integer
  * Otherwise - result is float with provided accuracy
+ * App.*-keys are supported
  *
  * @method percents
  * @param {string} dependentKey1
@@ -560,8 +609,8 @@ computed.percents = function (dependentKey1, dependentKey2, accuracy) {
     accuracy = 0;
   }
   return computed(dependentKey1, dependentKey2, function () {
-    var v1 = Number(get(this, dependentKey1));
-    var v2 = Number(get(this, dependentKey2));
+    var v1 = Number(smartGet(this, dependentKey1));
+    var v2 = Number(smartGet(this, dependentKey2));
     var result = v1 / v2 * 100;
     if (0 === accuracy) {
       return Math.round(result);
@@ -609,6 +658,7 @@ computed.sumBy = function (collectionKey, propertyName) {
 /**
  * A computed property that returns I18n-string formatted with dependent properties
  * Takes at least one argument
+ * App.*-keys are supported
  *
  * @param {string} key key in the I18n-messages
  * @param {...string} dependentKeys
@@ -626,6 +676,7 @@ computed.i18nFormat = generateComputedWithKey(function (key, dependentValues) {
 /**
  * A computed property that returns dependent values joined with separator
  * Takes at least one argument
+ * App.*-keys are supported
  *
  * @param {string} separator
  * @param {...string} dependentKeys
@@ -641,6 +692,7 @@ computed.concat = generateComputedWithKey(function (separator, dependentValues)
  * Based on <code>Ember.isBlank</code>
  * Takes at least 1 argument
  * Dependent values order affects the result
+ * App.*-keys are supported
  *
  * @param {...string} dependentKeys
  * @method {firstNotBlank}

http://git-wip-us.apache.org/repos/asf/ambari/blob/b19bf6ea/ambari-web/test/utils/ember_computed_test.js
----------------------------------------------------------------------
diff --git a/ambari-web/test/utils/ember_computed_test.js b/ambari-web/test/utils/ember_computed_test.js
index 380982c..4aa3158 100644
--- a/ambari-web/test/utils/ember_computed_test.js
+++ b/ambari-web/test/utils/ember_computed_test.js
@@ -20,12 +20,64 @@ require('utils/ember_computed');
 
 describe('Ember.computed macros', function () {
 
+  beforeEach(function () {
+    App.reopen({
+      someRandomTestingKey: function () {
+        return this.get('someAnotherKey');
+      }.property('someAnotherKey'),
+      someAnotherKey: ''
+    });
+  });
+
+  afterEach(function () {
+    delete App.someAnotherKey;
+    delete App.someRandomTestingKey;
+  });
+
+  describe('#equal', function () {
+
+    beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: '123'
+      });
+      this.obj = Em.Object.create({
+        prop1: '123',
+        prop2: Em.computed.equal('prop1', '123'),
+        prop3: Em.computed.equal('App.someRandomTestingKey', '123')
+      });
+    });
+
+    it('`true` if values are equal', function () {
+      expect(this.obj.get('prop2')).to.be.true;
+    });
+
+    it('`false` if values are not equal', function () {
+      this.obj.set('prop1', '321');
+      expect(this.obj.get('prop2')).to.be.false;
+    });
+
+    it('`prop3` depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop3')).to.be.false;
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
+  });
+
   describe('#notEqual', function () {
 
     beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: '123'
+      });
       this.obj = Em.Object.create({
         prop1: '123',
-        prop2: Em.computed.notEqual('prop1', '123')
+        prop2: Em.computed.notEqual('prop1', '123'),
+        prop3: Em.computed.notEqual('App.someRandomTestingKey', '123')
       });
     });
 
@@ -38,15 +90,28 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.true;
     });
 
+    it('`prop3` depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.be.false;
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop3')).to.be.true;
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#equalProperties', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', '123');
       this.obj = Em.Object.create({
         prop1: '123',
         prop2: '123',
-        prop3: Em.computed.equalProperties('prop1', 'prop2')
+        prop3: Em.computed.equalProperties('prop1', 'prop2'),
+        prop4: Em.computed.equalProperties('App.someRandomTestingKey', 'prop2'),
+        prop5: Em.computed.equalProperties('prop1', 'App.someRandomTestingKey')
       });
     });
 
@@ -59,15 +124,38 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop3')).to.be.false;
     });
 
+    it('prop4 depends on App.* key', function () {
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop4')).to.be.false;
+    });
+
+    it('prop5 depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.be.true;
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop5')).to.be.false;
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2']);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#notEqualProperties', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', '123');
       this.obj = Em.Object.create({
         prop1: '123',
         prop2: '123',
-        prop3: Em.computed.notEqualProperties('prop1', 'prop2')
+        prop3: Em.computed.notEqualProperties('prop1', 'prop2'),
+        prop4: Em.computed.notEqualProperties('App.someRandomTestingKey', 'prop2'),
+        prop5: Em.computed.notEqualProperties('prop1', 'App.someRandomTestingKey')
       });
     });
 
@@ -80,14 +168,36 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop3')).to.be.true;
     });
 
+    it('prop4 depends on App.* key', function () {
+      expect(this.obj.get('prop4')).to.be.false;
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop4')).to.be.true;
+    });
+
+    it('prop5 depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop5')).to.be.true;
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2']);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#ifThenElse', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', true);
       this.obj = Em.Object.create({
         prop1: true,
-        prop2: Em.computed.ifThenElse('prop1', '1', '0')
+        prop2: Em.computed.ifThenElse('prop1', '1', '0'),
+        prop3: Em.computed.ifThenElse('App.someRandomTestingKey', '1', '0')
       });
     });
 
@@ -100,17 +210,32 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.equal('0');
     });
 
+    it('prop3 depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.equal('1');
+      App.set('someAnotherKey', false);
+      expect(this.obj.get('prop3')).to.equal('0');
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#and', function () {
 
     beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: true
+      });
       this.obj = Em.Object.create({
         prop1: true,
         prop2: true,
         prop3: true,
         prop4: Em.computed.and('prop1', 'prop2', 'prop3'),
-        prop5: Em.computed.and('prop1', '!prop2', '!prop3')
+        prop5: Em.computed.and('prop1', '!prop2', '!prop3'),
+        prop6: Em.computed.and('App.someRandomTestingKey', 'prop1'),
+        prop7: Em.computed.and('!App.someRandomTestingKey', 'prop1')
       });
     });
 
@@ -142,17 +267,45 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop5')).to.be.true;
     });
 
+    it('`prop6` depends on App.* key', function () {
+      expect(this.obj.get('prop6')).to.be.true;
+      App.set('someAnotherKey', false);
+      expect(this.obj.get('prop6')).to.be.false;
+      App.set('someAnotherKey', true);
+      expect(this.obj.get('prop6')).to.be.true;
+    });
+
+    it('prop6 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop6._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop1']);
+    });
+
+    it('`prop7` depends on inverted App.* key', function () {
+      expect(this.obj.get('prop7')).to.be.false;
+      App.set('someAnotherKey', false);
+      expect(this.obj.get('prop7')).to.be.true;
+      App.set('someAnotherKey', true);
+      expect(this.obj.get('prop7')).to.be.false;
+    });
+
+    it('prop7 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop7._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop1']);
+    });
+
   });
 
   describe('#or', function () {
-
     beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: true
+      });
       this.obj = Em.Object.create({
         prop1: false,
         prop2: false,
         prop3: false,
         prop4: Em.computed.or('prop1', 'prop2', 'prop3'),
-        prop5: Em.computed.or('!prop1', '!prop2', '!prop3')
+        prop5: Em.computed.or('!prop1', '!prop2', '!prop3'),
+        prop6: Em.computed.or('App.someRandomTestingKey', 'prop1'),
+        prop7: Em.computed.or('!App.someRandomTestingKey', 'prop1')
       });
     });
 
@@ -185,16 +338,44 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop5')).to.be.false;
     });
 
+    it('`prop6` depends on App.* key', function () {
+      expect(this.obj.get('prop6')).to.be.true;
+      App.set('someAnotherKey', false);
+      expect(this.obj.get('prop6')).to.be.false;
+      App.set('someAnotherKey', true);
+      expect(this.obj.get('prop6')).to.be.true;
+    });
+
+    it('prop6 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop6._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop1']);
+    });
+
+    it('`prop7` depends on inverted App.* key', function () {
+      expect(this.obj.get('prop7')).to.be.false;
+      App.set('someAnotherKey', false);
+      expect(this.obj.get('prop7')).to.be.true;
+      App.set('someAnotherKey', true);
+      expect(this.obj.get('prop7')).to.be.false;
+    });
+
+    it('prop7 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop7._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop1']);
+    });
+
   });
 
   describe('#sumProperties', function () {
 
     beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: 5
+      });
       this.obj = Em.Object.create({
         prop1: 1,
         prop2: 2,
         prop3: 3,
-        prop4: Em.computed.sumProperties('prop1', 'prop2', 'prop3')
+        prop4: Em.computed.sumProperties('prop1', 'prop2', 'prop3'),
+        prop5: Em.computed.sumProperties('prop1', 'prop2', 'App.someRandomTestingKey')
       });
     });
 
@@ -222,14 +403,26 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop4')).to.equal(5);
     });
 
+    it('`prop5` depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.equal(8);
+      App.set('someAnotherKey', 6);
+      expect(this.obj.get('prop5')).to.equal(9);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'prop2', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#gte', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 4);
       this.obj = Em.Object.create({
         prop1: 2,
-        prop2: Em.computed.gte('prop1', 3)
+        prop2: Em.computed.gte('prop1', 3),
+        prop3: Em.computed.gte('App.someRandomTestingKey', 3)
       });
     });
 
@@ -247,15 +440,30 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.true;
     });
 
+    it('prop3 depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', 3);
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop3')).to.be.false;
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#gteProperties', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 4);
       this.obj = Em.Object.create({
         prop1: 2,
         prop2: 3,
-        prop3: Em.computed.gteProperties('prop1', 'prop2')
+        prop3: Em.computed.gteProperties('prop1', 'prop2'),
+        prop4: Em.computed.gteProperties('App.someRandomTestingKey', 'prop2'),
+        prop5: Em.computed.gteProperties('prop1', 'App.someRandomTestingKey')
       });
     });
 
@@ -273,14 +481,40 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop3')).to.be.true;
     });
 
+    it('prop4 depends on App.* key', function () {
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', 3);
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop4')).to.be.false;
+    });
+
+    it('prop5 depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop5')).to.be.true;
+      App.set('someAnotherKey', 1);
+      expect(this.obj.get('prop5')).to.be.true;
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2']);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#lte', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 0);
       this.obj = Em.Object.create({
         prop1: 2,
-        prop2: Em.computed.lte('prop1', 1)
+        prop2: Em.computed.lte('prop1', 1),
+        prop3: Em.computed.lte('App.someRandomTestingKey', 1)
       });
     });
 
@@ -298,15 +532,30 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.true;
     });
 
+    it('prop3 depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', 1);
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop3')).to.be.false;
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#lteProperties', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 1);
       this.obj = Em.Object.create({
         prop1: 2,
         prop2: 1,
-        prop3: Em.computed.lteProperties('prop1', 'prop2')
+        prop3: Em.computed.lteProperties('prop1', 'prop2'),
+        prop4: Em.computed.lteProperties('App.someRandomTestingKey', 'prop2'),
+        prop5: Em.computed.lteProperties('prop1', 'App.someRandomTestingKey')
       });
     });
 
@@ -324,14 +573,40 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop3')).to.be.true;
     });
 
+    it('prop4 depends on App.* key', function () {
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', 0);
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop4')).to.be.false;
+    });
+
+    it('prop5 depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop5')).to.be.true;
+      App.set('someAnotherKey', 3);
+      expect(this.obj.get('prop5')).to.be.true;
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2']);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#gt', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 4);
       this.obj = Em.Object.create({
         prop1: 2,
-        prop2: Em.computed.gt('prop1', 3)
+        prop2: Em.computed.gt('prop1', 3),
+        prop3: Em.computed.gt('App.someRandomTestingKey', 3)
       });
     });
 
@@ -349,15 +624,30 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.true;
     });
 
+    it('prop3 depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', 3);
+      expect(this.obj.get('prop3')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop3')).to.be.false;
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#gtProperties', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 4);
       this.obj = Em.Object.create({
         prop1: 2,
         prop2: 3,
-        prop3: Em.computed.gtProperties('prop1', 'prop2')
+        prop3: Em.computed.gtProperties('prop1', 'prop2'),
+        prop4: Em.computed.gtProperties('App.someRandomTestingKey', 'prop2'),
+        prop5: Em.computed.gtProperties('prop1', 'App.someRandomTestingKey')
       });
     });
 
@@ -375,14 +665,40 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop3')).to.be.true;
     });
 
+    it('prop4 depends on App.* key', function () {
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', 3);
+      expect(this.obj.get('prop4')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop4')).to.be.false;
+    });
+
+    it('prop5 depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', 1);
+      expect(this.obj.get('prop5')).to.be.true;
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2']);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#lt', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 0);
       this.obj = Em.Object.create({
         prop1: 2,
-        prop2: Em.computed.lt('prop1', 1)
+        prop2: Em.computed.lt('prop1', 1),
+        prop3: Em.computed.lt('App.someRandomTestingKey', 1)
       });
     });
 
@@ -400,15 +716,30 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.true;
     });
 
+    it('prop3 depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.be.true;
+      App.set('someAnotherKey', 1);
+      expect(this.obj.get('prop3')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop3')).to.be.false;
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#ltProperties', function () {
 
     beforeEach(function () {
+      App.set('someAnotherKey', 1);
       this.obj = Em.Object.create({
         prop1: 2,
         prop2: 1,
-        prop3: Em.computed.ltProperties('prop1', 'prop2')
+        prop3: Em.computed.ltProperties('prop1', 'prop2'),
+        prop4: Em.computed.ltProperties('App.someRandomTestingKey', 'prop2'),
+        prop5: Em.computed.ltProperties('prop1', 'App.someRandomTestingKey')
       });
     });
 
@@ -426,6 +757,30 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop3')).to.be.true;
     });
 
+    it('prop4 depends on App.* key', function () {
+      expect(this.obj.get('prop4')).to.be.false;
+      App.set('someAnotherKey', 0);
+      expect(this.obj.get('prop4')).to.be.true;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop4')).to.be.false;
+    });
+
+    it('prop5 depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', 2);
+      expect(this.obj.get('prop5')).to.be.false;
+      App.set('someAnotherKey', 3);
+      expect(this.obj.get('prop5')).to.be.true;
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2']);
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey']);
+    });
+
   });
 
   describe('#match', function () {
@@ -581,6 +936,7 @@ describe('Ember.computed macros', function () {
   describe('#alias', function() {
 
     beforeEach(function () {
+      App.set('someAnotherKey', {a: {b: 1}});
       this.obj = Em.Object.create({
         prop1: {
           a: {
@@ -589,7 +945,8 @@ describe('Ember.computed macros', function () {
             }
           }
         },
-        prop2: Em.computed.alias('prop1.a.b.c')
+        prop2: Em.computed.alias('prop1.a.b.c'),
+        prop3: Em.computed.alias('App.someAnotherKey.a.b')
       })
     });
 
@@ -602,6 +959,16 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.equal(2);
     });
 
+    it('prop3 depends on App.* key', function () {
+      expect(this.obj.get('prop3')).to.equal(1);
+      App.set('someAnotherKey.a.b', 4);
+      expect(this.obj.get('prop3')).to.equal(4);
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someAnotherKey.a.b']);
+    });
+
   });
 
   describe('#existsIn', function () {
@@ -632,14 +999,24 @@ describe('Ember.computed macros', function () {
   describe('#percents', function () {
 
     beforeEach(function () {
+      App.setProperties({
+        p1: 25,
+        p2: 100
+      });
       this.obj = Em.Object.create({
         prop1: 10,
         prop2: 25,
         prop3: Em.computed.percents('prop1', 'prop2'),
-        prop4: Em.computed.percents('prop1', 'prop2', 2)
+        prop4: Em.computed.percents('prop1', 'prop2', 2),
+        prop5: Em.computed.percents('App.p1', 'App.p2', 1)
       });
     });
 
+    afterEach(function () {
+      delete App.p1;
+      delete App.p2;
+    });
+
     it('should calculate percents', function () {
       expect(this.obj.get('prop3')).to.equal(40);
       expect(this.obj.get('prop4')).to.equal(40.00);
@@ -671,6 +1048,18 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop4')).to.equal(10.60);
     });
 
+    it('prop5 depends on App.* keys', function () {
+      expect(this.obj.get('prop5')).to.equal(25.0);
+      App.set('p2', 50);
+      expect(this.obj.get('prop5')).to.equal(50.0);
+      App.set('p1', 10);
+      expect(this.obj.get('prop5')).to.equal(20.0);
+    });
+
+    it('prop4 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['App.p1', 'App.p2']);
+    });
+
   });
 
   describe('#formatRole', function () {
@@ -730,11 +1119,21 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.equal(10);
     });
 
+    it('0 for empty collection', function () {
+      this.obj.set('prop1', []);
+      expect(this.obj.get('prop2')).to.equal(0);
+    });
+
   });
 
   describe('#i18nFormat', function () {
 
     beforeEach(function () {
+
+      App.setProperties({
+        someAnotherKey: 'some value'
+      });
+
       sinon.stub(Em.I18n, 't', function (key) {
         var msgs = {
           key1: '{0} {1} {2}'
@@ -746,7 +1145,8 @@ describe('Ember.computed macros', function () {
         prop2: 'cba',
         prop3: 'aaa',
         prop4: Em.computed.i18nFormat('key1', 'prop1', 'prop2', 'prop3'),
-        prop5: Em.computed.i18nFormat('not_existing_key', 'prop1', 'prop2', 'prop3')
+        prop5: Em.computed.i18nFormat('not_existing_key', 'prop1', 'prop2', 'prop3'),
+        prop6: Em.computed.i18nFormat('key1', 'App.someRandomTestingKey', 'prop2', 'prop3')
       });
     });
 
@@ -771,16 +1171,33 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop5')).to.equal('');
     });
 
+    it('`prop6` depends on App.* key', function () {
+      expect(this.obj.get('prop6')).to.equal('some value cba aaa');
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop6')).to.equal(' cba aaa');
+    });
+
+    it('prop6 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop6._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2', 'prop3']);
+    });
+
   });
 
   describe('#concat', function () {
 
     beforeEach(function () {
+
+      App.setProperties({
+        someAnotherKey: 'some value'
+      });
+
       this.obj = Em.Object.create({
         prop1: 'abc',
         prop2: 'cba',
         prop3: 'aaa',
-        prop4: Em.computed.concat(' ', 'prop1', 'prop2', 'prop3')
+        prop4: Em.computed.concat(' ', 'prop1', 'prop2', 'prop3'),
+        prop5: Em.computed.concat(' ', 'App.someRandomTestingKey', 'prop2', 'prop3'),
+        prop6: Em.computed.concat(' ')
       });
     });
 
@@ -793,6 +1210,20 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop4')).to.equal('aaa cba aaa');
     });
 
+    it('`prop5` depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.equal('some value cba aaa');
+      App.set('someAnotherKey', '');
+      expect(this.obj.get('prop5')).to.equal(' cba aaa');
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['App.someRandomTestingKey', 'prop2', 'prop3']);
+    });
+
+    it('prop6 without dependent keys', function () {
+      expect(this.obj.get('prop6')).to.equal('');
+    });
+
   });
 
   describe('#notExistsIn', function () {
@@ -823,11 +1254,18 @@ describe('Ember.computed macros', function () {
   describe('#firstNotBlank', function () {
 
     beforeEach(function () {
+
+      App.setProperties({
+        someAnotherKey: 'NOT-EMPTY-STRING'
+      });
+
       this.obj = Em.Object.create({
         prop1: '',
         prop2: null,
         prop3: '1234',
-        prop4: Em.computed.firstNotBlank('prop1', 'prop2', 'prop3')
+        prop4: Em.computed.firstNotBlank('prop1', 'prop2', 'prop3'),
+        prop5: Em.computed.firstNotBlank('prop1', 'App.someRandomTestingKey', 'prop3'),
+        prop6: Em.computed.firstNotBlank('prop1', 'prop2')
       })
     });
 
@@ -850,6 +1288,22 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop4')).to.equal('prop1 is used');
     });
 
+    it('`prop5` depends on App.* key', function () {
+      expect(this.obj.get('prop5')).to.equal('NOT-EMPTY-STRING');
+      App.set('someAnotherKey', '!!!!!!!');
+      expect(this.obj.get('prop5')).to.equal('!!!!!!!');
+      App.set('someAnotherKey', null);
+      expect(this.obj.get('prop5')).to.equal('1234');
+    });
+
+    it('prop5 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop5._dependentKeys).to.eql(['prop1', 'App.someRandomTestingKey', 'prop3']);
+    });
+
+    it('prop6 depends on blank values', function () {
+      expect(this.obj.get('prop6')).to.be.null;
+    });
+
   });
 
 });
\ No newline at end of file