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

spritzr

v0.1.1

Published

Provides an inheritance/traits/talents library

Downloads

11

Readme

Spritzr

Build Status

About spritzr

Spritzr is an inheritance/traits/talents library for node.js and the browser.

It aims to provide three things:

  • Extension: to do classical single inheritance
  • Traits: mixins at a class level and with state (a bit like multiple inheritance)
  • Talents: like traits, but applied to a single instance (and they can also be removed at will)

Spritzr was inspired by a great traits/talents library CocktailJS https://github.com/CocktailJS/cocktail.

Compatibility

Spritzr is automatically unit tested against the following browsers:

  • Internet Explorer 6, 7, 8, 9, 10 and 11
  • Firefox latest and 3.6 versions
  • Chrome latest version
  • Safari desktop latest version
  • Opera desktop latest version
  • Android 2.3 and 4.2
  • iOS 7

It is also tested on node.js version 0.10 and PhantomJS (headless webkit).


Special thanks to BrowserStack for providing a free account to run our automated tests on all these different browsers and operating systems!


API

Inheritance

Spritzr has an extend function which implements a basic single inheritance model.

The prototype chain is maintained so that instanceof works as expected.

function Animal(type) {
	this.type = type;
};
Animal.prototype.type = null;

Animal.prototype.greet = function() {
	return "Hi, I'm a " + this.type + " called " + this.name;
};

// We need to explicitly call the super constructor using a handy $super property.
function Person(name) {
	this.$super("person");
	this.name = name;
};
Person.prototype.name = null;

Spritzr.extend(Person, Animal);

var steve = new Person("Steve");

expect(steve.greet()).toBe("Hi, I'm a person called Steve");
expect(steve instanceof Person).toBe(true);
expect(steve instanceof Animal).toBe(true);

// Spritzr also provides an isa() function which acts like instanceof
expect(Spritzr.isa(steve, Animal)).toBe(true);

// We can also override methods and properties of the super class
// but still access them using $super
var Tony = function Tony() {
	this.$super("Tony");
};
Spritzr.extend(Tony, Person);

Tony.prototype.greet = function() {
	var normalGreeting = this.$super.greet();
	
	return normalGreeting + ", y'all!";
};

var tony = new Tony();
expect(tony.greet()).toBe("Hi, I'm a person called Tony, y'all!");

Gotchas

Super constructor not explicitly called

When extending a class, the super class constructor will not be implicitly called when the sub class is instantiated. Therefor you should call the $super() constructor from within the subclass constructor; for example:

var Animal = function() {
	// Set up animaly stuff
};

var Mammal = function() {
	this.$super();	// Call the Animal() constructor
	// Set up mammalian stuff like live babies and stuff.
};

Spritzr.extend(Mammal, Animal);
Scope fudging when calling a super class method

When you call a super class method using this.$super.method() then the scope gets lost somewhere along the way, which means that this within the super method is not pointing to the correct object. There are two ways around this:

  1. Ensure you always call this.$super() from within the constructor. This has access to the real object and will cache it for later within the $super object. You can then just call this.$super.method() to call the super class method.
  2. Pass in othe correct scope when you call the method by using this.$super.method.call(this, arg1, arg2 ... ).

Traits

Classes can be extended with multiple traits, which are a bit like interfaces in Java but can also contain method implementations and properties.

var Animal = function() { };

var Mammal = function() { };
Spritzr.extend(Mammal, Animal); // Mammal is an extension of Animal

var Amphibian = function() { };
Spritzr.extend(Amphibian, Animal); // Amphibian is an extension of Animal

var Bird = function() { };
Spritzr.extend(Bird, Animal); // Bird is an extension of Animal

// We create a LaysEggs trait, which can be a class or a plain old object
var LaysEggs = function() { };
LaysEggs.prototype.layEgg = function() {
	return new Egg();
};

// And we can apply the trait to specific classes
Spritzr.spritz(Amphibian, LaysEggs); // All Amphibians can now lay eggs
Spritzr.spritz(Bird, LaysEggs); // All Birds can now lay eggs

// Then we can use isa() to work out if an object has a specific trait
var cat = new Mammal();
expect(Spritzr.isa(cat, LaysEggs)).toBe(false);

var frog = new Amphibian();
expect(Spritzr.isa(frog, LaysEggs)).toBe(true);

var parrot = new Bird();
expect(Spritzr.isa(parrot, LaysEggs)).toBe(true);

// Traits are also inherited through class extension
var Emu = function() { };
Spritzr.extend(Emu, Bird); // Emu extends Bird

var emu = new Emu();
expect(Spritzr.isa(emu, LaysEggs)).toBe(true);

// or from other traits
var Monotreme = function() { };
Spritzr.spritz(Monotreme, LaysEggs);

var Platypus = function() { };
Spritzr.extend(Platypus, Mammal); // A platypus is a mammal
Spritzr.spritz(Platypus, Monotreme); // But also a monotreme

var ducky = new Platypus();
expect(Spritzr.isa(ducky, LaysEggs)).toBe(true);

Talents

Talents are a bit like traits, but they are applied to instances rather than classes. They can also be removed at any point.

// We have a class describing people
var Person = function(firstName, lastName) {
	this.firstName = firstName;
	this.lastName = lastName;
};
Person.prototype.firstName = null;
Person.prototype.lastName = null;
Person.prototype.getDisplayName = function() {
	return this.firstName + ' ' + this.lastName;
};

var sharon = new Person("Sharon", "Ackerman");
var tony = new Person("Tony", "Jones");

// We can define a talent to describe friendship
var Friend = function(nickname) {
	this.nickname = nickname;
};
Friend.prototype.nickname = null;
Friend.prototype.getDisplayName = function() {
	return this.firstName + ' "' + this.nickname + '" ' + this.lastName;
};

// And add a new talent to our friends
Spritzr.spritz(sharon, new Friend('The Shazza'));

// We can then check for existence of the talent to find out if a person is our friend
expect(Spritzr.isa(sharon, Friend)).toBe(true);
expect(Spritzr.isa(tony, Friend)).toBe(false);

// And the methods should be overridden appropriately
expect(sharon.getDisplayName()).toBe('Sharon "The Shazza" Ackerman');
expect(tony.getDisplayName()).toBe('Tony Jones');

// We can also remove talents from an instance using the amazing titled unspritz function
Spritzr.unspritz(sharon, Friend);
expect(sharon.getDisplayName()).toBe('Sharon Ackerman');

// We don't need to instantiate the talent first either - the constructor will automatically be called
var HasAccount = function() {
	this.username = (this.firstName.substr(0,1) + this.lastName).toLowerCase();
};
HasAccount.prototype.username = null;

Spritzr.spritz(tony, HasAccount); // This adds the methods/properties and calls the constructor

expect(Spritzr.isa(tony, HasAccount)).toBe(true);
expect(tony.username).toBe("tjones");

Caveats

The library is reasonably well tested, but there are some flows which haven't been thought about much so far:

  • The effect of spritzing the same trait or talent twice into a class of object is untested and undefined.
  • New properties added to a trait after it has been spritzed into a class won't be reflected in the class (so if you add trait A into class B, then add a method to A it won't be reflected in B). You should set up your class hierarchy at the start of the application and avoid mutating it later.
  • Equally, methods added to a talent after it's been spritzed into an instance also won't be reflected in the instance.
  • Probably a load of other stuff I haven't thought of!

The intention is to overcome these caveats in the future - it should be possible.