-
-
Save gaybro8777/3dc0fdf0c7844d1279516a4c5ecec672 to your computer and use it in GitHub Desktop.
My yesterday night 1 hour code rush: JavaScript Hash with Range-based keys
This file contains hidden or 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
/** | |
* September 20 night: 1 hour code rush | |
* @FGRibreau | |
* | |
* Requirements | |
* ------------ | |
* The aim of this code rush is to enable developers to define a "range hash map" | |
* in a very expressive way (without if/then/else). | |
* | |
* Data-set | |
* -------- | |
* | |
* rules = | |
* Nb of days -> Precision levels set | |
* --------------------------------------- | |
* ] -∞ ; 1 ] -> {min, hour, day, mon} | |
* ] 1 ; 8 ] -> {hour, day, mon} | |
* ] 8 ; 62 ] -> {day, mon} | |
* ] 62 ; +∞ [ -> {mon} | |
* | |
* | |
* High-level API | |
* -------------- | |
* | |
* rules.getFor([days.number]) -> {} | |
* | |
* Note | |
* ---- | |
* | |
* - Only _.toArray() underscore method was used and it could easily be replaced by a Array::slice.call(). | |
* - The unit-tests use Qunit. | |
*/ | |
var rules = new Rules() | |
.add(range('] -∞ ; 1 ]'), precisions('min', 'hour', 'day', 'mon')) | |
.add(range('] 1 ; 8 ]'), precisions('hour', 'day', 'mon')) | |
.add(range('] 8 ; 62 ]'), precisions('day', 'mon')) | |
.add(range('] 62 ; +∞ ['), precisions('mon')); | |
/** | |
* Implementation | |
*/ | |
function Rules(){ | |
var rules = []; | |
this.add = function(range, value){ | |
if(!range.in){throw new Error("add(range, value), range must implement .in(Number) -> Boolean");} | |
rules.push(_.toArray(arguments)); | |
return this; | |
}; | |
this.getFor = function(n){ | |
var i = -1, iM = rules.length; | |
while(i++ < iM){ | |
if(rules[i][0].in(n)){return rules[i][1];} | |
} | |
return undefined; | |
}; | |
}; | |
function range(str){ | |
function car(s){return (s || '')[0];} | |
function cdr(s){return (s || '').substring(1);} | |
function cdl(s){return (s || '').substring(0, s.length-1);} | |
function last(s){return (s || '')[s.length-1];} | |
function toNumber(s){return s.indexOf('∞')>0 ? (s[0]==='-'?-1:1)/0 : parseInt(s, 10);} | |
function _range(){ | |
var L, R, Lincluded, Rincluded; | |
str = str.replace(/\s+/gi, '').split(';'); | |
this.Lincluded = Lincluded = car(str[0]) === '['; | |
this.L = L = toNumber(cdr(str[0])); | |
this.R = R = toNumber(cdl(str[1])); | |
this.Rincluded = Rincluded = last(str[1]) === ']'; | |
this.in = function(n){ | |
return ( | |
(!Lincluded && n > L) || (Lincluded && n >= L)) && ((!Rincluded && n < R) || (Rincluded && n <= R) | |
); | |
}; | |
} | |
return new _range(); | |
}; | |
function precisions(){return _.toArray(arguments);}; | |
/** | |
* Unit-tests | |
*/ | |
// Test | |
function checkRangeParse(str, Lincluded, L, R, Rincluded){ | |
var _range = range(str); | |
equal(_range.Lincluded, Lincluded, str + ' Lincluded =' + Lincluded); | |
equal(_range.L, L, str + ' L =' + L); | |
equal(_range.R, R, str + ' R =' + R); | |
equal(_range.Rincluded, Rincluded, str + ' Rincluded =' + Rincluded); | |
} | |
checkRangeParse('] -∞ ; 1 ]', false, -Infinity, 1, true); | |
checkRangeParse('] 1 ; 8 ]', false, 1 , 8 , true); | |
checkRangeParse('] 8 ; 62 ]', false, 8 , 62, true); | |
checkRangeParse('] 62 ; +∞ [', false, 62, +Infinity, false); | |
// Test | |
function inRange(_range, _in, expected){ | |
equal(range(_range).in(_in), expected, _range + '.in('+_in+') = ' + expected); | |
} | |
inRange('] -∞ ; 1 ]', -10, true); | |
inRange('] -∞ ; 1 ]', 0, true); | |
inRange('] -∞ ; 1 ]', 1, true); | |
inRange('] -∞ ; 1 ]', 2, false); | |
inRange('] 1 ; 8 ]', 1, false); | |
inRange('] 1 ; 8 ]', 2, true); | |
inRange('] 1 ; 8 ]', 8, true); | |
inRange('] 1 ; 8 ]', 9, false); | |
inRange('] 8 ; 62 ]', 8, false); | |
inRange('] 8 ; 62 ]', 9, true); | |
inRange('] 8 ; 62 ]', 62, true); | |
inRange('] 8 ; 62 ]', 63, false); | |
inRange('] 62 ; +∞ [', 61, false); | |
inRange('] 62 ; +∞ [', 62, false); | |
inRange('] 62 ; +∞ [', 63, true); | |
inRange('] 62 ; +∞ [', 890, true); | |
// Test | |
function valueFor(_range, expected){ | |
deepEqual(rules.getFor(_range), expected, "rules.getFor("+_range+") " + JSON.stringify(expected)); | |
} | |
valueFor(-1, ['min', 'hour', 'day', 'mon']); | |
valueFor(1, ['min', 'hour', 'day', 'mon']); | |
valueFor(2, ['hour', 'day', 'mon']); | |
valueFor(8, ['hour', 'day', 'mon']); | |
valueFor(9, ['day', 'mon']); | |
valueFor(62, ['day', 'mon']); | |
valueFor(63, ['mon']); | |
valueFor(6390, ['mon']); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment