Skip to content

Commit

Permalink
sys.inspect is totally more awesome now
Browse files Browse the repository at this point in the history
- No longer relies on JSON.stringify, so it can output nulls and functions
- Handles circular references better
- Has tests
  • Loading branch information
xaviershay authored and ry committed Dec 6, 2009
1 parent 4d818f1 commit 34c0235
Show file tree
Hide file tree
Showing 2 changed files with 90 additions and 20 deletions.
84 changes: 64 additions & 20 deletions lib/sys.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,26 +17,11 @@ exports.error = function (x) {
/**
* Echos the value of a value. Trys to print the value out
* in the best way possible given the different types.
*
*
* @param {Object} value The object to print out
*/
exports.inspect = function (value) {
if (value === 0) return "0";
if (value === false) return "false";
if (value === "") return '""';
if (typeof(value) == "function") return "[Function]";
if (value === undefined) return;

try {
return JSON.stringify(value, undefined, 1);
} catch (e) {
// TODO make this recusrive and do a partial JSON output of object.
if (e.message.search("circular")) {
return "[Circular Object]";
} else {
throw e;
}
}
return formatter(value, '', []);
};

exports.p = function (x) {
Expand All @@ -50,13 +35,13 @@ exports.exec = function (command) {
var promise = new process.Promise();

child.addListener("output", function (chunk) {
if (chunk) stdout += chunk;
if (chunk) stdout += chunk;
});

child.addListener("error", function (chunk) {
if (chunk) stderr += chunk;
if (chunk) stderr += chunk;
});

child.addListener("exit", function (code) {
if (code == 0) {
promise.emitSuccess(stdout, stderr);
Expand All @@ -82,3 +67,62 @@ exports.exec = function (command) {
* @param {function} superCtor Constructor function to inherit prototype from
*/
exports.inherits = process.inherits;

/**
* A recursive function to format an object - used by inspect.
*
* @param {Object} value
* the value to format
* @param {String} indent
* the indent level of any nested objects, since they are formatted over
* more than one line
* @param {Array} parents
* contains all objects above the current one in the heirachy, used to
* prevent getting stuck in a loop on circular references
*/
var formatter = function(value, indent, parents) {
switch(typeof(value)) {
case 'string': return '"' + value + '"';
case 'number': return '' + value;
case 'function': return '[Function]';
case 'boolean': return '' + value;
case 'undefined': return 'undefined';
case 'object':
if (value == null) return 'null';
if (parents.indexOf(value) >= 0) return '[Circular]';
parents.push(value);

if (value instanceof Array) {
return formatObject(value, indent, parents, '[]', function(x, f) {
return f(value[x]);
});
} else {
return formatObject(value, indent, parents, '{}', function(x, f) {
return f(x) + ': ' + f(value[x]);
});
}
return buffer;
default:
throw('inspect unimplemented for ' + typeof(value));
}
}

/**
* Helper function for formatting either an array or an object, used internally by formatter
*/
var formatObject = function(obj, indent, parents, parenthesis, entryFormatter) {
var buffer = parenthesis[0];
var values = [];

var localFormatter = function(value) {
return formatter(value, indent + ' ', parents);
};
for (x in obj) {
values.push(indent + ' ' + entryFormatter(x, localFormatter));
}
if (values.length > 0) {
buffer += "\n" + values.join(",\n") + "\n" + indent;
}
buffer += parenthesis[1];
return buffer;
}
26 changes: 26 additions & 0 deletions test/mjsunit/test-sys.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
process.mixin(require("./common"));
process.mixin(require("sys"));

assert.equal("0", inspect(0));
assert.equal("1", inspect(1));
assert.equal("false", inspect(false));
assert.equal('""', inspect(""));
assert.equal('"hello"', inspect("hello"));
assert.equal("[Function]", inspect(function() {}));
assert.equal('undefined', inspect(undefined));
assert.equal('null', inspect(null));

assert.equal('[]', inspect([]));
assert.equal('[\n 1,\n 2\n]', inspect([1, 2]));
assert.equal('[\n 1,\n [\n 2,\n 3\n ]\n]', inspect([1, [2, 3]]));

assert.equal('{}', inspect({}));
assert.equal('{\n "a": 1\n}', inspect({a: 1}));
assert.equal('{\n "a": [Function]\n}', inspect({a: function() {}}));
assert.equal('{\n "a": 1,\n "b": 2\n}', inspect({a: 1, b: 2}));
assert.equal('{\n "a": {}\n}', inspect({'a': {}}));
assert.equal('{\n "a": {\n "b": 2\n }\n}', inspect({'a': {'b': 2}}));

var value = {}
value['a'] = value;
assert.equal('{\n "a": [Circular]\n}', inspect(value));

0 comments on commit 34c0235

Please sign in to comment.