From f308cbc7569b75304d29b6f6393f9253416e2e8a Mon Sep 17 00:00:00 2001 From: "Alex A. Naanou" Date: Wed, 6 May 2020 05:30:11 +0300 Subject: [PATCH] added mixout(..)... Signed-off-by: Alex A. Naanou --- README.md | 35 ++++++++++++++++++++++++++++++++ object.js | 60 +++++++++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 89 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 5bf746c..621ccab 100755 --- a/README.md +++ b/README.md @@ -105,6 +105,7 @@ class L extends Array { - [Inheritance](#inheritance) - [Callable instances](#callable-instances) - [Advanced usage](#advanced-usage) + - [Mix-ins](#mix-ins) - [Low level constructor](#low-level-constructor) - [Extending the constructor](#extending-the-constructor) - [Inheriting from native constructor objects](#inheriting-from-native-constructor-objects) @@ -242,6 +243,40 @@ user's responsibility to call `.__call__(..)` method. (this may change in the future) +### Mix-ins + +Prototype-based mixin... +```javascript + +var utilityMixin = { + utility: function(){ + // ... + }, +} + +var Base = object.Constructor('Base') + + +// mixin directly into the instance... +var m = object.mixin(Base(), utilityMixin) +``` + +`.mixin(..)` will copy the contents of `utilityMixin` into the prototype +chain between `m` and `m.__proto__`. + + +Constructor-based mixin... +```javascript +var UtilityMixin = function(parent){ + return object.Constructor(parent.name + '+utils', parent, utilityMixin) } + +var Mixed = object.Constructor('Mixed', UtilityMixin(Base), { + // ... +}) + +var m = Mixed() +``` + ## Advanced usage diff --git a/object.js b/object.js index 6be106b..08f2ef5 100755 --- a/object.js +++ b/object.js @@ -206,8 +206,8 @@ function(proto, name){ // Find the next parent method and call it... // -// parentCall(proto, name, this, ...) -// parentCall(meth, this, ...) +// parentCall(proto, name, this, ..) +// parentCall(meth, this, ..) // -> res // -> undefined // @@ -260,7 +260,7 @@ function(root, ...objects){ // Mix sets of methods/props/attrs into an object as prototypes... // -// mixin(root, object, ...) +// mixin(root, object, ..) // -> root // // @@ -268,14 +268,62 @@ function(root, ...objects){ // mixinFlat(..) the method set into this object leaving the // original objects intact. // -// root <-- object1_copy <-- .. <-- objectN_copy +// root <-- object1_copy <-- .. <-- objectN_copy <- root.__proto__ // +// +// NOTE: this will only mix in non-empty objects... +// +// XXX BUG: this is wrong... +// var m = { m: function(){ console.log('!!!') } } +// var a = object.Constructor('A', Array, {})() +// var aa = object.mixin(a, m) +// aa === a // -> false var mixin = module.mixin = function(root, ...objects){ - return objects + root.__proto__ = objects .reduce(function(res, cur){ - return module.mixinFlat(Object.create(res), cur) }, root) } + return Object.keys(cur).length > 0 ? + module.mixinFlat(Object.create(res), cur) + : res }, root.__proto__) + return root } + + +// Mix-out sets of methods/props/attrs out of an object prototype chain... +// +// mixout(root, object, ..) +// -> root +// +// This is the opposite to mixin(..) +// +// XXX Q: should this drop all occurences (current) or just the first??? +// XXX revise... +var mixout = +module.mixout = +function(root, ...objects){ + var match = function(root, obj){ + if(root === obj){ + return true } + if(Object.keys(root).length != Object.keys(obj).length){ + return false } + var e = Object.entries(obj) + while(e.length > 0){ + var [k, v] = e.pop() + if(!root.hasOwnProperty(k) || root[k] !== v){ + return false } } + return true } + var drop = function(obj){ + var cur = root + while(cur.__proto__ != null){ + match(cur.__proto__, obj) + && (cur.__proto__ = cur.__proto__.__proto__) + cur = cur.__proto__ } + return root } + + // do the work... + objects.map(drop) + + return root }