Created
December 5, 2009 05:43
-
-
Save xaviershay/249560 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
From a0db2d73d6d6099c5bc810d60bcce192c6d81dbe Mon Sep 17 00:00:00 2001 | |
From: Xavier Shay <xavier@rhnh.net> | |
Date: Tue, 1 Dec 2009 21:20:14 +1100 | |
Subject: [PATCH] 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 | |
--- | |
lib/sys.js | 84 +++++++++++++++++++++++++++++++++++----------- | |
test/mjsunit/test-sys.js | 26 ++++++++++++++ | |
2 files changed, 90 insertions(+), 20 deletions(-) | |
create mode 100644 test/mjsunit/test-sys.js | |
diff --git a/lib/sys.js b/lib/sys.js | |
index da749db..16e2606 100644 | |
--- a/lib/sys.js | |
+++ b/lib/sys.js | |
@@ -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) { | |
@@ -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); | |
@@ -88,3 +73,62 @@ exports.inherits = function (ctor, superCtor) { | |
ctor.prototype = new tempCtor(); | |
ctor.prototype.constructor = ctor; | |
}; | |
+ | |
+/** | |
+ * 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; | |
+} | |
diff --git a/test/mjsunit/test-sys.js b/test/mjsunit/test-sys.js | |
new file mode 100644 | |
index 0000000..8a0aa35 | |
--- /dev/null | |
+++ b/test/mjsunit/test-sys.js | |
@@ -0,0 +1,26 @@ | |
+process.mixin(require("./common")); | |
+process.mixin(require("sys")); | |
+ | |
+assertEquals("0", inspect(0)); | |
+assertEquals("1", inspect(1)); | |
+assertEquals("false", inspect(false)); | |
+assertEquals('""', inspect("")); | |
+assertEquals('"hello"', inspect("hello")); | |
+assertEquals("[Function]", inspect(function() {})); | |
+assertEquals('undefined', inspect(undefined)); | |
+assertEquals('null', inspect(null)); | |
+ | |
+assertEquals('[]', inspect([])); | |
+assertEquals('[\n 1,\n 2\n]', inspect([1, 2])); | |
+assertEquals('[\n 1,\n [\n 2,\n 3\n ]\n]', inspect([1, [2, 3]])); | |
+ | |
+assertEquals('{}', inspect({})); | |
+assertEquals('{\n "a": 1\n}', inspect({a: 1})); | |
+assertEquals('{\n "a": [Function]\n}', inspect({a: function() {}})); | |
+assertEquals('{\n "a": 1,\n "b": 2\n}', inspect({a: 1, b: 2})); | |
+assertEquals('{\n "a": {}\n}', inspect({'a': {}})); | |
+assertEquals('{\n "a": {\n "b": 2\n }\n}', inspect({'a': {'b': 2}})); | |
+ | |
+var value = {} | |
+value['a'] = value; | |
+assertEquals('{\n "a": [Circular]\n}', inspect(value)); | |
-- | |
1.6.2.4 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment