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

ambari git commit: AMBARI-14128. Improve Em.computed macros (onechiporenko)

Repository: ambari
Updated Branches:
  refs/heads/trunk f74ec8712 -> fd29b0815


AMBARI-14128. Improve Em.computed macros (onechiporenko)


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

Branch: refs/heads/trunk
Commit: fd29b081504d22715d46382484b8795daf8b2798
Parents: f74ec87
Author: Oleg Nechiporenko <on...@apache.org>
Authored: Tue Dec 1 13:55:01 2015 +0200
Committer: Oleg Nechiporenko <on...@apache.org>
Committed: Tue Dec 1 14:06:31 2015 +0200

----------------------------------------------------------------------
 ambari-web/app/utils/ember_computed.js       | 395 +++++++++++++++++++++-
 ambari-web/test/utils/ember_computed_test.js | 160 +++++++++
 2 files changed, 549 insertions(+), 6 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/ambari/blob/fd29b081/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 03ac4fc..a75fc50 100644
--- a/ambari-web/app/utils/ember_computed.js
+++ b/ambari-web/app/utils/ember_computed.js
@@ -41,8 +41,7 @@ function getProperties(self, propertyNames) {
     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);
+    var value = isApp ? App.get(name) : get(self, name);
     value = shouldBeInverted ? !value : value;
     ret[propertyName] = value;
   }
@@ -60,8 +59,7 @@ function getProperties(self, propertyNames) {
 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)
+  return  isApp ? App.get(name) : get(self, name);
 }
 
 /**
@@ -147,6 +145,15 @@ computed.equal = function (dependentKey, value) {
 /**
  * A computed property that returns true if the provided dependent property is not equal to the given value
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'a',
+ *  p2: Em.computed.notEqual('p1', 'a')
+ * });
+ * console.log(o.get('p2')); // false
+ * o.set('p1', 'b');
+ * console.log(o.get('p2')); // true
+ * </pre>
  *
  * @method notEqual
  * @param {string} dependentKey
@@ -162,6 +169,16 @@ computed.notEqual = function (dependentKey, value) {
 /**
  * A computed property that returns true if provided dependent properties are equal to the each other
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'a',
+ *  p2: 'b',
+ *  p3: Em.computed.equalProperties('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // false
+ * o.set('p1', 'b');
+ * console.log(o.get('p3')); // true
+ * </pre>
  *
  * @method equalProperties
  * @param {string} dependentKey1
@@ -177,6 +194,16 @@ computed.equalProperties = function (dependentKey1, dependentKey2) {
 /**
  * A computed property that returns true if provided dependent properties are not equal to the each other
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'a',
+ *  p2: 'b',
+ *  p3: Em.computed.notEqualProperties('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // true
+ * o.set('p1', 'b');
+ * console.log(o.get('p3')); // false
+ * </pre>
  *
  * @method notEqualProperties
  * @param {string} dependentKey1
@@ -241,6 +268,15 @@ computed.rejectMany = function (collectionKey, propertyName, valuesToReject) {
 /**
  * A computed property that returns trueValue if dependent value is true and falseValue otherwise
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: true,
+ *  p2: Em.computed.ifThenElse('p1', 'abc', 'cba')
+ * });
+ * console.log(o.get('p2')); // 'abc'
+ * o.set('p1', false);
+ * console.log(o.get('p2')); // 'cba'
+ * </pre>
  *
  * @method ifThenElse
  * @param {string} dependentKey
@@ -259,6 +295,17 @@ computed.ifThenElse = function (dependentKey, trueValue, falseValue) {
  * Takes any number of arguments
  * Returns true if all of them are truly, false - otherwise
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: true,
+ *  p2: true,
+ *  p3: true,
+ *  p4: Em.computed.and('p1', 'p2', 'p3')
+ * });
+ * console.log(o.get('p4')); // true
+ * o.set('p1', false);
+ * console.log(o.get('p4')); // false
+ * </pre>
  *
  * @method and
  * @param {...string} dependentKeys
@@ -280,6 +327,17 @@ computed.and = generateComputedWithProperties(function (properties) {
  * Takes any number of arguments
  * Returns true if at least one of them is truly, false - otherwise
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: false,
+ *  p2: false,
+ *  p3: false,
+ *  p4: Em.computed.or('p1', 'p2', 'p3')
+ * });
+ * console.log(o.get('p4')); // false
+ * o.set('p1', true);
+ * console.log(o.get('p4')); // true
+ * </pre>
  *
  * @method or
  * @param {...string} dependentKeys
@@ -300,6 +358,17 @@ 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
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 1,
+ *  p2: 2,
+ *  p3: 3,
+ *  p4: Em.computed.sumProperties('p1', 'p2', 'p3')
+ * });
+ * console.log(o.get('p4')); // 6
+ * o.set('p1', 2);
+ * console.log(o.get('p4')); // 7
+ * </pre>
  *
  * @method sumProperties
  * @param {...string} dependentKeys
@@ -318,6 +387,17 @@ 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
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: Em.computed.gte('p1', 1)
+ * });
+ * console.log(o.get('p2')); // true
+ * o.set('p1', 4);
+ * console.log(o.get('p2')); // true
+ * o.set('p1', 5);
+ * console.log(o.get('p2')); // false
+ * </pre>
  *
  * @method gte
  * @param {string} dependentKey
@@ -333,6 +413,18 @@ computed.gte = function (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
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: 1,
+ *  p3: Em.computed.gteProperties('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // true
+ * o.set('p2', 4);
+ * console.log(o.get('p3')); // true
+ * o.set('p2', 5);
+ * console.log(o.get('p3')); // false
+ * </pre>
  *
  * @method gteProperties
  * @param {string} dependentKey1
@@ -348,6 +440,17 @@ computed.gteProperties = function (dependentKey1, dependentKey2) {
 /**
  * A computed property that returns true if dependent property is less or equal to the needed value
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: Em.computed.lte('p1', 1)
+ * });
+ * console.log(o.get('p2')); // false
+ * o.set('p1', 4);
+ * console.log(o.get('p2')); // true
+ * o.set('p1', 5);
+ * console.log(o.get('p2')); // true
+ * </pre>
  *
  * @method lte
  * @param {string} dependentKey
@@ -363,6 +466,18 @@ computed.lte = function (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
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: 1,
+ *  p3: Em.computed.lteProperties('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // false
+ * o.set('p2', 4);
+ * console.log(o.get('p3')); // true
+ * o.set('p2', 5);
+ * console.log(o.get('p3')); // true
+ * </pre>
  *
  * @method lteProperties
  * @param {string} dependentKey1
@@ -378,6 +493,17 @@ computed.lteProperties = function (dependentKey1, dependentKey2) {
 /**
  * A computed property that returns true if dependent value is greater than the needed value
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: Em.computed.gt('p1', 1)
+ * });
+ * console.log(o.get('p2')); // true
+ * o.set('p1', 4);
+ * console.log(o.get('p2')); // false
+ * o.set('p1', 5);
+ * console.log(o.get('p2')); // false
+ * </pre>
  *
  * @method gt
  * @param {string} dependentKey
@@ -393,6 +519,18 @@ computed.gt = function (dependentKey, value) {
 /**
  * A computed property that returns true if first dependent property is greater than the second dependent property
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: 1,
+ *  p3: Em.computed.gteProperties('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // true
+ * o.set('p2', 4);
+ * console.log(o.get('p3')); // false
+ * o.set('p2', 5);
+ * console.log(o.get('p3')); // false
+ * </pre>
  *
  * @method gtProperties
  * @param {string} dependentKey1
@@ -408,6 +546,17 @@ computed.gtProperties = function (dependentKey1, dependentKey2) {
 /**
  * A computed property that returns true if dependent value is less than the needed value
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: Em.computed.lt('p1', 1)
+ * });
+ * console.log(o.get('p2')); // false
+ * o.set('p1', 4);
+ * console.log(o.get('p2')); // false
+ * o.set('p1', 5);
+ * console.log(o.get('p2')); // true
+ * </pre>
  *
  * @method lt
  * @param {string} dependentKey
@@ -423,6 +572,18 @@ computed.lt = function (dependentKey, value) {
 /**
  * A computed property that returns true if first dependent property is less than the second dependent property
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 4,
+ *  p2: 1,
+ *  p3: Em.computed.ltProperties('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // false
+ * o.set('p2', 4);
+ * console.log(o.get('p3')); // false
+ * o.set('p2', 5);
+ * console.log(o.get('p3')); // true
+ * </pre>
  *
  * @method gtProperties
  * @param {string} dependentKey1
@@ -437,6 +598,15 @@ computed.ltProperties = function (dependentKey1, dependentKey2) {
 
 /**
  * A computed property that returns true if dependent property is match to the needed regular expression
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'abc',
+ *  p2: Em.computed.lteProperties('p1', /^a/)
+ * });
+ * console.log(o.get('p2')); // true
+ * o.set('p1', 'bc');
+ * console.log(o.get('p2')); // false
+ * </pre>
  *
  * @method match
  * @param {string} dependentKey
@@ -455,6 +625,15 @@ computed.match = function (dependentKey, regexp) {
 
 /**
  * A computed property that returns true of some collection's item has property with needed value
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: [{a: 1}, {a: 2}, {a: 3}],
+ *  p2: Em.computed.someBy('p1', 'a', 1)
+ * });
+ * console.log(o.get('p2')); // true
+ * o.set('p1.0.a', 2);
+ * console.log(o.get('p2')); // false
+ * </pre>
  *
  * @method someBy
  * @param {string} collectionKey
@@ -474,6 +653,15 @@ computed.someBy = function (collectionKey, propertyName, neededValue) {
 
 /**
  * A computed property that returns true of all collection's items have property with needed value
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: [{a: 1}, {a: 1}, {a: 1}],
+ *  p2: Em.computed.everyBy('p1', 'a', 1)
+ * });
+ * console.log(o.get('p2')); // true
+ * o.set('p1.0.a', 2);
+ * console.log(o.get('p2')); // false
+ * </pre>
  *
  * @method everyBy
  * @param {string} collectionKey
@@ -493,6 +681,15 @@ computed.everyBy = function (collectionKey, propertyName, neededValue) {
 
 /**
  * A computed property that returns array with values of named property on all items in the collection
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: [{a: 1}, {a: 2}, {a: 3}],
+ *  p2: Em.computed.everyBy('p1', 'a')
+ * });
+ * console.log(o.get('p2')); // [1, 2, 3]
+ * o.set('p1.0.a', 2);
+ * console.log(o.get('p2')); // [2, 2, 3]
+ * </pre>
  *
  * @method mapBy
  * @param {string} collectionKey
@@ -511,6 +708,15 @@ computed.mapBy = function (collectionKey, propertyName) {
 
 /**
  * A computed property that returns array with collection's items that have needed property value
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: [{a: 1}, {a: 2}, {a: 3}],
+ *  p2: Em.computed.filterBy('p1', 'a', 2)
+ * });
+ * console.log(o.get('p2')); // [{a: 2}]
+ * o.set('p1.0.a', 2);
+ * console.log(o.get('p2')); // [{a: 2}, {a: 2}]
+ * </pre>
  *
  * @method filterBy
  * @param {string} collectionKey
@@ -530,6 +736,15 @@ computed.filterBy = function (collectionKey, propertyName, neededValue) {
 
 /**
  * A computed property that returns first collection's item that has needed property value
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: [{a: 1, b: 1}, {a: 2, b: 2}, {a: 3, b: 3}],
+ *  p2: Em.computed.findBy('p1', 'a', 2)
+ * });
+ * console.log(o.get('p2')); // [{a: 2, b: 2}]
+ * o.set('p1.0.a', 2);
+ * console.log(o.get('p2')); // [{a: 2, b: 1}]
+ * </pre>
  *
  * @method findBy
  * @param {string} collectionKey
@@ -551,6 +766,15 @@ 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
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: {a: {b: {c: 2}}},
+ *  p2: Em.computed.alias('p1.a.b.c')
+ * });
+ * console.log(o.get('p2')); // 2
+ * o.set('p1.a.b.c', 4);
+ * console.log(o.get('p2')); // 4
+ * </pre>
  *
  * @method alias
  * @param {string} dependentKey
@@ -564,6 +788,15 @@ computed.alias = function (dependentKey) {
 
 /**
  * A computed property that returns true if dependent property exists in the needed values
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 2,
+ *  p2: Em.computed.existsIn('p1', [1, 2, 3])
+ * });
+ * console.log(o.get('p2')); // true
+ * o.set('p1', 4);
+ * console.log(o.get('p2')); // false
+ * </pre>
  *
  * @method existsIn
  * @param {string} dependentKey
@@ -579,6 +812,15 @@ computed.existsIn = function (dependentKey, neededValues) {
 
 /**
  * A computed property that returns true if dependent property doesn't exist in the needed values
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 2,
+ *  p2: Em.computed.notExistsIn('p1', [1, 2, 3])
+ * });
+ * console.log(o.get('p2')); // false
+ * o.set('p1', 4);
+ * console.log(o.get('p2')); // true
+ * </pre>
  *
  * @method notExistsIn
  * @param {string} dependentKey
@@ -597,6 +839,16 @@ computed.notExistsIn = function (dependentKey, neededValues) {
  * If accuracy is 0 (by default), result is rounded to integer
  * Otherwise - result is float with provided accuracy
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 2,
+ *  p2: 4,
+ *  p3: Em.computed.percents('p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // 50
+ * o.set('p2', 5);
+ * console.log(o.get('p3')); // 40
+ * </pre>
  *
  * @method percents
  * @param {string} dependentKey1
@@ -621,6 +873,15 @@ computed.percents = function (dependentKey1, dependentKey2, accuracy) {
 
 /**
  * A computed property that returns result of <code>App.format.role</code> for dependent value
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'SECONDARY_NAMENODE',
+ *  p3: Em.computed.formatRole('p1')
+ * });
+ * console.log(o.get('p2')); // 'SNameNode'
+ * o.set('p1', 'FLUME_HANDLER);
+ * console.log(o.get('p2')); // 'Flume'
+ * </pre>
  *
  * @method formatRole
  * @param {string} dependentKey
@@ -635,6 +896,15 @@ computed.formatRole = function (dependentKey) {
 
 /**
  * A computed property that returns sum of the named property in the each collection's item
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: [{a: 1}, {a: 2}, {a: 3}],
+ *  p2: Em.computed.sumBy('p1', 'a')
+ * });
+ * console.log(o.get('p2')); // 6
+ * o.set('p1.0.a', 2);
+ * console.log(o.get('p2')); // 7
+ * </pre>
  *
  * @method sumBy
  * @param {string} collectionKey
@@ -674,9 +944,46 @@ computed.i18nFormat = generateComputedWithKey(function (key, dependentValues) {
 });
 
 /**
+ * A computed property that returns string formatted with dependent properties
+ * Takes at least one argument
+ * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'abc',
+ *  p2: 'cba',
+ *  p3: Em.computed.format('{0} => {1}', 'p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // 'abc => cba'
+ * o.set('p1', 'aaa');
+ * console.log(o.get('p3')); // 'aaa => cba'
+ * </pre>
+ *
+ * @param {string} str string to format
+ * @param {...string} dependentKeys
+ * @method format
+ * @returns {Ember.ComputedProperty}
+ */
+computed.format = generateComputedWithKey(function (str, dependentValues) {
+  if (!str) {
+    return '';
+  }
+  return str.format.apply(str, dependentValues);
+});
+
+/**
  * A computed property that returns dependent values joined with separator
  * Takes at least one argument
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 'abc',
+ *  p2: 'cba',
+ *  p3: Em.computed.concat('|', 'p1', 'p2')
+ * });
+ * console.log(o.get('p3')); // 'abc|cba'
+ * o.set('p1', 'aaa');
+ * console.log(o.get('p3')); // 'aaa|cba'
+ * </pre>
  *
  * @param {string} separator
  * @param {...string} dependentKeys
@@ -693,9 +1000,20 @@ computed.concat = generateComputedWithKey(function (separator, dependentValues)
  * Takes at least 1 argument
  * Dependent values order affects the result
  * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: null,
+ *  p2: '',
+ *  p3: 'abc'
+ *  p4: Em.computed.firstNotBlank('p1', 'p2', 'p3')
+ * });
+ * console.log(o.get('p4')); // 'abc'
+ * o.set('p1', 'aaa');
+ * console.log(o.get('p4')); // 'aaa'
+ * </pre>
  *
  * @param {...string} dependentKeys
- * @method {firstNotBlank}
+ * @method firstNotBlank
  * @return {Ember.ComputedProperty}
  */
 computed.firstNotBlank = generateComputedWithValues(function (values) {
@@ -705,4 +1023,69 @@ computed.firstNotBlank = generateComputedWithValues(function (values) {
     }
   }
   return null;
-});
\ No newline at end of file
+});
+
+/**
+ * A computed property that returns dependent value if it is truly or ('0'|0)
+ * Returns <code>'n/a'</code> otherwise
+ * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 0,
+ *  p2: Em.computed.formatUnavailable('p1')
+ * });
+ * console.log(o.get('p2')); // 0
+ * o.set('p1', 12);
+ * console.log(o.get('p2')); // 12
+ * o.set('p1', 'some string');
+ * console.log(o.get('p2')); // 'n/a'
+ * </pre>
+ *
+ * @param {string} dependentKey
+ * @method formatUnavailable
+ * @returns {Ember.ComputedProperty}
+ */
+computed.formatUnavailable = function(dependentKey) {
+  return computed(dependentKey, function () {
+    var value = smartGet(this, dependentKey);
+    return (value || value == 0) ? value : Em.I18n.t('services.service.summary.notAvailable');
+  });
+};
+
+/**
+ * A computed property that returns one of provided values basing on dependent value
+ * If dependent value is 0, <code>zeroMsg</code> is returned
+ * If dependent value is 1, <code>oneMsg</code> is returned
+ * If dependent value is greater than 1, <code>manyMsg</code> is returned
+ * App.*-keys are supported
+ * <pre>
+ * var o = Em.Object.create({
+ *  p1: 0,
+ *  p2: Em.computed.formatUnavailable('p1', '0msg', '1msg', '2+msg')
+ * });
+ * console.log(o.get('p2')); // '0msg'
+ * o.set('p1', 1);
+ * console.log(o.get('p2')); // '1msg'
+ * o.set('p1', 100500);
+ * console.log(o.get('p2')); // '2+msg'
+ * </pre>
+ *
+ * @param {string} dependentKey
+ * @param {string} zeroMsg
+ * @param {string} oneMsg
+ * @param {string} manyMsg
+ * @returns {Ember.ComputedProperty}
+ * @method countBasedMessage
+ */
+computed.countBasedMessage = function (dependentKey, zeroMsg, oneMsg, manyMsg) {
+  return computed(dependentKey, function () {
+    var value = Number(smartGet(this, dependentKey));
+    if (value === 0) {
+      return zeroMsg;
+    }
+    if (value > 1) {
+      return manyMsg;
+    }
+    return oneMsg;
+  });
+};
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/ambari/blob/fd29b081/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 4aa3158..3a22f99 100644
--- a/ambari-web/test/utils/ember_computed_test.js
+++ b/ambari-web/test/utils/ember_computed_test.js
@@ -806,6 +806,10 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.false;
     });
 
+    it('`prop2` has valid dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1']);
+    });
+
   });
 
   describe('#someBy', function () {
@@ -831,6 +835,10 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.false;
     });
 
+    it('`prop2` has valid dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1.@each.a']);
+    });
+
   });
 
   describe('#everyBy', function () {
@@ -856,6 +864,10 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.false;
     });
 
+    it('`prop2` has valid dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1.@each.a']);
+    });
+
   });
 
   describe('#mapBy', function () {
@@ -881,6 +893,10 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.eql([]);
     });
 
+    it('`prop2` has valid dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1.@each.a']);
+    });
+
   });
 
   describe('#filterBy', function () {
@@ -906,6 +922,10 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.eql([]);
     });
 
+    it('`prop2` has valid dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1.@each.a']);
+    });
+
   });
 
   describe('#findBy', function () {
@@ -931,6 +951,10 @@ describe('Ember.computed macros', function () {
       expect(this.obj.get('prop2')).to.be.null;
     });
 
+    it('`prop2` has valid dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop2._dependentKeys).to.eql(['prop1.@each.a']);
+    });
+
   });
 
   describe('#alias', function() {
@@ -1306,4 +1330,140 @@ describe('Ember.computed macros', function () {
 
   });
 
+  describe('#format', function () {
+
+    beforeEach(function () {
+
+      App.setProperties({
+        someAnotherKey: 'some value'
+      });
+
+      this.obj = Em.Object.create({
+        prop1: 'abc',
+        prop2: 'cba',
+        prop3: 'aaa',
+        prop4: Em.computed.format('{0} {1} {2}', 'prop1', 'prop2', 'prop3'),
+        prop5: Em.computed.format(null, 'prop1', 'prop2', 'prop3'),
+        prop6: Em.computed.format('{0} {1} {2}', 'App.someRandomTestingKey', 'prop2', 'prop3')
+      });
+    });
+
+    it('`prop4` check dependent keys', function () {
+      expect(Em.meta(this.obj).descs.prop4._dependentKeys).to.eql(['prop1', 'prop2', 'prop3']);
+    });
+
+    it('should format message', function () {
+      expect(this.obj.get('prop4')).to.equal('abc cba aaa');
+    });
+
+    it('should format message (2)', function () {
+      this.obj.set('prop1', 'aaa');
+      expect(this.obj.get('prop4')).to.equal('aaa cba aaa');
+    });
+
+    it('empty string for not existing i18-key', 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('#formatUnavailable', function () {
+
+    beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: 1
+      });
+
+      this.obj = Em.Object.create({
+        prop1: 1,
+        prop2: Em.computed.formatUnavailable('prop1'),
+        prop3: Em.computed.formatUnavailable('App.someRandomTestingKey')
+      });
+    });
+
+    it('`value` is 1', function () {
+      expect(this.obj.get('prop2')).to.equal(1);
+      expect(this.obj.get('prop3')).to.equal(1);
+    });
+
+    it('`value` is 0', function () {
+      App.set('someAnotherKey', 0);
+      this.obj.set('prop1', 0);
+      expect(this.obj.get('prop2')).to.equal(0);
+      expect(this.obj.get('prop3')).to.equal(0);
+    });
+
+    it('`value` is `0`', function () {
+      App.set('someAnotherKey', '0');
+      this.obj.set('prop1', '0');
+      expect(this.obj.get('prop2')).to.equal('0');
+      expect(this.obj.get('prop3')).to.equal('0');
+    });
+
+    it('`value` is not numeric', function () {
+      App.set('someAnotherKey', null);
+      this.obj.set('prop1', null);
+      expect(this.obj.get('prop2')).to.equal('n/a');
+      expect(this.obj.get('prop3')).to.equal('n/a');
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
+  });
+
+  describe('#countBasedMessage', function () {
+
+    var msg0 = 'msg0';
+    var msg1 = 'msg1';
+    var msgM = 'msgM';
+
+    beforeEach(function () {
+      App.setProperties({
+        someAnotherKey: 1
+      });
+
+      this.obj = Em.Object.create({
+        prop1: 1,
+        prop2: Em.computed.countBasedMessage('prop1', msg0, msg1, msgM),
+        prop3: Em.computed.countBasedMessage('App.someRandomTestingKey', msg0, msg1, msgM)
+      });
+    });
+
+    it('`value` is 1', function () {
+      expect(this.obj.get('prop2')).to.equal(msg1);
+      expect(this.obj.get('prop3')).to.equal(msg1);
+    });
+
+    it('`value` is 0', function () {
+      App.set('someAnotherKey', 0);
+      this.obj.set('prop1', 0);
+      expect(this.obj.get('prop2')).to.equal(msg0);
+      expect(this.obj.get('prop3')).to.equal(msg0);
+    });
+
+    it('`value` is greater than 1', function () {
+      App.set('someAnotherKey', 3);
+      this.obj.set('prop1', 3);
+      expect(this.obj.get('prop2')).to.equal(msgM);
+      expect(this.obj.get('prop3')).to.equal(msgM);
+    });
+
+    it('prop3 dependent keys are valid', function () {
+      expect(Em.meta(this.obj).descs.prop3._dependentKeys).to.eql(['App.someRandomTestingKey']);
+    });
+
+  });
+
 });
\ No newline at end of file