Remove include() add node.mixin()
authorRyan Dahl <ry@tinyclouds.org>
Mon, 5 Oct 2009 13:46:31 +0000 (15:46 +0200)
committerRyan Dahl <ry@tinyclouds.org>
Mon, 5 Oct 2009 13:46:31 +0000 (15:46 +0200)
include() should not be used by libraries because it will pollute the global
namespace. To discourage this behavior and bring Node more in-line with
the current CommonJS module system, include() is removed.

Small scripts like unit tests often times do want to pollute the global
namespace for ease. To avoid the boiler plate code of

  var x = require("/x.js");
  var foo = x.foo;
  var bar = x.bar;

The function node.mixin() is stolen from jQuery's jQuery.extend. So that it
can be written:

  node.mixin(require("/x.js"));

Reference:
http://docs.jquery.com/Utilities/jQuery.extend
http://groups.google.com/group/nodejs/browse_thread/thread/f9ac83e5c11e7e87

46 files changed:
benchmark/http_simple.js
benchmark/process_loop.js
benchmark/run.js
bin/node-repl
doc/api.txt
src/node.js
src/util.js
test/mjsunit/common.js
test/mjsunit/disabled/test-cat.js
test/mjsunit/disabled/test-http-stress.js
test/mjsunit/disabled/test-remote-module-loading.js
test/mjsunit/disabled/test_dns.js
test/mjsunit/test-buffered-file.js
test/mjsunit/test-delayed-require.js
test/mjsunit/test-event-emitter-add-listeners.js
test/mjsunit/test-exec.js
test/mjsunit/test-file-cat-noexist.js
test/mjsunit/test-fs-stat.js
test/mjsunit/test-fs-write.js
test/mjsunit/test-http-cat.js
test/mjsunit/test-http-client-race.js
test/mjsunit/test-http-client-upload.js
test/mjsunit/test-http-malformed-request.js
test/mjsunit/test-http-proxy.js
test/mjsunit/test-http-server.js
test/mjsunit/test-http.js
test/mjsunit/test-mkdir-rmdir.js
test/mjsunit/test-module-loading.js
test/mjsunit/test-multipart.js
test/mjsunit/test-process-buffering.js
test/mjsunit/test-process-kill.js
test/mjsunit/test-process-simple.js
test/mjsunit/test-process-spawn-loop.js
test/mjsunit/test-promise-wait.js
test/mjsunit/test-readdir.js
test/mjsunit/test-tcp-binary.js
test/mjsunit/test-tcp-many-clients.js
test/mjsunit/test-tcp-pingpong-delay.js
test/mjsunit/test-tcp-pingpong.js
test/mjsunit/test-tcp-reconnect.js
test/mjsunit/test-tcp-throttle-kernel-buffer.js
test/mjsunit/test-tcp-throttle.js
test/mjsunit/test-tcp-timeout.js
test/mjsunit/test-timers.js
test/mjsunit/test-utf8-scripts.js
test/mjsunit/test-wait-ordering.js

index f334c01..8974af6 100644 (file)
@@ -1,7 +1,7 @@
 libDir = node.path.join(node.path.dirname(__filename), "../lib");
 node.libraryPaths.unshift(libDir);
 
-include("/utils.js");
+node.mixin(require("/utils.js"));
 http = require("/http.js");
 
 fixed = ""
@@ -16,7 +16,7 @@ http.createServer(function (req, res) {
   var arg = commands[2];
   var status = 200;
 
-  //p(req.headers);
+  p(req.uri.params);
 
   if (command == "bytes") {
     var n = parseInt(arg, 10)
index 2e1e354..e338ad3 100644 (file)
@@ -1,6 +1,6 @@
 libDir = node.path.join(node.path.dirname(__filename), "../lib");
 node.libraryPaths.unshift(libDir);
-include("/utils.js");
+node.mixin(require("/utils.js"));
 function next (i) {
   if (i <= 0) return;
 
index d9c2668..869ae55 100644 (file)
@@ -1,6 +1,6 @@
 libDir = node.path.join(node.path.dirname(__filename), "../lib");
 node.libraryPaths.unshift(libDir);
-include("/utils.js");
+node.mixin(require("/utils.js"));
 var benchmarks = [ "static_http_server.js" 
                  , "timers.js"
                  , "process_loop.js"
index 20f04e8..00975dc 100755 (executable)
@@ -1,6 +1,6 @@
 #!/usr/bin/env node
 
-include("/utils.js");
+node.mixin(require("/utils.js"));
 puts("Welcome to the Node.js REPL.");
 puts("Enter ECMAScript at the prompt.");
 puts("Tip 1: Use 'rlwrap node-repl' for a better interface");
index f766eca..4e6fbb0 100644 (file)
@@ -16,8 +16,8 @@ An example of a web server written with Node which responds with "Hello
 World": 
 
 ----------------------------------------
-include("/utils.js");
-include("/http.js");
+node.mixin(require("/utils.js"));
+node.mixin(require("/http.js"));
 createServer(function (request, response) {
   response.sendHeader(200, {"Content-Type": "text/plain"});
   response.sendBody("Hello World\n");
@@ -61,11 +61,23 @@ error reporting.
 The filename of the script being executed.
 
 +require(path)+ ::
-+include(path)+ ::
 See the modules section.
 
 +node.libraryPaths+ ::
-The search path for absolute path arguments to +require()+ and +include()+.
+The search path for absolute path arguments to +require()+.
+
++node.mixin([deep], target, object1, [objectN])+ ::
+Extend one object with one or more others, returning the modified object.
+If no target is specified, the +process+ namespace itself is extended. 
+Keep in mind that the target object will be modified, and will be returned
+from +node.mixin()+.
++
+If a boolean true is specified as the first argument, Node performs a deep
+copy, recursively copying any objects it finds. Otherwise, the copy will
+share structure with the original object(s).
++
+Undefined properties are not copied. However, properties inherited from the
+object's prototype will be copied over.
 
 === The +process+ Object
 
@@ -119,7 +131,7 @@ Executes the command as a child process, buffers the output and returns it
 in a promise callback.
 +
 ----------------------------------------
-include("/utils.js");
+node.mixin(require("/utils.js"));
 exec("ls /").addCallback(function (stdout, stderr) {
   puts(stdout);
 });
@@ -269,7 +281,7 @@ The contents of +foo.js+:
 
 ----------------------------------------
 var circle = require("circle.js");
-include("/utils.js");
+node.mixin(require("/utils.js"));
 puts("The area of a circle of radius 4 is " + circle.area(4));
 ----------------------------------------
 
@@ -292,24 +304,20 @@ The module +circle.js+ has exported the functions +area()+ and
 object.  (Alternatively, one can use +this+ instead of +exports+.) Variables
 local to the module will be private. In this example the variable +PI+ is
 private to +circle.js+. The function +puts()+ comes from the module
-+"/utils.js"+. Because +include("/utils.js")+ was called, +puts()+ is in the
-global namespace.
++"/utils.js"+.
 
 The module path is relative to the file calling +require()+.  That is,
 +circle.js+ must be in the same directory as +foo.js+ for +require()+ to
 find it.
 
-Like +require()+ the function +include()+ also loads a module. Instead of
-returning a namespace object, +include()+ will add the module's exports into
-the global namespace. For example:
+Use +node.mixin()+ to include modules into the global namespace.
 
 ----------------------------------------
-include("circle.js");
-include("/utils.js");
+node.mixin(process, require("circle.js"), require("/utils.js"));
 puts("The area of a cirlce of radius 4 is " + area(4));
 ----------------------------------------
 
-When an absolute path is given to +require()+ or +include()+, like
+When an absolute path is given to +require()+, like
 +require("/mjsunit.js")+ the module is searched for in the
 +node.libraryPaths+ array. +node.libraryPaths+ on my system looks like this: 
 
@@ -567,8 +575,7 @@ Objects returned from +node.fs.stat()+ are of this type.
 
 === HTTP
 
-To use the HTTP server and client one must +require("/http.js")+ or
-+include("/http.js")+.
+To use the HTTP server and client one must +require("/http.js")+.
 
 The HTTP interfaces in Node are designed to support many features
 of the protocol which have been traditionally difficult to use.
@@ -990,8 +997,7 @@ stream.addListener('complete', function() {
 
 === TCP
 
-To use the TCP server and client one must +require("/tcp.js")+ or
-+include("/tcp.js")+.
+To use the TCP server and client one must +require("/tcp.js")+.
 
 ==== +tcp.Server+
 
@@ -999,7 +1005,7 @@ Here is an example of a echo server which listens for connections
 on port 7000
 
 ----------------------------------------
-include("/tcp.js");
+node.mixin(require("/tcp.js"));
 var server = createServer(function (socket) {
   socket.setEncoding("utf8");
   socket.addListener("connect", function () {
@@ -1237,8 +1243,8 @@ result of the last expression.
 
 The library is called +/repl.js+ and it can be used like this:
 ------------------------------------
-include("/utils.js");
-include("/tcp.js");
+node.mixin(require("/utils.js"));
+node.mixin(require("/tcp.js"));
 nconnections = 0;
 createServer(function (c) {
   error("Connection!");
index 1cf7989..57a40c2 100644 (file)
@@ -13,7 +13,7 @@ node.createChildProcess = function (command) {
 };
 
 node.exec = function () {
-  throw new Error("node.exec() has moved. Use include('/utils.js') to bring it back.");
+  throw new Error("node.exec() has moved. Use require('/utils.js') to bring it back.");
 }
 
 node.http.createServer = function () {
@@ -28,6 +28,61 @@ node.tcp.createConnection = function (port, host) {
   throw new Error("node.tcp.createConnection() has moved. Use require('/tcp.js') to access it.");
 };
 
+/* From jQuery.extend in the jQuery JavaScript Library v1.3.2
+ * Copyright (c) 2009 John Resig
+ * Dual licensed under the MIT and GPL licenses.
+ * http://docs.jquery.com/License
+ */
+node.mixin = function() {
+       // copy reference to target object
+       var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+
+       // Handle a deep copy situation
+       if ( typeof target === "boolean" ) {
+               deep = target;
+               target = arguments[1] || {};
+               // skip the boolean and the target
+               i = 2;
+       }
+
+       // Handle case when target is a string or something (possible in deep copy)
+       if ( typeof target !== "object" && !node.isFunction(target) )
+               target = {};
+
+       // mixin process itself if only one argument is passed
+       if ( length == i ) {
+               target = process;
+               --i;
+       }
+
+       for ( ; i < length; i++ )
+               // Only deal with non-null/undefined values
+               if ( (options = arguments[ i ]) != null )
+                       // Extend the base object
+                       for ( var name in options ) {
+                               var src = target[ name ], copy = options[ name ];
+
+                               // Prevent never-ending loop
+                               if ( target === copy )
+                                       continue;
+
+                               // Recurse if we're merging object values
+                               if ( deep && copy && typeof copy === "object" && !copy.nodeType )
+                                       target[ name ] = node.mixin( deep, 
+                                               // Never move original objects, clone them
+                                               src || ( copy.length != null ? [ ] : { } )
+                                       , copy );
+
+                               // Don't bring in undefined values
+                               else if ( copy !== undefined )
+                                       target[ name ] = copy;
+
+                       }
+
+       // Return the modified object
+       return target;
+};
+
 // Timers
 
 function setTimeout (callback, after) {
@@ -207,27 +262,12 @@ node.Module.prototype.loadScript = function (loadPromise) {
       return requireAsync(url).wait();
     }
 
-    function includeAsync (url) {
-      var promise = requireAsync(url)
-      promise.addCallback(function (t) {
-        // copy properties into global namespace.
-        for (var prop in t) {
-          if (t.hasOwnProperty(prop)) process[prop] = t[prop];
-        }
-      });
-      return promise;
-    }
-
-    function include (url) {
-      includeAsync(url).wait();
-    }
-
     // create wrapper function
-    var wrapper = "function (__filename, exports, require, include) { " + content + "\n};";
+    var wrapper = "function (__filename, exports, require) { " + content + "\n};";
     var compiled_wrapper = node.compile(wrapper, self.filename);
 
     node.loadingModules.unshift(self);
-    compiled_wrapper.apply(self.target, [self.filename, self.target, require, include]);
+    compiled_wrapper.apply(self.target, [self.filename, self.target, require]);
     node.loadingModules.shift();
 
     self.waitChildrenLoad(function () {
index 0a477bb..4c79f0a 100644 (file)
@@ -70,21 +70,21 @@ node.path = new function () {
 
 
 puts = function () {
-  throw new Error("puts() has moved. Use include('/utils.js') to bring it back.");
+  throw new Error("puts() has moved. Use require('/utils.js') to bring it back.");
 }
 
 print = function () {
-  throw new Error("print() has moved. Use include('/utils.js') to bring it back.");
+  throw new Error("print() has moved. Use require('/utils.js') to bring it back.");
 }
 
 p = function () {
-  throw new Error("p() has moved. Use include('/utils.js') to bring it back.");
+  throw new Error("p() has moved. Use require('/utils.js') to bring it back.");
 }
 
 node.debug = function () {
-  throw new Error("node.debug() has moved. Use include('/utils.js') to bring it back.");
+  throw new Error("node.debug() has moved. Use require('/utils.js') to bring it back.");
 }
 
 node.error = function () {
-  throw new Error("node.error() has moved. Use include('/utils.js') to bring it back.");
+  throw new Error("node.error() has moved. Use require('/utils.js') to bring it back.");
 }
index b74dac6..53338ab 100644 (file)
@@ -5,10 +5,6 @@ exports.libDir = node.path.join(exports.testDir, "../../lib");
 node.libraryPaths.unshift(exports.libDir);
 
 var mjsunit = require("/mjsunit.js");
-include("/utils.js");
-// Copy mjsunit namespace out
-for (var prop in mjsunit) {
-  if (mjsunit.hasOwnProperty(prop)) exports[prop] = mjsunit[prop];
-}
-
+var utils = require("/utils.js");
+node.mixin(exports, mjsunit, utils);
 
index c3bc3fb..22045bb 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("../common.js"));
 http = require("/http.js");
 PORT = 8888;
 
index 7397f1d..3746683 100644 (file)
@@ -1,4 +1,4 @@
-include('../mjsunit.js');
+node.mixin(require('../common.js'));
 
 var PORT = 8003;
 var request_count = 1000;
index cead6d6..2789b2e 100644 (file)
@@ -9,7 +9,7 @@ var s = node.http.createServer(function (req, res) {
 });
 s.listen(8000);
 
-include("mjsunit.js");
+node.mixin(require("../common.js"));
 var a = require("http://localhost:8000/")
 
 assertInstanceof(a.A, Function);
index dc14ad5..ccfcf00 100644 (file)
@@ -1,3 +1,4 @@
+node.mixin(require("../common.js"));
 for (var i = 2; i < ARGV.length; i++) {
   var name = ARGV[i]
   puts("looking up " + name);
index dc10100..a27a3a7 100644 (file)
@@ -1,10 +1,10 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var testTxt = node.path.join(fixturesDir, "test.txt");
 
 var libDir = node.path.join(testDir, "../../lib");
 node.libraryPaths.unshift(libDir);
-include("/file.js");
+node.mixin(require("/file.js"));
 
 var fileUnlinked = false;
 
index 1070516..3501bed 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 setTimeout(function () {
   a = require("fixtures/a.js");
index fa392c6..6d42ff7 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var e = new node.EventEmitter();
 
index 7e386fd..65702cf 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 success_count = 0;
 error_count = 0;
index 6b652d9..a35fb59 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 var got_error = false;
 
 var filename = node.path.join(fixturesDir, "does_not_exist.txt");
index 403a4cc..33c14ba 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var got_error = false;
 var success_count = 0;
index 6c4c2bd..b72d4bd 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var path = node.path.join(fixturesDir, "write.txt");
 var expected = "hello";
index 4e12265..625d287 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 http = require("/http.js");
 PORT = 8888;
 
index 8087d7e..1fbeff2 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 http = require("/http.js");
 PORT = 8888;
 
index 6e95f11..f24acea 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 http = require("/http.js");
 var PORT = 18032;
 
index 72ddb61..3c7173c 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 http = require("/http.js");
 
index f902661..94fa4f0 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 http = require("/http.js");
 
 var PROXY_PORT = 8869;
index 7495afa..3d3bb50 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 http = require("/http.js");
 
index c8d5b27..ebdd6ee 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 http = require("/http.js");
 PORT = 8888;
 
index 08c2fa7..6fedb5c 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var dirname = node.path.dirname(__filename);
 var fixtures = node.path.join(dirname, "fixtures");
index 814f700..cfa3bda 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 debug("load test-module-loading.js");
 
index c8ba90c..262429f 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 http = require("/http.js");
 
 var multipart = require('/multipart.js');
index c55fa51..a5c09d8 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var pwd_called = false;
 
index 8487190..6851e0b 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var exit_status = -1;
 
index 76d2ca9..2fb1976 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var cat = node.createChildProcess("cat");
 
index 0d92c33..2b63dea 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var N = 40;
 var finished = false;
index 5274735..aa7b043 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var p1_done = false;
 var p1 = new node.Promise();
index 5981386..2bf09c6 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var got_error = false;
 
index db431a9..881a9be 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 PORT = 23123;
 
index 0bb644a..5cc3ad2 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 // settings
 var port = 20743;
index 298aff9..687c8d7 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 
 
index d1e068d..a974bf9 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 
 
index c6cf6b9..d1d6e53 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 var N = 50;
 var port = 8921;
index 86cf461..d5144b6 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 PORT = 20444;
 N = 30*1024; // 500kb
index bcd3bcb..cf3b028 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 PORT = 20443;
 N = 200;
index c60fcec..dacb1e1 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 tcp = require("/tcp.js");
 port = 9992;
 exchanges = 0;
index f1b43aa..53c4b9d 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 var WINDOW = 200; // why is does this need to be so big?
 
index c2950d3..cb820bc 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 // üäö
 
index cc05222..40e99df 100644 (file)
@@ -1,4 +1,4 @@
-include("common.js");
+node.mixin(require("common.js"));
 
 function timer (t) {
   var promise = new node.Promise();