Skip to content

Instantly share code, notes, and snippets.

@unbug
Last active January 6, 2024 04:17
Show Gist options
  • Save unbug/dd596d79b5eace7d245f0a4db6cd2be5 to your computer and use it in GitHub Desktop.
Save unbug/dd596d79b5eace7d245f0a4db6cd2be5 to your computer and use it in GitHub Desktop.

Revisions

  1. unbug revised this gist Apr 13, 2017. No changes.
  2. unbug revised this gist Feb 3, 2017. 1 changed file with 4 additions and 4 deletions.
    8 changes: 4 additions & 4 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,7 @@ export function compose(...funcs) {
    }

    /**
    * Manage and apply middleweares for an object.
    * Manage and apply middlewares for an object.
    * Middleware functions are functions that have access to the target function and it's arguments,
    * and the target object and the next middleware function in the target function cycle.
    * The next middleware function is commonly denoted by a variable named next.
    @@ -133,11 +133,11 @@ export function compose(...funcs) {
    * p.speak('hi');
    *
    * ## middlewareMethods
    * Or we can use `middlewareMethods` to define function names for middleweare target within a class.
    * Or we can use `middlewareMethods` to define function names for middleware target within a class.
    *
    * class CuePointMiddleware {
    * constructor() {
    * //Define function names for middleweare target.
    * //Define function names for middleware target.
    * this.middlewareMethods = ['walk', 'speak'];
    * }
    * log(text) {
    @@ -217,7 +217,7 @@ export class MiddlewareManager {
    use(methodName, ...middlewares) {
    if (typeof methodName === 'object') {
    Array.prototype.slice.call(arguments).forEach(arg => {
    // A middleweare object can specify targer functions within middlewareMethods (Array).
    // A middleware object can specify target functions within middlewareMethods (Array).
    // e.g. obj.middlewareMethods = ['method1', 'method2'];
    // only method1 and method2 will be the target function.
    typeof arg === 'object' && (arg.middlewareMethods || Object.keys(arg)).forEach(key => {
  3. unbug revised this gist Jan 6, 2017. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Middleware.js
    Original file line number Diff line number Diff line change
    @@ -221,7 +221,7 @@ export class MiddlewareManager {
    // e.g. obj.middlewareMethods = ['method1', 'method2'];
    // only method1 and method2 will be the target function.
    typeof arg === 'object' && (arg.middlewareMethods || Object.keys(arg)).forEach(key => {
    this._applyToMethod(key, arg[key].bind(arg));
    typeof arg[key] === 'function' && this._applyToMethod(key, arg[key].bind(arg));
    });
    });
    } else {
  4. unbug revised this gist Dec 27, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -30,7 +30,7 @@ export function compose(...funcs) {
    }

    /**
    * Manage and apply middleweare to an object.
    * Manage and apply middleweares for an object.
    * Middleware functions are functions that have access to the target function and it's arguments,
    * and the target object and the next middleware function in the target function cycle.
    * The next middleware function is commonly denoted by a variable named next.
    @@ -207,7 +207,7 @@ export class MiddlewareManager {
    }

    /**
    * Apply middleware to the target object.
    * Apply (register) middleware functions to the target function or apply (register) middleware objects.
    * If the first argument is a middleware object, the rest arguments must be middleware objects.
    *
    * @param {string|object} methodName String for target function name, object for a middleware object.
  5. unbug revised this gist Dec 27, 2016. No changes.
  6. unbug revised this gist Dec 27, 2016. 1 changed file with 13 additions and 13 deletions.
    26 changes: 13 additions & 13 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -1,7 +1,7 @@
    'use strict';
    /* eslint-disable consistent-this */

    let applyMiddlewareHash = [];
    let middlewareManagerHash = [];

    /**
    * Composes single-argument functions from right to left. The rightmost
    @@ -30,7 +30,7 @@ export function compose(...funcs) {
    }

    /**
    * Apply middleweare to an object.
    * Manage and apply middleweare to an object.
    * Middleware functions are functions that have access to the target function and it's arguments,
    * and the target object and the next middleware function in the target function cycle.
    * The next middleware function is commonly denoted by a variable named next.
    @@ -102,8 +102,8 @@ export function compose(...funcs) {
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use('walk', walk);
    * const middlewareManager = new MiddlewareManager(p);
    * middlewareManager.use('walk', walk);
    * p.walk(3);
    *
    * Whenever a Person instance call it's walk method, we'll see logs from the looger middleware.
    @@ -127,8 +127,8 @@ export function compose(...funcs) {
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use(PersonMiddleware);
    * const middlewareManager = new MiddlewareManager(p);
    * middlewareManager.use(PersonMiddleware);
    * p.walk(3);
    * p.speak('hi');
    *
    @@ -161,28 +161,28 @@ export function compose(...funcs) {
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use(new PersonMiddleware())
    * const middlewareManager = new MiddlewareManager(p);
    * middlewareManager.use(new PersonMiddleware())
    * p.walk(3);
    * p.speak('hi');
    *
    */
    export class ApplyMiddleware {
    export class MiddlewareManager {
    /**
    * @param {object} target The target object.
    * @param {...object} middlewareObjects Middleware objects.
    * @return {object} this
    */
    constructor(target, ...middlewareObjects) {
    let instance = applyMiddlewareHash.find(function (key) {
    let instance = middlewareManagerHash.find(function (key) {
    return key._target === target;
    });
    // a target can only has one ApplyMiddleware instance
    // a target can only has one MiddlewareManager instance
    if (instance === undefined) {
    this._target = target;
    this._methods = {};
    this._methodMiddlewares = {};
    applyMiddlewareHash.push(this);
    middlewareManagerHash.push(this);
    instance = this;
    }
    instance.use(...middlewareObjects);
    @@ -230,4 +230,4 @@ export class ApplyMiddleware {

    return this;
    }
    }
    }
  7. unbug revised this gist Dec 23, 2016. 1 changed file with 8 additions and 6 deletions.
    14 changes: 8 additions & 6 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -113,13 +113,13 @@ export function compose(...funcs) {
    * Middleware object is an object that contains function's name as same as the target object's function name.
    *
    * const PersonMiddleware {
    * walk: target => next => (step) => {
    * walk: target => next => step => {
    * console.log(`walk start, steps: step.`);
    * const result = next(step);
    * console.log(`walk end.`);
    * return result;
    * },
    * speak: target => next => (word) => {
    * speak: target => next => word => {
    * word = 'this is a middleware trying to say: ' + word;
    * return next(word);
    * }
    @@ -144,15 +144,15 @@ export function compose(...funcs) {
    * console.log('Middleware log: ' + text);
    * }
    * walk(target) {
    * return next => (step) => {
    * return next => step => {
    * this.log(`walk start, steps: step.`);
    * const result = next(step);
    * this.log(`walk end.`);
    * return result;
    * }
    * }
    * speak(target) {
    * return next => (word) => {
    * return next => word => {
    * this.log('this is a middleware tring to say: ' + word);
    * return next(word);
    * }
    @@ -208,8 +208,10 @@ export class ApplyMiddleware {

    /**
    * Apply middleware to the target object.
    * @param {string|object} methodName String for target function name, object
    * @param {...function} middlewares The middleware chain to be applied.
    * If the first argument is a middleware object, the rest arguments must be middleware objects.
    *
    * @param {string|object} methodName String for target function name, object for a middleware object.
    * @param {...function|...object} middlewares The middleware chain to be applied.
    * @return {object} this
    */
    use(methodName, ...middlewares) {
  8. unbug revised this gist Dec 22, 2016. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -1,4 +1,5 @@
    'use strict';
    /* eslint-disable consistent-this */

    let applyMiddlewareHash = [];

    @@ -173,7 +174,6 @@ export class ApplyMiddleware {
    * @return {object} this
    */
    constructor(target, ...middlewareObjects) {
    const that = this;
    let instance = applyMiddlewareHash.find(function (key) {
    return key._target === target;
    });
    @@ -183,7 +183,7 @@ export class ApplyMiddleware {
    this._methods = {};
    this._methodMiddlewares = {};
    applyMiddlewareHash.push(this);
    instance = that;
    instance = this;
    }
    instance.use(...middlewareObjects);

    @@ -228,4 +228,4 @@ export class ApplyMiddleware {

    return this;
    }
    }
    }
  9. unbug revised this gist Dec 21, 2016. 1 changed file with 82 additions and 11 deletions.
    93 changes: 82 additions & 11 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -72,27 +72,98 @@ export function compose(...funcs) {
    *
    * @example
    *
    * ## Basic
    *
    * We define a Person class.
    * // the target object
    * class Person {
    * // the target function
    * walk(step) {
    * this.step = step;
    * }
    * // the target function
    * walk(step) {
    * this.step = step;
    * }
    *
    * speak(word) {
    * this.word = word;
    * }
    * }
    *
    * Then we define a middleware function to print log.
    *
    * // middleware for walk function
    * const logger = target => next => (...args) => {
    * console.log(`walk start, steps: ${args[0]}.`);
    * const result = next(...args);
    * console.log(`walk end.`);
    * return result;
    * }
    * console.log(`walk start, steps: ${args[0]}.`);
    * const result = next(...args);
    * console.log(`walk end.`);
    * return result;
    * }
    *
    * Now we apply the log function as a middleware to a Person instance.
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use('walk', walk);
    * p.walk();
    * p.walk(3);
    *
    * Whenever a Person instance call it's walk method, we'll see logs from the looger middleware.
    *
    * ## Middleware object
    * We can also apply a middleware object to a target object.
    * Middleware object is an object that contains function's name as same as the target object's function name.
    *
    * const PersonMiddleware {
    * walk: target => next => (step) => {
    * console.log(`walk start, steps: step.`);
    * const result = next(step);
    * console.log(`walk end.`);
    * return result;
    * },
    * speak: target => next => (word) => {
    * word = 'this is a middleware trying to say: ' + word;
    * return next(word);
    * }
    * }
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use(PersonMiddleware);
    * p.walk(3);
    * p.speak('hi');
    *
    * ## middlewareMethods
    * Or we can use `middlewareMethods` to define function names for middleweare target within a class.
    *
    * class CuePointMiddleware {
    * constructor() {
    * //Define function names for middleweare target.
    * this.middlewareMethods = ['walk', 'speak'];
    * }
    * log(text) {
    * console.log('Middleware log: ' + text);
    * }
    * walk(target) {
    * return next => (step) => {
    * this.log(`walk start, steps: step.`);
    * const result = next(step);
    * this.log(`walk end.`);
    * return result;
    * }
    * }
    * speak(target) {
    * return next => (word) => {
    * this.log('this is a middleware tring to say: ' + word);
    * return next(word);
    * }
    * }
    * }
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use(new PersonMiddleware())
    * p.walk(3);
    * p.speak('hi');
    *
    */
    export class ApplyMiddleware {
    @@ -157,4 +228,4 @@ export class ApplyMiddleware {

    return this;
    }
    }
    }
  10. unbug revised this gist Dec 21, 2016. 1 changed file with 3 additions and 3 deletions.
    6 changes: 3 additions & 3 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -82,9 +82,9 @@ export function compose(...funcs) {
    *
    * // middleware for walk function
    * const logger = target => next => (...args) => {
    * this.log(`walk start, steps: ${args[0]}.`);
    * console.log(`walk start, steps: ${args[0]}.`);
    * const result = next(...args);
    * this.log(`walk end.`);
    * console.log(`walk end.`);
    * return result;
    * }
    *
    @@ -157,4 +157,4 @@ export class ApplyMiddleware {

    return this;
    }
    }
    }
  11. unbug revised this gist Dec 21, 2016. 1 changed file with 16 additions and 9 deletions.
    25 changes: 16 additions & 9 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -1,5 +1,7 @@
    'use strict';

    let applyMiddlewareHash = [];

    /**
    * Composes single-argument functions from right to left. The rightmost
    * function can take multiple arguments as it provides the signature for
    @@ -26,8 +28,6 @@ export function compose(...funcs) {
    return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));
    }

    let targetsCache = [];

    /**
    * Apply middleweare to an object.
    * Middleware functions are functions that have access to the target function and it's arguments,
    @@ -102,13 +102,20 @@ export class ApplyMiddleware {
    * @return {object} this
    */
    constructor(target, ...middlewareObjects) {
    let instance = targetsCache.find(function (key) {
    return key === target;
    }) || this;
    instance._target = instance._target || target;
    instance._methods = instance._methods || {};
    instance._methodMiddlewares = instance._methodMiddlewares || {};
    const that = this;
    let instance = applyMiddlewareHash.find(function (key) {
    return key._target === target;
    });
    // a target can only has one ApplyMiddleware instance
    if (instance === undefined) {
    this._target = target;
    this._methods = {};
    this._methodMiddlewares = {};
    applyMiddlewareHash.push(this);
    instance = that;
    }
    instance.use(...middlewareObjects);

    return instance;
    }

    @@ -150,4 +157,4 @@ export class ApplyMiddleware {

    return this;
    }
    }
    }
  12. unbug revised this gist Dec 19, 2016. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion Middleware.js
    Original file line number Diff line number Diff line change
    @@ -141,7 +141,7 @@ export class ApplyMiddleware {
    // e.g. obj.middlewareMethods = ['method1', 'method2'];
    // only method1 and method2 will be the target function.
    typeof arg === 'object' && (arg.middlewareMethods || Object.keys(arg)).forEach(key => {
    this._applyToMethod(key, arg[key]);
    this._applyToMethod(key, arg[key].bind(arg));
    });
    });
    } else {
  13. unbug revised this gist Dec 19, 2016. 1 changed file with 14 additions and 5 deletions.
    19 changes: 14 additions & 5 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -26,6 +26,8 @@ export function compose(...funcs) {
    return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));
    }

    let targetsCache = [];

    /**
    * Apply middleweare to an object.
    * Middleware functions are functions that have access to the target function and it's arguments,
    @@ -100,10 +102,14 @@ export class ApplyMiddleware {
    * @return {object} this
    */
    constructor(target, ...middlewareObjects) {
    this._target = target;
    this._methods = {};
    this._methodMiddlewares = {};
    this.use(...middlewareObjects);
    let instance = targetsCache.find(function (key) {
    return key === target;
    }) || this;
    instance._target = instance._target || target;
    instance._methods = instance._methods || {};
    instance._methodMiddlewares = instance._methodMiddlewares || {};
    instance.use(...middlewareObjects);
    return instance;
    }

    _applyToMethod(methodName, ...middlewares) {
    @@ -131,7 +137,10 @@ export class ApplyMiddleware {
    use(methodName, ...middlewares) {
    if (typeof methodName === 'object') {
    Array.prototype.slice.call(arguments).forEach(arg => {
    typeof arg === 'object' && Object.keys(arg).forEach(key => {
    // A middleweare object can specify targer functions within middlewareMethods (Array).
    // e.g. obj.middlewareMethods = ['method1', 'method2'];
    // only method1 and method2 will be the target function.
    typeof arg === 'object' && (arg.middlewareMethods || Object.keys(arg)).forEach(key => {
    this._applyToMethod(key, arg[key]);
    });
    });
  14. unbug revised this gist Dec 5, 2016. 1 changed file with 2 additions and 2 deletions.
    4 changes: 2 additions & 2 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -10,7 +10,7 @@
    * from right to left. For example, compose(f, g, h) is identical to doing
    * (...args) => f(g(h(...args))).
    */
    export function Compose(...funcs) {
    export function compose(...funcs) {
    if (funcs.length === 0) {
    return arg => arg;
    }
    @@ -117,7 +117,7 @@ export class ApplyMiddleware {
    middlewares.forEach(middleware =>
    typeof middleware === 'function' && this._methodMiddlewares[methodName].push(middleware(this._target))
    );
    this._target[methodName] = Compose(...this._methodMiddlewares[methodName])(method.bind(this._target));
    this._target[methodName] = compose(...this._methodMiddlewares[methodName])(method.bind(this._target));
    }
    }
    }
  15. unbug revised this gist Dec 5, 2016. No changes.
  16. unbug revised this gist Dec 5, 2016. No changes.
  17. unbug created this gist Dec 5, 2016.
    144 changes: 144 additions & 0 deletions Middleware.js
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,144 @@
    'use strict';

    /**
    * Composes single-argument functions from right to left. The rightmost
    * function can take multiple arguments as it provides the signature for
    * the resulting composite function.
    *
    * @param {...Function} funcs The functions to compose.
    * @returns {Function} A function obtained by composing the argument functions
    * from right to left. For example, compose(f, g, h) is identical to doing
    * (...args) => f(g(h(...args))).
    */
    export function Compose(...funcs) {
    if (funcs.length === 0) {
    return arg => arg;
    }

    funcs = funcs.filter(func => typeof func === 'function');

    if (funcs.length === 1) {
    return funcs[0];
    }

    const last = funcs[funcs.length - 1];
    const rest = funcs.slice(0, -1);
    return (...args) => rest.reduceRight((composed, f) => f(composed), last(...args));
    }

    /**
    * Apply middleweare to an object.
    * Middleware functions are functions that have access to the target function and it's arguments,
    * and the target object and the next middleware function in the target function cycle.
    * The next middleware function is commonly denoted by a variable named next.
    *
    * Middleware functions can perform the following tasks:
    * - Execute any code.
    * - Make changes to the function's arguments.
    * - End the target function.
    * - Call the next middleware in the stack.
    *
    * If the current middleware function does not end the target function cycle,
    * it must call next() to pass control to the next middleware function. Otherwise,
    * the target function will be left hanging.
    *
    * e.g.
    * ```
    * const walk = target => next => (...args) => {
    * this.log(`walk function start.`);
    * const result = next(...args);
    * this.log(`walk function end.`);
    * return result;
    * }
    * ```
    *
    * Middleware object is an object that contains function's name as same as the target object's function name.
    *
    * e.g.
    * ```
    * const Logger = {
    * walk: target => next => (...args) => {
    * console.log(`walk function start.`);
    * const result = next(...args);
    * console.log(`walk function end.`);
    * return result;
    * }
    * }
    * ```
    *
    * Function's name start or end with "_" will not be able to apply middleware.
    *
    * @example
    *
    * // the target object
    * class Person {
    * // the target function
    * walk(step) {
    * this.step = step;
    * }
    * }
    *
    * // middleware for walk function
    * const logger = target => next => (...args) => {
    * this.log(`walk start, steps: ${args[0]}.`);
    * const result = next(...args);
    * this.log(`walk end.`);
    * return result;
    * }
    *
    * // apply middleware to target object
    * const p = new Person();
    * const applyMiddleware = new ApplyMiddleware(p);
    * applyMiddleware.use('walk', walk);
    * p.walk();
    *
    */
    export class ApplyMiddleware {
    /**
    * @param {object} target The target object.
    * @param {...object} middlewareObjects Middleware objects.
    * @return {object} this
    */
    constructor(target, ...middlewareObjects) {
    this._target = target;
    this._methods = {};
    this._methodMiddlewares = {};
    this.use(...middlewareObjects);
    }

    _applyToMethod(methodName, ...middlewares) {
    if (typeof methodName === 'string' && !/^_+|_+$/g.test(methodName)) {
    let method = this._methods[methodName] || this._target[methodName];
    if (typeof method === 'function') {
    this._methods[methodName] = method;
    if (this._methodMiddlewares[methodName] === undefined) {
    this._methodMiddlewares[methodName] = [];
    }
    middlewares.forEach(middleware =>
    typeof middleware === 'function' && this._methodMiddlewares[methodName].push(middleware(this._target))
    );
    this._target[methodName] = Compose(...this._methodMiddlewares[methodName])(method.bind(this._target));
    }
    }
    }

    /**
    * Apply middleware to the target object.
    * @param {string|object} methodName String for target function name, object
    * @param {...function} middlewares The middleware chain to be applied.
    * @return {object} this
    */
    use(methodName, ...middlewares) {
    if (typeof methodName === 'object') {
    Array.prototype.slice.call(arguments).forEach(arg => {
    typeof arg === 'object' && Object.keys(arg).forEach(key => {
    this._applyToMethod(key, arg[key]);
    });
    });
    } else {
    this._applyToMethod(methodName, ...middlewares);
    }

    return this;
    }
    }