fixed process.mixin to properly copy getters/setters
authorRasmus Andersson <rasmus@notion.se>
Thu, 18 Feb 2010 16:50:48 +0000 (17:50 +0100)
committerRyan Dahl <ry@tinyclouds.org>
Thu, 18 Feb 2010 18:17:13 +0000 (10:17 -0800)
src/node.js
test/mjsunit/test-process-mixin.js

index 4506bd8..0d3da4c 100644 (file)
@@ -105,9 +105,10 @@ process.assert = function (x, msg) {
 // Copyright (c) 2009 John Resig
 // Dual licensed under the MIT and GPL licenses.
 // http://docs.jquery.com/License
+// Modified for node.js (formely for copying properties correctly)
 process.mixin = function() {
   // copy reference to target object
-  var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, options;
+  var target = arguments[0] || {}, i = 1, length = arguments.length, deep = false, source;
 
   // Handle a deep copy situation
   if ( typeof target === "boolean" ) {
@@ -129,27 +130,31 @@ process.mixin = function() {
 
   for ( ; i < length; i++ ) {
     // Only deal with non-null/undefined values
-    if ( (options = arguments[ i ]) != null ) {
+    if ( (source = 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" ) {
-          target[ name ] = process.mixin( deep,
-            // Never move original objects, clone them
-            src || ( copy.length != null ? [ ] : { } )
-          , copy );
-
-        // Don't bring in undefined values
-        } else {
-          target[ name ] = copy;
+      Object.getOwnPropertyNames(source).forEach(function(k){
+        var d = Object.getOwnPropertyDescriptor(source, k);
+        if (d.get) {
+          target.__defineGetter__(k, d.get);
+          if (d.set)
+            target.__defineSetter__(k, d.set);
         }
-      }
+        else {
+          // Prevent never-ending loop
+          if (target === d.value)
+            continue;
+          
+          if (deep && d.value && typeof d.value === "object") {
+            target[k] = process.mixin(deep,
+              // Never move original objects, clone them
+              source || (d.value.length != null ? [] : {})
+            , d.value);
+          }
+          else {
+            target[k] = d.value;
+          }
+        }
+      });
     }
   }
   // Return the modified object
index f357825..502c229 100644 (file)
@@ -19,4 +19,19 @@ var objectWithUndefinedValue = {foo: undefined};
 target = {};
 
 process.mixin(target, objectWithUndefinedValue);
-assert.ok(target.hasOwnProperty('foo'));
\ No newline at end of file
+assert.ok(target.hasOwnProperty('foo'));
+
+// This test verifies getters and setters being copied correctly
+
+var source = {
+  _foo:'a',
+  get foo(){ return this._foo; },
+  set foo(value){ this._foo = "did set to "+value; }
+};
+var target = {};
+process.mixin(target, source);
+target._foo = 'b';
+assert.equal(source.foo, 'a');
+assert.equal('b', target.foo, 'target.foo != "b" -- value/result was copied instead of getter function');
+source.foo = 'c';
+assert.equal('did set to c', source.foo, 'source.foo != "c" -- value was set instead of calling setter function');