New Research: Supply Chain Attack on Axios Pulls Malicious Dependency from npm.Details →
Socket
Book a DemoSign in
Socket

spritzr

Package Overview
Dependencies
Maintainers
1
Versions
3
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

spritzr

Provides an inheritance/traits/talents library

latest
Source
npmnpm
Version
0.1.1
Version published
Weekly downloads
12
-53.85%
Maintainers
1
Weekly downloads
 
Created
Source

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).

BrowserStack

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:

  • 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.
  • 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.

Keywords

class

FAQs

Package last updated on 14 Jul 2014

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts