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

keylime

v1.0.0

Published

A delicious way to work with prototypes in JavaScript.

Downloads

5

Readme

Keylime

A delicious way to work with prototypes in JavaScript.

Keylime is small library for working with prototype objects in JavaScript. It provides some syntax sugar for defining your prototype's properties & methods, and APIs for sharing behavior between your prototypes through mixins.

// Keylime lets you turn this:
function Jedi(options) {
  this.name = options.name;
  this.side = options.side || 'light';
  this.powers = option.powers || ['push', 'jump'];
  this.createdAt = options.createdAt || Date.now();
}
Jedi.prototype.meditate = function meditate() {
  return this.name + ' is meditating...';
}

// ... into this:
var Jedi = keylime('Jedi')
  .attr('name')
  .attr('side', 'light')
  .attr('powers', ['push', 'jump']);
  .attr('createdAt', Date.now)
  .method('meditate', function meditate() {
    return this.name + ' is meditating...';
  });

Features

  • Declarative, chainable syntax.
  • Easily define attributes and methods.
  • Create mixins to share behaviour between your objects.
  • Use extensions to customize Keylime's syntax.
  • Great browser support (IE8 and up).
  • Leightweight (~9kb minified). Zero dependencies.

Download

Using in the browser:

Using npm:

npm install --save keylime

Using bower:

bower install --save keylime

Installation

In the browser:

<script src="keylime.min.js"></script>

In Node:

var keylime = require('keylime');

Using AMD/Require:

require([keylime], function(keylime) {
  // ...
});

Creating a constructor

The top-level Keylime function generates new constructor functions. These functions not only create new instances for you, but also have special functions that allow you to define how the function should behave.

var Jedi = keylime('Jedi');

All the following API examples use Jedi to refer to a keylime constructor.

Defining attributes

Keylime allows you to define "attributes" that every instance of the constructor should have, with optional default values.

// no default value
Jedi.attr('name');

// default value
Jedi.attr('side', 'light');

Dynamic default values

You can use functions to calculate default values at time of creation:

Jedi.attr('createdAt', function() {
  return Date.now();
});

// or for short:
Jedi.attr('createdAt', Date.now);

Arrays/Objects as default values

If you set an array or object as the default value, it will be copied to every instance, not shared:

Jedi.attr('powers', ['push', 'jump']);

var obi = new Jedi();
var mace = new Jedi();

obi.powers.push('mind trick');    //=> ['push', 'jump', 'mind trick']
mace.powers;                      //=> ['push', 'jump']

Creating instances

You can create instances of your objects using the either new keyword, or you can call the .create() function.

new Jedi();

// or

Jedi.create();

Setting attributes during creation

Attributes can be passed in an object as the first parameter during creation. Properties that are not attributes will be filtered out during creation:

var yoda = Jedi({
  name: 'yoda',
  invalidAttr: 10
});

yoda.name;        //=> 'yoda'
yoda.invalidAttr; //=> undefined

Defining Methods

You can define methods on objects, and Keylime will put these methods on the prototype chain for you. Inside the function body, this refers to the instance, like usual.

Jedi.method('meditate', function meditate() {
  return this.name + ' is meditating...';
});

var anakin = new Jedi({
  name: 'anakin'
});

anakin.meditate(); //=> anakin is meditating...

Mixins

Mixins allow you to abstract shared or complex logic into re-usable modules. Think of mixins similarly to middlewhere. A mixin is a function that receives the constructor it was included in, and allows you to modify the constructor.

For example, you could create a mixin that defines how HP is managed in characters on a game.

function hp(model, maxHealth, minHealth) {
  model
    .attr('health', maxHealth)

    .method('receiveHeal', function receiveHeal(amount) {
      var newHealth = this.health + amount;
      this.health = (newHealth > maxHealth) ? maxHealth : newHealth;
      return this.health;
    })

    .method('isAlive', function isAlive() {
      return this.health <= minHealth;
    })

    .method('receiveDamage', function receiveDamage(amount) {
      var newHealth = this.health - amount;
      this.health = (newHealth < minHealth) ? minHealth : newHealth;
      return this.health;
    });
}

var Jedi = keylime('Jedi')
  .include(hp, 0, 100)
  .attr('name');

var yoda = new Jedi({
  health: 50
});

yoda.health;              //=> 50
yoda.receiveDamage(80);   //=> 0
yoda.isAlive();           //=> false

Mixins instead of inheritance

Keylime does not provide any APIs for inheriting other constructors. Instead, Keylime encourages abstraction through the use of mixins.

For example, instead of creating a base Character constructor that defines how healthpoints and damage are managed, create a healthpoint mixin, and include that in your constructors.

Mixins can be used to wrap other libraries, create database adapters, etc.

Extending Keylime

Keylime allows you to extend the syntax with your own functionality. A Keylime extension looks identical to a mixin.

Extensions are useful for wrapping other libraries, or providing new ways to describe constructor functionality. For example, here is an extension wrapping validate.js:

keylime.registerExtension('validate', function validate(model, constraints) {
  model.constraints = constraints;

  model
    .method('validate', function validate() {
      return validatejs(this, model.constraints);
    })
    .method('isValid', function isValid() {
      return this.validate() === undefined;
    });
});

var Jedi = keylime('Jedi')
  .validate({
    name: {
      presence: true
    }
  })
  .attr('name');

var yoda = new Jedi();

yoda.isValid();      //=> false
yoda.name = 'Yoda';
yoda.isValid();      //=> true

Hooking into object creation

Keylime allows you to hook into object creating through handler functions, similary to handling events in jQuery.

Unlike event handlers however, these functions are not asyncrounous. Keylime will wait for all of your handlers to finish before returning the new instance. This allows you modify the instance before the its sent back to the caller.

Jedi.on('init', function(instance) {
  // instance with attributes already set
});

Modifying attributes during creation

Since Keylime waits for all handler functions to finish before returning new instances, it provides a special API you should use if you need to modify specific attributes.

This prevents you from having to loop through attributes in multiple handlers to update values.

Jedi.on('attr', 'id', function appendTime(idValue) {
  var timestamp = new Date();
  return idValue + '_' + timestamp.toISOString();
});

var yoda = new Jedi({
  id: 'yoda'
});

yoda.id; //=> 'yoda_2015-01-28T21:46:15.574Z'

Credits

Logo by the awesome @ronniecjohnson.