Skip to content

Commit 34c0235

Browse files
xaviershayry
authored andcommitted
sys.inspect is totally more awesome now
- No longer relies on JSON.stringify, so it can output nulls and functions - Handles circular references better - Has tests
1 parent 4d818f1 commit 34c0235

File tree

2 files changed

+90
-20
lines changed

2 files changed

+90
-20
lines changed

lib/sys.js

+64-20
Original file line numberDiff line numberDiff line change
@@ -17,26 +17,11 @@ exports.error = function (x) {
1717
/**
1818
* Echos the value of a value. Trys to print the value out
1919
* in the best way possible given the different types.
20-
*
20+
*
2121
* @param {Object} value The object to print out
2222
*/
2323
exports.inspect = function (value) {
24-
if (value === 0) return "0";
25-
if (value === false) return "false";
26-
if (value === "") return '""';
27-
if (typeof(value) == "function") return "[Function]";
28-
if (value === undefined) return;
29-
30-
try {
31-
return JSON.stringify(value, undefined, 1);
32-
} catch (e) {
33-
// TODO make this recusrive and do a partial JSON output of object.
34-
if (e.message.search("circular")) {
35-
return "[Circular Object]";
36-
} else {
37-
throw e;
38-
}
39-
}
24+
return formatter(value, '', []);
4025
};
4126

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

5237
child.addListener("output", function (chunk) {
53-
if (chunk) stdout += chunk;
38+
if (chunk) stdout += chunk;
5439
});
5540

5641
child.addListener("error", function (chunk) {
57-
if (chunk) stderr += chunk;
42+
if (chunk) stderr += chunk;
5843
});
59-
44+
6045
child.addListener("exit", function (code) {
6146
if (code == 0) {
6247
promise.emitSuccess(stdout, stderr);
@@ -82,3 +67,62 @@ exports.exec = function (command) {
8267
* @param {function} superCtor Constructor function to inherit prototype from
8368
*/
8469
exports.inherits = process.inherits;
70+
71+
/**
72+
* A recursive function to format an object - used by inspect.
73+
*
74+
* @param {Object} value
75+
* the value to format
76+
* @param {String} indent
77+
* the indent level of any nested objects, since they are formatted over
78+
* more than one line
79+
* @param {Array} parents
80+
* contains all objects above the current one in the heirachy, used to
81+
* prevent getting stuck in a loop on circular references
82+
*/
83+
var formatter = function(value, indent, parents) {
84+
switch(typeof(value)) {
85+
case 'string': return '"' + value + '"';
86+
case 'number': return '' + value;
87+
case 'function': return '[Function]';
88+
case 'boolean': return '' + value;
89+
case 'undefined': return 'undefined';
90+
case 'object':
91+
if (value == null) return 'null';
92+
if (parents.indexOf(value) >= 0) return '[Circular]';
93+
parents.push(value);
94+
95+
if (value instanceof Array) {
96+
return formatObject(value, indent, parents, '[]', function(x, f) {
97+
return f(value[x]);
98+
});
99+
} else {
100+
return formatObject(value, indent, parents, '{}', function(x, f) {
101+
return f(x) + ': ' + f(value[x]);
102+
});
103+
}
104+
return buffer;
105+
default:
106+
throw('inspect unimplemented for ' + typeof(value));
107+
}
108+
}
109+
110+
/**
111+
* Helper function for formatting either an array or an object, used internally by formatter
112+
*/
113+
var formatObject = function(obj, indent, parents, parenthesis, entryFormatter) {
114+
var buffer = parenthesis[0];
115+
var values = [];
116+
117+
var localFormatter = function(value) {
118+
return formatter(value, indent + ' ', parents);
119+
};
120+
for (x in obj) {
121+
values.push(indent + ' ' + entryFormatter(x, localFormatter));
122+
}
123+
if (values.length > 0) {
124+
buffer += "\n" + values.join(",\n") + "\n" + indent;
125+
}
126+
buffer += parenthesis[1];
127+
return buffer;
128+
}

test/mjsunit/test-sys.js

+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
process.mixin(require("./common"));
2+
process.mixin(require("sys"));
3+
4+
assert.equal("0", inspect(0));
5+
assert.equal("1", inspect(1));
6+
assert.equal("false", inspect(false));
7+
assert.equal('""', inspect(""));
8+
assert.equal('"hello"', inspect("hello"));
9+
assert.equal("[Function]", inspect(function() {}));
10+
assert.equal('undefined', inspect(undefined));
11+
assert.equal('null', inspect(null));
12+
13+
assert.equal('[]', inspect([]));
14+
assert.equal('[\n 1,\n 2\n]', inspect([1, 2]));
15+
assert.equal('[\n 1,\n [\n 2,\n 3\n ]\n]', inspect([1, [2, 3]]));
16+
17+
assert.equal('{}', inspect({}));
18+
assert.equal('{\n "a": 1\n}', inspect({a: 1}));
19+
assert.equal('{\n "a": [Function]\n}', inspect({a: function() {}}));
20+
assert.equal('{\n "a": 1,\n "b": 2\n}', inspect({a: 1, b: 2}));
21+
assert.equal('{\n "a": {}\n}', inspect({'a': {}}));
22+
assert.equal('{\n "a": {\n "b": 2\n }\n}', inspect({'a': {'b': 2}}));
23+
24+
var value = {}
25+
value['a'] = value;
26+
assert.equal('{\n "a": [Circular]\n}', inspect(value));

0 commit comments

Comments
 (0)