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

polymorphic

v1.4.5

Published

Create functions with different argument signatures for different code flows

Downloads

84

Readme

npm version Build Status Coverage Status dependencies dev-dependencies Codacy Badge

node-polymorphic

Create different flows in code based on different argument signatures

Install

npm install --save polymorphic

Concept

One of the complaints on writing javascript is that it is not as strict as one would like, adding 'use strict' to the code helps a lot but it does not (yet) enforce function calls with explicitly typed arguments. In comes polymorphic, trying to add both a level of strictness while also (trying to) improve convenience. If you have ever found yourself checking the arguments of your functions over and over again (if not, you should check your input), you may find it relaxing to use polymorphic which can do this for you. Or actually, it does not validate the inputs, but it will not find a proper function signature for the call resulting in a thrown Error.

API

The polymorphic function itself takes no arguments, all it does is creating the polymorphic function, e.g. var myVar = polymorphic();. While myVar now contains a polymorphic function, it will not accept any mix of arguments as it simply has no handlers for any pattern. Calling it now would result in an Error. Calling myVar(); will throw: polymorph: signature not found ""

.signature(string signature1, [string ...signatureN,] function handler) (void)

By calling the .signature method on the polymorphic function you've created (myVar in the example above), you can add any number of signatures you want (in excess of 1) + the handler function for those signatures. The syntax of a single argument in a signature is:type [name[=default]] It should be noted that defaults can only be one of the following types: number, int, float, string, boolean

Recognized types in a signature

All of the basic types supported by javascript are supported, next to a few more convenient ones.

  • string
  • number (also float and int)
  • boolean (also bool)
  • array
  • object (note that you may choose to use the constructor name to be more explicit, by default this takes the inheritance chain into consideration, but accepts an added ! (e.g. 'Foo!') to indicate only a Foo is accepted and not an inherited object)
  • void (also an empty signature: ''), denotes a signature which does not allow any arguments
  • ... (note that this variadic type will always become an array containing zero of more arguments, the variadic must be the last argument in a signature)

Usage

var polymorphic = require('polymorphic'),
	total = polymorphic();

total.signature('number, number', function(a, b) {
	return a + b;
});

total.signature('string, string', function(a, b) {
	//  call the numeric `total` handler with the strings changed into numbers
	return total(+a, +b);
});

console.log(total(1, 2));      //  3
console.log(total('4', '2'));  //  6
console.log(total(true));      //  throws Error, as there is no signature allowing a single boolean argument

Default values

A lot of times more flexibility and consistency can be achieved by having default values, values - if not explicitly provided - to be a certain value.

var polymorphic = require('polymorphic'),
	tax = polymorphic();

tax.signature('number, number percentage=15', function(a, b) {
	return a + (a * (b / 100));
});

//  using the default `tax`
console.log(tax(1));  //  1.15
console.log(tax(2));  //  2.3

//  specify a custom `tax`
console.log(tax(1, 10));  //  1.1
console.log(tax(2, 75));  //  3.5

References

In version 1.1.0, the concept of references is introduced, this allows you to refer to other (named) variables and will take the value of the referred variable if not provided during the call.

var polymorphic = require('polymorphic'),
	ref = polymorphic();

ref.signature('string a=hello, string b=@a', function(a, b) {
	return a + ', ' + b;
});

console.log(ref());                  //  'hello, hello'
console.log(ref('hi'));              //  'hi, hi'
console.log(ref('hello', 'world'));  //  'hello, world'

Strong typing

As of version 1.0.0 (breaking API change), inheritance is taken into consideration

var polymorphic = require('polymorphic'),
	util = require('util'),
	showDate = polymorphic();

//  define a couple of very simple object types, both dealing with - for example - a date but treated differently
function Foo() {
	this.date = new Date();
}

function Bar() {
	this.timestamp = Date.now();
}

function Baz() {
	//  actually execute everything done in the Bar constructor
	Baz.super_.apply(this, arguments);
}

util.inherits(Baz, Bar);


//  the goal is to log a date object, so we add that signature (note that Date is a native object)
showDate.signature('Date', function(date) {
	//  this logs the same as: console.log('>> ' + date)
	console.log('>> %s', date);
});

//  add different signatures for our objects
showDate.signature('Foo', function(foo) {
	//  we know a Foo has a 'date' property containing a Date object, so we can provide that to `strong`
	showDate(foo.date);
});

showDate.signature('Bar', function(bar) {
	//  we know a Bar has a 'timestamp' property containing the milliseconds since 1970-01-01 00:00:00.0
	//  we also happen to know this timestamp can be used to re-create a Date
	showDate(new Date(bar.timestamp));
});

//  and now...
showDate(new Date());  //  e.g. >> Mon Apr 27 2015 01:23:45 GMT+0200 (CEST)
showDate(new Foo());   //  e.g. >> Mon Apr 27 2015 01:23:45 GMT+0200 (CEST)
showDate(new Bar());   //  e.g. >> Mon Apr 27 2015 01:23:45 GMT+0200 (CEST)
//  (as of 1.0.0) Baz extends Bar and is therefor allowed on Bar signatures
showDate(new Baz());   //  e.g. >> Mon Apr 27 2015 01:23:45 GMT+0200 (CEST)

In order to allow only Bar instances and never an extend, you can specify the signature 'Bar!' (read this as "must be a Bar!"). In case both 'Bar' and 'Bar!' would exist, the most explicit one ('Bar!') will take precedence. Adding the following to the example above:

//  add a signature allowing only explicit Bar types
showDate.signature('Bar!', function(bar) {
	showDate(new Date(bar.timestamp), 'bar!');
});

showDate(new Bar());   //  e.g. >> Mon Apr 27 2015 01:23:45 GMT+0200 (CEST) (from: bar!)
showDate(new Baz());   //  e.g. >> Mon Apr 27 2015 01:23:45 GMT+0200 (CEST) (from: bar or baz)

Variadic arguments (...)

As of version 0.2.0 the variadic type is understood by polymorphic, a variadic type equips you with a lot more flexibility and may be able to help you declaring less specific signatures in some cases. Basically the variadic type (as implemented by polymorphic) is a way of creating a signature which tells I want this and that, + anything else

var polymorphic = require('polymorphic'),
	variadic = polymorphic();

//  create a variadic signature, requiring the first argument to be an integer and doesn't care about the rest
variadic.signature('int, ...', function(num, rest) {
	console.log('integer: %d', num);
	rest.forEach(function(m) {
		console.log(' -', m);
	});
});

variadic(1);
/*
integer: 1
*/

variadic(10);
/*
integer: 10
*/

variadic(3, 1, 2, 'any', true);
/*
integer: 3
 - 1
 - 2
 - 'any'
 - true
*/

Similar packages

As there are currently over 140.000 public modules on npm, there sure are modules providing the same functionality. It feels like cheating not to mention a couple of the more popular ones, so here is a shortlist (in alphabetical order) to check out.

License

MIT © 2015-2016 Konfirm Open

NOTE; Polymorphic up to version 1.3.0 was licensed under the GPLv2 The MIT license is compatible with GPL and offers less restrictions on the projects using this software.