multimethod.js | |
---|---|
multimethod.js 0.1.0 (c) 2011 Kris Jordan
| (function() { |
Multimethods are a functional programming control structure for dispatching function calls with user-defined criteria that can be changed at run time. Inspired by clojure's multimethods, multimethod.js provides an alternative to classical, prototype-chain based polymorphism. | |
Internal Utility Functions | |
No operation function used by default by | var noop = function() {}; |
Identity | var identity = function(a) { return a; }; |
A | var indexOf = function(value, methods) {
for(var i in methods) {
var matches = methods[i][0];
if(_(value).isEqual(matches)) {
return i;
}
}
return false;
} |
Given a dispatch | var match = function(value, methods) {
var index = indexOf(value, methods);
if(index !== false) {
return methods[index][1];
} else {
return false;
}
} |
Simple, consistent helper that returns a native value or invokes a function
and returns its return value. Used by | var toValue = function(subject, args) {
if(_.isFunction(subject)) {
return subject.apply(this, args);
} else {
return subject;
}
}; |
Plucking a single property value from an object in | var pluck = function(property) {
return function(object) {
return object[property];
}
}; |
Implementation | |
| var multimethod = function(dispatch) { |
Private Properties | |
| var _dispatch, |
| _methods = [], |
| _default = noop; |
The fundamental control flow of the | var _lookup = function() {
var criteria = _dispatch.apply(this, arguments),
method = match(criteria, _methods);
if(method !== false) {
return method;
} else {
return _default;
}
}; |
The result of calling | var returnFn = function() {
var method = _lookup.apply(this, arguments);
return toValue.call(this, method, arguments);
}; |
Member Methods / API | |
| returnFn['dispatch'] = function(dispatch) {
if(_.isFunction(dispatch)) {
_dispatch = dispatch;
} else if(_.isString(dispatch)) {
_dispatch = pluck(dispatch);
} else {
throw "dispatch requires a function or a string.";
}
return this;
} |
If | returnFn.dispatch(dispatch || identity); |
| returnFn['when'] = function(matchValue, fn) {
var index = indexOf(matchValue, _methods);
if(index !== false) {
_methods[index] = [matchValue, fn];
} else {
_methods.push([matchValue, fn]);
}
return this;
} |
| returnFn['remove'] = function(matchValue) {
var index = indexOf(matchValue, _methods);
if(index !== false) {
_methods.splice(index, 1);
}
return this;
} |
| returnFn['default'] = function(method) {
_default = method;
return this;
} |
Our | return returnFn;
}; |
The following snippet courtesy of underscore.js.
Export | if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
exports = module.exports = multimethod;
var _ = require('underscore');
}
exports.multimethod = multimethod;
} else if (typeof define === 'function' && define.amd) {
define('multimethod', function() {
return multimethod;
});
} else {
this['multimethod'] = multimethod;
var _ = this['_'];
}
multimethod.version = '0.1.0';
}).call(this);
|