Last active
August 29, 2015 14:06
-
-
Save marlun78/07be3b7b46a046886736 to your computer and use it in GitHub Desktop.
Provides an immutable enum-like type where both keys and values must be unique.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/** | |
* UniqueMap.js | |
* Provides an immutable enum-like type where both keys and values must be unique. | |
* Copyright (c) 2014 marlun78 | |
* MIT License, https://gist.github.com/marlun78/bd0800cf5e8053ba9f83 | |
*/ | |
(function (undefined) { | |
'use strict'; | |
/** | |
* Immutable UniqueMap Type | |
* @typedef {Object} UniqueMap | |
* @property {Function} getKeys | |
* @property {Function} getValues | |
* @property {Function} hasKeys | |
* @property {Function} hasValues | |
*/ | |
/** | |
* @constructor | |
* @param {Object} map - A map of unique keys and unique values. | |
* Keys must be strings and values must be primitives. | |
* @returns {UniqueMap} | |
*/ | |
function UniqueMap(map) { | |
var keys = Object.keys(map), | |
values = []; | |
// Its OK with a loop here. | |
// This type is a convenience and is not expected to have high usage. | |
keys.forEach(function (key) { | |
var value = map[key], | |
type = typeof value; | |
if (type !== 'boolean' && type !== 'number' && type !== 'string') { | |
throw new TypeError('Values must be primitive values (Boolean, Number or String)'); | |
} | |
if (keys.indexOf(value) > -1 || values.indexOf(value) > -1) { | |
throw new Error('Keys and values must be unique. Evaluating key/value ' + value); | |
} | |
values.push(value); | |
}); | |
// Privileged methods (rather than shared prototype methods) to have privacy and immutability. | |
Object.defineProperties(this, { | |
getKey: { | |
/** | |
* Retrieves the key for a value | |
* @param {Boolean|Number|String} value - The value of the key to get | |
* @returns {String|Undefined} | |
*/ | |
value: function getKey(value) { | |
var index = values.indexOf(value); | |
return index > -1 ? keys[index] : undefined; | |
} | |
}, | |
getValue: { | |
/** | |
* Retrieves the value for a key | |
* @param {Boolean|Number|String} key - The key of the value to get | |
* @returns {Boolean|Number|String|Undefined} | |
*/ | |
value: function getValue(key) { | |
var index = keys.indexOf(String(key)); | |
return index > -1 ? values[index] : undefined; | |
} | |
}, | |
hasKey: { | |
/** | |
* Checks if the passed key exists or not | |
* @param {Boolean|Number|String} key - The key of the value to get | |
* @returns {Boolean} | |
*/ | |
value: function hasKey(key) { | |
var index = keys.indexOf(String(key)); | |
return index > -1; | |
} | |
}, | |
hasValue: { | |
/** | |
* Checks if the passed value exists or not | |
* @param {Boolean|Number|String} value - The value of the key to get | |
* @returns {Boolean} | |
*/ | |
value: function hasValue(value) { | |
var index = values.indexOf(value); | |
return index > -1; | |
} | |
} | |
}); | |
} | |
// ============================== TESTS ============================== | |
var colors = new UniqueMap({ | |
red: '#f00', | |
green: '#0f0', | |
blue: '#00f' | |
}); | |
console.log('Colors Tests'); | |
console.assert(colors.getKey('#f00') === 'red', '`getValue` should return the value associated with the key'); | |
console.assert(colors.getKey('none') === undefined, '`getKey` expected to return undefined if no key found'); | |
console.assert(colors.hasKey('blue') === true, '`hasKey` expected to return true'); | |
console.assert(colors.hasKey('none') === false, '`hasKey` expected to return false'); | |
console.assert(colors.getValue('red') === '#f00', '`getValue` should return the value associated with the key'); | |
console.assert(colors.getValue('none') === undefined, '`getValue` should return undefined if no key found'); | |
console.assert(colors.hasValue('#00f') === true, '`hasKey` expected to return true'); | |
console.assert(colors.hasValue('none') === false, '`hasKey` expected to return false'); | |
try { | |
new UniqueMap({ fn: function(){} }); | |
console.assert(false, 'Expected `new UniqueMap` to throw due to value of wrong type'); | |
} catch(e) {} | |
try { | |
new UniqueMap({ a: 1, b: 1 }); | |
console.assert(false, 'Expected `new UniqueMap` to throw due to non-unique values'); | |
} catch(e) {} | |
console.dir(colors); | |
}()); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment