diff --git a/lib/proto.js b/lib/proto.js index f052c51..72f30a5 100644 --- a/lib/proto.js +++ b/lib/proto.js @@ -72,15 +72,19 @@ * Mixin a given set of properties * @param prop The properties to mix in * @param obj [optional] + * @param namesList [optional] Array of names to extend with (if empty all are used) * The object to add the mixin */ - mixin: function (prop, obj) { + mixin: function (prop, obj, namesList) { var self = obj || this; var fnTest = /\b_super\b/; var _super = Object.getPrototypeOf(self) || self.prototype; var descriptors = {}; var proto = prop; + var names = namesList && (Array.isArray(namesList) ? namesList : [namesList]); var processProperty = function (name) { + if (names && !names.includes(name)) return; + var descriptor = Object.getOwnPropertyDescriptor(proto, name); if (!descriptors[name] && descriptor) { @@ -119,10 +123,11 @@ * Extend the current or a given object with the given property and return the extended object. * @param prop The properties to extend with * @param obj [optional] The object to extend from + * @param names [optional] Array of names to extend with (if empty all are used) * @returns The extended object */ - extend: function (prop, obj) { - return this.mixin(prop, Object.create(obj || this)); + extend: function (prop, obj, names) { + return this.mixin(prop, Object.create(obj || this), names); }, /** * Return a callback function with this set to the current or a given context object. diff --git a/readme.md b/readme.md index a998803..1ed654b 100644 --- a/readme.md +++ b/readme.md @@ -254,6 +254,30 @@ singHello() // Laaaa Laalaaa! Helloooooo! `proxy` only works on objects extended from UberProto. +### Named extend and mixin +Both `Proto.extend()` and `Proto.mixin()` has an optional third parameter where you can name the methods and symbols you want to extend your object with e.g.: + +``` javascript +operaSinger.mixin({ + sing : function(text){ + return this._super() + ' ' + text; + }, + sang : function(text) { + return this.sing() + ' Lolololooo! ' + text; + }, + sung : function(text) { + return this.sing() + ' Dodododooo! ' + text; + } +}, undefined, [ 'sang', 'sing' ]); + +var singHello = operaSinger.proxy('sing', 'Helloooooo!'); +var sangHello = operaSinger.proxy('sang', 'Helloooooo!'); + +singHello() // Laaaa Laalaaa! Helloooooo! +sangHello() // Laaaa Laalaaa! Lolololooo! Helloooooo! +var sungHello = operaSinger.proxy('sung', 'Helloooooo!'); // results in error +``` + ## License MIT License diff --git a/test/test.js b/test/test.js index e8de526..c527c27 100644 --- a/test/test.js +++ b/test/test.js @@ -265,4 +265,150 @@ describe('UberProto', function () { assert.strictEqual(extext.sayHi(), 'Hi David Luecke!!!'); }); }); + + describe('Named extend and mixin', () => { + it('extends objects with name', function () { + var Original = { + sayHello () { + assert.ok(true, 'sayHello called'); + return 'hello'; + } + }; + var Extended = Proto.extend(Original); + Extended = Extended.extend({ + sayHi: function () { + assert.ok(true, 'sayHi called'); + return 'hi'; + }, + sayYo: function () { + assert.ok(true, 'sayYo called'); + return 'yo'; + } + }, undefined, ['sayHi']); + + assert.strictEqual(Extended.create().sayHi(), 'hi', 'Said hi'); + assert.strictEqual(Extended.create().sayHello(), 'hello', 'Said hello'); + assert.strictEqual(typeof Extended.create().sayYo, 'undefined', 'Cannot Say yo'); + }); + + it('extends objects with names', function () { + var Original = { + sayHello: function () { + assert.ok(true, 'sayHello called'); + return 'hello'; + } + }; + var Extended = Proto.extend(Original); + Extended = Extended.extend({ + sayHi: function () { + assert.ok(true, 'sayHi called'); + return 'hi'; + }, + sayYo: function () { + assert.ok(true, 'sayYo called'); + return 'yo'; + } + }, undefined, ['sayHi', 'sayYo']); + + assert.strictEqual(Extended.create().sayHi(), 'hi', 'Said hi'); + assert.strictEqual(Extended.create().sayHello(), 'hello', 'Said hello'); + assert.strictEqual(Extended.create().sayYo(), 'yo', 'Said yo'); + }); + + it('extends objects with all', function () { + var Original = { + sayHello: function () { + assert.ok(true, 'sayHello called'); + return 'hello'; + } + }; + var Extended = Proto.extend(Original); + Extended = Extended.extend({ + sayHi: function () { + assert.ok(true, 'sayHi called'); + return 'hi'; + }, + sayYo: function () { + assert.ok(true, 'sayYo called'); + return 'yo'; + } + }); + + assert.strictEqual(Extended.create().sayHi(), 'hi', 'Said hi'); + assert.strictEqual(Extended.create().sayHello(), 'hello', 'Said hello'); + assert.strictEqual(Extended.create().sayYo(), 'yo', 'Said yo'); + }); + + it('mixin objects with name', function () { + var Original = { + sayHello: function () { + assert.ok(true, 'sayHello called'); + return 'hello'; + } + }; + var Mixined = Proto.mixin(Original); + Mixined = Mixined.mixin({ + sayHi: function () { + assert.ok(true, 'sayHi called'); + return 'hi'; + }, + sayYo: function () { + assert.ok(true, 'sayYo called'); + return 'yo'; + } + }, undefined, ['sayHi']); + + assert.strictEqual(Mixined.create().sayHi(), 'hi', 'Said hi'); + assert.strictEqual(Mixined.create().sayHello(), 'hello', 'Said hello'); + assert.strictEqual(typeof Mixined.create().sayYo, 'undefined', 'Cannot Say yo'); + }); + + it('extends objects with names', function () { + var Original = { + sayHello: function () { + assert.ok(true, 'sayHello called'); + return 'hello'; + } + }; + var Mixined = Proto.mixin(Original); + Mixined = Mixined.mixin({ + sayHi: function () { + assert.ok(true, 'sayHi called'); + return 'hi'; + }, + sayYo: function () { + assert.ok(true, 'sayYo called'); + return 'yo'; + } + }, undefined, ['sayHi', 'sayYo']); + + assert.strictEqual(Mixined.create().sayHi(), 'hi', 'Said hi'); + assert.strictEqual(Mixined.create().sayHello(), 'hello', 'Said hello'); + assert.strictEqual(Mixined.create().sayYo(), 'yo', 'Said yo'); + }); + + it('extends objects with all', function () { + var Original = { + sayHello: function () { + assert.ok(true, 'sayHello called'); + return 'hello'; + } + }; + var Mixined = Proto.mixin(Original); + Mixined = Mixined.mixin({ + sayHi: function () { + assert.ok(true, 'sayHi called'); + return 'hi'; + }, + sayYo: function () { + assert.ok(true, 'sayYo called'); + return 'yo'; + } + }); + + assert.strictEqual(Mixined.create().sayHi(), 'hi', 'Said hi'); + assert.strictEqual(Mixined.create().sayHello(), 'hello', 'Said hello'); + assert.strictEqual(Mixined.create().sayYo(), 'yo', 'Said yo'); + }); + }); });