Skip to content

Instantly share code, notes, and snippets.

@ruiramos
Last active January 19, 2022 14:58
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save ruiramos/d1af3dfbf640e953c87447b33b272150 to your computer and use it in GitHub Desktop.
Save ruiramos/d1af3dfbf640e953c87447b33b272150 to your computer and use it in GitHub Desktop.
Simple Javascript pattern matching
let a = [null, {status: 'OK'}];
switch_(
(err, _) => console.log('error', err),
(_, resp) => console.log('response', resp)
)(a);
// logs 'response' { "status": "OK" }
let b = [{err: 401}, null];
switch_(
(err, _) => console.log('error', err),
(_, resp) => console.log('response', resp)
)(b);
// logs 'error' { "err": 401 }
let c = [1, 2, 3, 4];
let sumReduce = numbers => switch_(
(x, $tail) => x + sumReduce($tail),
(x) => x
)(numbers);
console.log(sumReduce(c)); // 10
let len = array => switch_(
(a, b, c) => 3,
(a, b) => 2,
(a) => 1,
() => 'dont know'
)(array);
console.log(len([9,9,9,9,9,9])) // 'dont know'
let players = switch_(
({pool}) => `${pool} plays pool`,
({darts}) => `${darts} plays darts`,
() => 'none'
);
console.log(players({darts: 'David'})); // David plays darts
console.log(players({pool: 'Paul'})); // Paul plays pool
let guess = switch_(
(n = 1) => 'very low: ' + n,
(n = 2) => 'low: ' + n,
(n = 3) => 'almost: ' + n,
(n = 4) => 'just right: ' + n,
(n) => 'give up: ' + n
);
console.log(guess(4)); // just right: 4
let guessHarder = switch_(
(n = 3, p = 2) => 'WINNER!!!',
(a, b) => 'try again',
() => 'guess 2 numbers'
);
console.log(guessHarder([4, 2])); // try again
//---
function switch_(...exps){
return function(data = []){
if(!Array.isArray(data)) data = [data];
for(let i = 0; i < exps.length; i++){
let exp = exps[i];
var args = exp
.toString()
.match(/(?:function\s)?.*?\(([^)]*)\)/)[1]
.split(',');
let argValues = [];
let usesTail = false;
for(let j = 0; j < args.length; j++){
let arg = args[j].trim();
if(arg === '_'){
argValues[j] = null;
continue;
}
if(!data[j]) break;
if(arg.indexOf('$') === 0) {
argValues[j] = data.slice(j);
usesTail = true;
break;
} else if(arg.match(/{\w+}/)){
let name = (arg.match(/(\w+)/))[1];
let result = eval_(data[j], name);
if(result){
argValues[j] = {[name]: result};
} else break;
} else if(arg.indexOf('=') > -1){
let [ref, val] = arg.split('=');
ref = ref.trim();
val = val.trim();
let result = data[j] == val;
if(result){
argValues[j] = val;
} else break;
} else {
argValues[j] = data[j];
}
}
if((
// common case where number of params and args match
argValues.length === data.length &&
argValues.length === args.length
) || (
// empty catch all
args.length === 1 &&
args[0] === ""
) ||
// $tail special case
usesTail
){
return exp.apply(null, argValues);
}
}
}
}
function eval_(ctx, obj){
try{
return new Function(`return ${obj}`).call(ctx);
} catch(e){
return new Function(`return this.${obj}`).call(ctx);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment