Browse Source

first version of Mixins module for mixing attributes of one object into another

Myk Melez 15 years ago
parent
commit
ac0aa1e8c1
2 changed files with 107 additions and 0 deletions
  1. 83 0
      Mixins.js
  2. 24 0
      test/unit/test_Mixins.js

+ 83 - 0
Mixins.js

@@ -0,0 +1,83 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Snowl.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Myk Melez <myk@mozilla.org>
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either the GNU General Public License Version 2 or later (the "GPL"), or
+ * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+let EXPORTED_SYMBOLS = ["Mixins"];
+
+/**
+ * Mix attributes (properties, methods, getters/setters) from the source object
+ * into the target object.
+ *
+ * Note: doesn't mix in attributes that already exist in the target object
+ * (i.e. doesn't override existing attributes).
+ * ??? Should it?
+ * 
+ * FIXME: give the target object access in some way to the source's version
+ * of attributes it overrides.
+ *
+ * @param   source  {Object}  the object that provides attributes
+ * @param   target  {Object}  the object that receives attributes
+ */
+function mixin(source, target) {
+  for (let attr in source) {
+    // Don't mix in attributes that already exist in the target.
+    if (attr in target)
+      continue;
+
+    let getter = source.__lookupGetter__(attr);
+    let setter = source.__lookupSetter__(attr);
+
+    if (getter || setter) {
+      if (getter)
+        target.__defineGetter__(attr, getter);
+      if (setter)
+        target.__defineSetter__(attr, setter);
+    }
+    else
+       target[attr] = source[attr];
+  }
+}
+
+// FIXME: support both source and target arguments accepting arrays of objects.
+let Mixins = {
+  mix: function(source) {
+    return {
+      source: source,
+      into: function(target) {
+        mixin(this.source, target);
+      }
+    };
+  }
+};

+ 24 - 0
test/unit/test_Mixins.js

@@ -0,0 +1,24 @@
+Components.utils.import("resource://jsmodules/Mixins.js");
+
+let source = {
+  property: 1,
+  property_that_exists_in_target: 2,
+  method: function() {},
+  get getter() {},
+  set setter() {}
+};
+
+let target = {
+  property_that_exists_in_target: 3
+};
+
+function run_test() {
+  Mixins.mix(source).into(target);
+  do_check_eq(target.property, source.property);
+  do_check_eq(target.property_that_exists_in_target, 3);
+  do_check_eq(target.method, source.method);
+  do_check_eq(target.__lookupGetter__("getter"),
+              source.__lookupGetter__("getter"));
+  do_check_eq(target.__lookupSetter__("setter"),
+              source.__lookupSetter__("setter"));
+}