npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2024 – Pkg Stats / Ryan Hefner

remixin

v2.0.0

Published

Aspect-oriented, mixin library

Downloads

35

Readme

Remixin version build status

Remixin is the aspect-oriented mixin library developed and in use at SoundCloud. It is inspired by Twitter's advice.js and Joose.

For an introduction about why you'd want to use a mixin library, Angus Croll and Dan Webb from Twitter gave a good talk about the concept and Angus blogged on the subject.

Installation

Install the package via npm:

npm install remixin

And then import it:

import { Mixin } from 'remixin';

Alternatively, download a browser-ready version from the unpkg CDN:

<script src="https://unpkg.com/underscore"></script> <!-- creates window._ -->
<script src="https://unpkg.com/remixin"></script> <!-- creates window.remixin -->

(Underscore.js is a dependency and needs to be included first.)

Usage

  • Create a new mixin using mixin = new Mixin(modifiers)
  • Apply a mixin to an object, using mixin.applyTo(object)
  • Pass options to a mixin which has a custom apply method using mixin.applyTo(object, options)
  • Curry options into a mixin using curried = mixin.withOptions(options)
  • Combine mixins by using combined = new Mixin(mixin1, [mixin2, ...], modifiers)

Modifiers

When defining a mixin, there are several key words to define method modifiers:

  • before: {Object.<String,Function>}
    • defines methods to be executed before the original function. It has the same function signature (it is given the same arguments list) as the original, but can not modify the arguments passed to the original, nor change whether the function is executed.
  • after: {Object.<String,Function>}
    • The same as before, this has the same signature, but can not modify the return value of the function.
  • around: {Object.<String,Function>}
    • defines methods to be executed 'around' the original. The original function is passed as the first argument, followed by the original arguments. The modifier function may change the arguments to be passed to the original, may modify the return value, and even can decide not to execute the original. Given the power that this provides, use with care!
  • requires: {Array.<String>}
    • an array of property names which must exist on the target object (or its prototype). Basically defines an expected interface.
  • requirePrototype: {Object}
    • this prototype should be present on the target object's prototype chain. can be used to specify what 'class' target should be or from what prototype it should inherit from.
  • override: {Object.<String,*>}
    • properties or methods which specifically should override the values already defined on the target object.
  • defaults: {Object.<String,*>}
    • properties or methods which should be applied to the target object only if they do not already exist on that object. Properties defined in the prototype chain will be overridden.
  • merge: {Object.<String,Array|Object|String}
    • a map of objects, arrays or strings to apply to the target object, merging with existing properties if they already exist. The merge strategy used depends on the data type used in the mixin:
      • Arrays are concatenated, ensuring uniqueness.
      • Objects are extended without replacing existing keys. That is, it uses _.extend({}, mixin.obj, target.obj).
      • Strings are treated like space-separated token lists: concatenated, ensuring uniqueness.

All other keys are copied onto the target object unless that key already exists. If overriding these keys is desired, then it should be defined in the override block. If a default implementation is desired, then it should be defined in the defaults block.

Incorrect use of these modifiers will throw an error if Mixin.debug is set to true. For example, if a field declared in requires is not found, or if a before is applied on a non-function. By default, Mixin.debug is false.

Custom applyTo

If custom code is required for your mixin, then defining a key named applyTo allows a custom method to be executed when the mixin is applied. This method is passed two arguments: the target object and any options defined by the calling code:

zoomable = new Mixin({
 applyTo(obj, options) {
   this.extend(obj, {
     zoom() {
       this.width *= options.zoomRatio;
       this.height *= options.zoomRatio;
     }
   });
 }
});

zoomable.applyTo(MyCanvasObject.prototype, { zoomRatio: 2 });

All of the standard modifier names (eg: after, around, before) are available in the context, as well as extend to add new properties.

Currying options

Taking the example from above, sometimes it's more convenient to have the options curried into the mixin already. For this, use .withOptions which will return a new mixin with those options stored. For example:

var standardDPI = zoomable.withOptions({ zoomRatio: 1});
var highDPI = zoomable.withOptions({ zoomRatio: 2 });

Combining mixins

Sometimes, one mixin will necessitate the target object also having another mixin. For example, you might have a mixin which gives a View the behaviour of a drop-down menu. Drop-down menus have some shared behaviour with other overlays, such as modal dialogues. These can be combined into a single mixin, to hide the implementation from the class which requires the combined behaviour:

overlay = new Mixin({
  merge: {
    events: {
      'click .closeButton': 'onCloseClick'
    }
  },
  show() { ... },
  hide() { ... },
  onCloseClick() {
    this.hide();
  }
});

dropDownMenu = new Mixin(overlay, {
  after: {
    onCloseClick() {
      this.parentButton.focus();
    }
  }
});

ProfileButton = View.extend({ ... });
dropDownMenu.applyTo(ProfileButton.prototype);

Any number of mixins can be combined into one:

megaMixin = new Mixin(mixin1, mixin2, mixin3, mixin4, {});

Development

To build the source:

make

To run the tests:

make test

To see a coverage report:

make coverage