Giter Site home page Giter Site logo

untool / mixinable Goto Github PK

View Code? Open in Web Editor NEW
5.0 2.0 2.0 1.69 MB

A functional JavaScript mixin library that is at the core of untool's core. Supports synchronous and asynchronous mixin method implementations.

Home Page: https://www.npmjs.com/package/mixinable

License: MIT License

JavaScript 100.00%
mixins roles traits delegation composition framework

mixinable's Introduction

mixinable

travis npm

mixinable is a small functional utility library allowing you to use mixins in your code. More specifically, it allows you to create mixin containers that apply mixin method application strategies to mixin method implementations.

Mixins are usually classes that can easily be shared, modified and extended using standard language features. mixinable supports asynchronous methods returning Promises.

Installation

Using NPM:

npm install -S mixinable

Using Yarn:

yarn add mixinable

To be able to use mixinable, you will have to make sure your environment supports Promise: if, for example, you need to support IE11, you will have to polyfill Promise.

API

define(definition, mixins)

The main export of mixinable is a define() function accepting a mixin container definition and an array of mixins, i.e. classes. The definition hash is made up of strategy functions prescribing how to handle different mixin methods you provide. It returns a create() function that accepts whatever arguments your mixins' constructor()s accept.

Example
import define from 'mixinable';

const create = define(
  {
    // mixin strategy function
    bar(functions, arg) {
      return functions.pop()(arg);
    },
  },
  [
    // mixin implementation
    class {
      bar(arg) {
        console.log(arg);
      },
    }
  ]
);

const foo = create();

foo.bar('yeah!');
// yeah!

Speaking of which: mixinable creates a separate hidden mixin instance for every mixin you provide. When used inside a mixin method, this refers to this hidden instance.

Mixin methods not included in your definition are only accessible from within the mixin instance itself, but not from the outside.

Example
import define from 'mixinable';

const create = define(
  {
    bar(functions, arg) {
      return functions.pop()(arg);
    },
  },
  [
    // mixin implementations
    class {
      // public mixin method
      bar(arg) {
        this.qux(arg);
      },
      // private mixin method
      qux(arg) {
        console.log(arg);
      },
    }
  ]
);

const foo = create();

foo.bar('yeah!');
// yeah!

console.log(typeof foo.bar, typeof foo.qux);
// function undefined

Mixin definitions can be (or contain) custom constructors. These functions are being passed the create() function's arguments upon creation.

Example
import define from 'mixinable';

const create = define({}, [
  // mixin contructors
  class {
    constructor(arg) {
      console.log(arg);
    }
  },
]);

create('yee-hah!');
// yee-hah!

define.override

override is a helper implementating a mixin strategy that resembles classical inherintance (class ... extends): it simply calls the last method implementation.

Example
import define, { override } from 'mixinable';

const create = define({
  // mixin strategy function
  bar: override,
}, [
  // mixin implementations
  class {
    bar() {
      console.log(1);
    }
  },
  class {
    bar() {
      console.log(2);
    }
  },
]);

const foo = create();

foo.bar();
// 2

override returns a Promise if one of its implementations does. If you want it to always return a Promise, i.e. if you can not be sure whether one of your implementations might return one, please use define.async.override.

override is aliased to callable in all places, enabling implementers to communicate their intentions more clearly: override is often used to provide callable (utility) methods.

define.parallel

parallel is a helper implementating a mixin strategy that executes all defined implementations in parallel. This is probably most useful if asynchronous implementations are involved.

Example
import define, { parallel } from 'mixinable';

const create = define({
  // mixin strategy function
  bar: parallel,
}, [
  // mixin implementations
  class {
    bar(val, inc) {
      return val + inc;
    }
  },
  class {
    bar(val, inc) {
      return val + inc;
    }
  },
]);

const foo = create();

foo.bar(0, 1).then(res => console.log(res));
// [1, 1]

parallel returns a Promise if one of its implementations does. If you want it to always return a Promise, i.e. if you can not be sure whether one of your implementations might return one, please use define.async.parallel.

If you want to make sure parallel never returns a Promise, please use it as define.sync.parallel - or, better yet, use it as define.sync.sequence, for that is technically correct.

define.pipe

pipe is a helper implementating a strategy that passes each implementation's output to the next, using the first argument as the initial value. All other arguments are being passed to all implementations as-is.

Example
import define, { pipe } from 'mixinable';

const create = define({
  // mixin strategy function
  bar: pipe,
}, [
  // mixin implementations
  class {
    bar(val, inc) {
      return val + inc;
    }
  },
  class {
    bar(val, inc) {
      return val + inc;
    }
  },
]);

const foo = create();

foo.bar(0, 1).then(res => console.log(res));
// 2

pipe returns a Promise if one of its implementations does. If you want it to always return a Promise, i.e. if you can not be sure whether one of your implementations might return one, please use define.async.pipe.

define.compose

compose works essentially identically as pipe, but in reverse order: the very last implementation receives the initial value and the first implementation returns the final output.

Example
import define, { compose } from 'mixinable';

const mixin = define({
  // mixin strategy function
  bar: compose,
}, [
  // mixin implementations
  // ...
]);

compose returns a Promise if one of its implementations does. If you want it to always return a Promise, i.e. if you can not be sure whether one of your implementations might return one, please use define.async.compose.

Custom Strategies

You can supply your own mixin strategies: such strategies are plain functions that receive the defined implementations as their first argument. The following example shows a naïve re-implementation of the override strategy.

Example
import define from 'mixinable';

const mixin = define({
  // mixin strategy function
  bar(functions, ...args) {
    functions.pop().apply(null, args);
  },
}, [
  // mixin implementation
  class {
    bar(arg) {
      console.log(arg);
    },
  },
]);

const foo = create();

foo.bar(1);
// 1

Utilities

define.async

All of the strategies described above return a Promise if one of their implementations does. If you want them to always return a Promise please use define.async.{override/callable,parallel,pipe,compose}.

define.sync

If you want to make sure one of the strategies never returns a Promise please use define.sync.{override/callable,parallel/sequence,pipe,compose}. If you do, an Error will be thrown if a Promise is returned.

Contributing

If you want to contribute to this project, create a fork of its repository using the GitHub UI. Check out your new fork to your computer:

mkdir mixinable && cd $_
git clone [email protected]:user/mixinable.git

Afterwards, you can yarn install the required dev dependencies and start hacking away. When you are finished, please do go ahead and create a pull request.

mixinable itself is (almost) entirely written in ECMAScript 5 and adheres to semistandard code style. Please make sure your contribution does, too.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.