mixin-a-lot v4.0.11
mixin.a.lot
What is it?
A small aspect-oriented JavaScript mixin API.
Why use it?
- You can advise mixin behavior with your own functions.
- You can advise the mixing process with your own functions.
- You can opt-out of mixin data and behavior.
- It has no dependencies.
Install
$ npm i mixin-a-lotIf you want type definitions
$ tsd linkExamples
Import the module:
import {mix} from 'mixin-a-lot';Mixing
A mixin is just a plain old JavaScript object. Mix it into your object, function or prototype.
Any mixed-in functions will always be called on the target context.
class Person {
constructor(name) {
this.name = name;
}
};
let named = {
sayName() {
console.log(this.name);
}
};
// mix into a Function
mix(Person, named);
Person.sayName(); // 'Person'
// or mix into its prototype
mix(Person.prototype, named);
new Person('Victor').sayName(); // 'Victor'
// or mix into a random object
let object = {name: 'object'};
mix(object, named);
object.sayName(); // 'object'Adapters
Take
let loggerMixin = {
errLog: '/logs/app.err',
infLog: '/logs/app.log',
log: function(logEvent) {
let {didError, message} = logEvent;
if (didError) {
fs.writeFile(this.errLog, `${this.logname}:${message}`);
} else {
fs.writeFile(this.infLog, `${this.logname}:${message}`);
}
},
};as a starting point.
You can write adapters to and from mixin methods.
let logger = {
logname: 'prefix_logger'
};
let prefixMessage = function(error, message) {
let prefix;
if (!error) {
prefix = 'INFO';
} else {
prefix = 'ERROR';
if (!message) {
message = error.message;
}
}
return {didError: !!error, message: `${prefix}:${message}`};
};
mix(logger, loggerMixin, {
adapterTo: {
log: prefixMessage,
},
});
// writes 'prefix_logger:ERROR:error connecting to DB' to /logs/app.err
myLogger.log(new IOError('error connecting to DB'));
// writes 'prefix_logger:INFO:request @ /user/:id from yangmillstheory' to /logs/app.log
myLogger.log(null, `request @ /user/:id from ${user}`); Adapters are called on the target context before or after the mixin method.
An example of an post-adapter can be seen in the tests. It logs all messages written to disk to the console as well.
Adapters can be chained, to give an execution flow like
pre adapter -> mixin method -> post adapterPre and post mixing routines
Each mixin can specify pre and post mix routines. Each routine is invoked on the context with the mixin as a target.
This is a good place to run validation, finalization, or set default properties.
// shared/mixins/logger.js
let loggers = new WeakSet(); // ES6 only
let loggerMixin = {
// ...
// properties as before
// ...
// new
premix(target) {
if (typeof target.logname !== 'string') {
throw new TypeError(`Expected string logname; got ${target.logname}`);
}
},
// new
postmix(target) {
loggers.add(target);
},
};premix and postmix won't be mixed into the target.
Opting out or overriding
You want some shared data or behavior, but not all of it.
mix(mixee, {
method1() {
// ...
},
method2() {
// ...
},
foo: true,
}, {
omit: ['method1']
});
mixee.method1 // undefined
mixee.method2 // function() { ... }
mixee.foo // trueOr, you want to override some data or behavior.
let named = {
name: 'mixin',
sayName() {
console.log(this.name);
},
};
let mixee = {
name: 'mixee'
};
mix(mixee, named, {omit: ['name']});
mixee.sayName() // 'mixee'
// probably not what you want
mix(mixee, named);
mixee.sayName() // 'mixin'Tests for all these examples can be found here.
API
mix(target: Object, mixin: IMixin, options?: Object)
Mix own properties from mixin into target. options can be an object literal with
omit: array of strings which are property names ofmixinto exclude from mixingadapterTo: object literal mapping mixin method names to adapters to themadapterFrom: object literal mapping mixin method names to adapters from them
mixin can have two special properties
premix: function called onmixinbefore mixing (but aftermixis called) withtargetas the argumentpostmix: function called onmixinafter mixing (but beforemixreturns) withtargetas the argument
These properties will not be copied into target.
Development
Development is in snake_case TypeScript.
Get the source:
$ git clone git@github.com:username/mixin.a.lot.gitInstall dependencies:
$ cd mixin.a.lot && sudo npm iDevelop (watch for changes and execute tests):
$ ./node_modules/.bin/gulp devTo see all the available tasks:
$ ./node_modules/.bin/gulp -TLicense
MIT © 2016, Victor Alvarez
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago