util: show meaningful values for boxed primitives
authorNathan Rajlich <nathan@tootallnate.net>
Thu, 6 Feb 2014 02:09:23 +0000 (18:09 -0800)
committerFedor Indutny <fedor.indutny@gmail.com>
Thu, 6 Feb 2014 10:19:47 +0000 (14:19 +0400)
Before, `new String('foo')` would be inspected as `"{}"` which
is simply not very helpful. Now, a more meaningful
`"[String: 'foo']"` result will be returned from `util.inspect()`.

Boxed String, Boolean, and Number types are all supported.

Closes #7047

lib/util.js
test/simple/test-util-inspect.js

index ee803af..500c1d1 100644 (file)
@@ -239,6 +239,28 @@ function formatValue(ctx, value, recurseTimes) {
     keys = Object.getOwnPropertyNames(value);
   }
 
+  // This could be a boxed primitive (new String(), etc.), check valueOf()
+  // NOTE: Avoid calling `valueOf` on `Date` instance because it will return
+  // a number which, when object has some additional user-stored `keys`,
+  // will be printed out.
+  var formatted;
+  var raw = value;
+  try {
+    // the .valueOf() call can fail for a multitude of reasons
+    if (!isDate(value))
+      raw = value.valueOf();
+  } catch (e) {
+    // ignore...
+  }
+
+  if (isString(raw)) {
+    // for boxed Strings, we have to remove the 0-n indexed entries,
+    // since they just noisey up the output and are redundant
+    keys = keys.filter(function(key) {
+      return !(key >= 0 && key < raw.length);
+    });
+  }
+
   // Some type of object without properties can be shortcutted.
   if (keys.length === 0) {
     if (isFunction(value)) {
@@ -254,6 +276,19 @@ function formatValue(ctx, value, recurseTimes) {
     if (isError(value)) {
       return formatError(value);
     }
+    // now check the `raw` value to handle boxed primitives
+    if (isString(raw)) {
+      formatted = formatPrimitiveNoColor(ctx, raw);
+      return ctx.stylize('[String: ' + formatted + ']', 'string');
+    }
+    if (isNumber(raw)) {
+      formatted = formatPrimitiveNoColor(ctx, raw);
+      return ctx.stylize('[Number: ' + formatted + ']', 'number');
+    }
+    if (isBoolean(raw)) {
+      formatted = formatPrimitiveNoColor(ctx, raw);
+      return ctx.stylize('[Boolean: ' + formatted + ']', 'boolean');
+    }
   }
 
   var base = '', array = false, braces = ['{', '}'];
@@ -285,6 +320,24 @@ function formatValue(ctx, value, recurseTimes) {
     base = ' ' + formatError(value);
   }
 
+  // Make boxed primitive Strings look like such
+  if (isString(raw)) {
+    formatted = formatPrimitiveNoColor(ctx, raw);
+    base = ' ' + '[String: ' + formatted + ']';
+  }
+
+  // Make boxed primitive Numbers look like such
+  if (isNumber(raw)) {
+    formatted = formatPrimitiveNoColor(ctx, raw);
+    base = ' ' + '[Number: ' + formatted + ']';
+  }
+
+  // Make boxed primitive Booleans look like such
+  if (isBoolean(raw)) {
+    formatted = formatPrimitiveNoColor(ctx, raw);
+    base = ' ' + '[Boolean: ' + formatted + ']';
+  }
+
   if (keys.length === 0 && (!array || value.length == 0)) {
     return braces[0] + base + braces[1];
   }
@@ -338,6 +391,15 @@ function formatPrimitive(ctx, value) {
 }
 
 
+function formatPrimitiveNoColor(ctx, value) {
+  var stylize = ctx.stylize;
+  ctx.stylize = stylizeNoColor;
+  var str = formatPrimitive(ctx, value);
+  ctx.stylize = stylize;
+  return str;
+}
+
+
 function formatError(value) {
   return '[' + Error.prototype.toString.call(value) + ']';
 }
index 474410e..8651a2d 100644 (file)
@@ -213,3 +213,25 @@ test_lines({
   very_long_key: 'very_long_value',
   even_longer_key: ['with even longer value in array']
 });
+
+// test boxed primitives output the correct values
+assert.equal(util.inspect(new String('test')), '[String: \'test\']');
+assert.equal(util.inspect(new Boolean(false)), '[Boolean: false]');
+assert.equal(util.inspect(new Boolean(true)), '[Boolean: true]');
+assert.equal(util.inspect(new Number(0)), '[Number: 0]');
+assert.equal(util.inspect(new Number(-0)), '[Number: -0]');
+assert.equal(util.inspect(new Number(-1.1)), '[Number: -1.1]');
+assert.equal(util.inspect(new Number(13.37)), '[Number: 13.37]');
+
+// test boxed primitives with own properties
+var str = new String('baz');
+str.foo = 'bar';
+assert.equal(util.inspect(str), '{ [String: \'baz\'] foo: \'bar\' }');
+
+var bool = new Boolean(true);
+bool.foo = 'bar';
+assert.equal(util.inspect(bool), '{ [Boolean: true] foo: \'bar\' }');
+
+var num = new Number(13.37);
+num.foo = 'bar';
+assert.equal(util.inspect(num), '{ [Number: 13.37] foo: \'bar\' }');