Skip to content

Instantly share code, notes, and snippets.

@electroCutie
Created February 29, 2020 10:59
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save electroCutie/27ea5ba658c1c935104426ce9cc24b69 to your computer and use it in GitHub Desktop.
Save electroCutie/27ea5ba658c1c935104426ce9cc24b69 to your computer and use it in GitHub Desktop.
//include "/sprintf.js";
//snippet "Object.freeze";
//snippet "Array.forEach";
(function(){
"use strict";
function getOrCall(o, attr){
var v = o[attr];
return undefined != v && null != v && typeof v === "function" ? v.call(o) : v;
}
function interpretPath(O, path){
return path.split(".").reduce(function(OO, p){
return OO.mapGetter(p);
}, O);
}
function Present(v){
// if(assert(null != v)) Object.freeze(this); // This REALLY slows down some things
this.value = v;
}
var P = {};
P.isPresent = function() { return true;};
P.ifPresent = function(c){ c(this.get());};
P.uObj = function(e){ return optionalOf(uTemplate.getObject(this.get()));};
P.map = function(f){ return optionalOf(f(this.get()));};
P.mapGetter = function(a){ return optionalOf(getOrCall(this.get(), a));};
P.mapPath = function(a){ return interpretPath(this, a);};
P.filter = function(p){ return p(this.get()) ? this : E; };
P.get =
P.orNull =
P.orFalse =
P.orElse =
P.orElseGet =
P.orElseThrow = function() {return this.value;};
Present.prototype = Object.freeze(P);
var E = {};
E.isPresent = function() { return false;};
E.ifPresent = function(){};
E.uObj =
E.map =
E.mapPath =
E.filter =
E.mapGetter = function() { return this;};
E.get = function() { throw "No such element";};
E.orNull = function() { return null;};
E.orFalse = function() { return false;};
E.orElse = function(v){ return v;};
E.orElseGet = function(s){ return s();};
E.orElseThrow = function(t){ throw t;};
Object.freeze(E);
function optionalOf(v){ return null == v ? E : new Present(v); }
/*
* Optional Function Builder
*/
function buildF(steps, parentF){
assert(null != parentF);
assert($.isFunction(parentF));
var txt = [], args = [], argNames = [];
var argIdx = 0;
txt.push("return function(o){\nreturn Optional.ofNullable(o)");
steps.forEach(function(s){
var argVal = s.arg;
if(undefined !== argVal){
var arg = "a"+(argIdx++);
txt.push(sprintf(s.sprintfTxt, s.verb, arg));
argNames.push(arg);
args.push(argVal);
}else{
txt.push(sprintf(".%s()", s.verb));
}
});
txt.push(";};");
return parentF(
(new Function(argNames.join(", "), txt.join("\n"))).apply(null, args)
);
}
function Builder(parentF){
this.steps = [];
this.parentF = null != parentF
? parentF
: function(o){ return o;};
}
Builder.prototype.mapPath = function(v){
this.steps.push({
verb: "mapPath",
arg: v,
sprintfTxt: v.split(".").map(function(p){
return ".mapGetter('"+p+"')";
}).join("\n")
});
return this;
};
Builder.prototype.uObj = function(){
this.steps.push({verb: "uObj"});
return this;
};
["isPresent", "ifPresent", "map", "mapGetter"].forEach(function(act){
Builder.prototype[act] = function(v){
this.steps.push({verb: act, arg: v, sprintfTxt: ".%s(%s)"});
return this;
};
});
["get", "orNull", "orElse", "orElseGet", "orElseThrow"].forEach(function(terminal){
var f = function(v){
this.steps.push({verb: terminal, arg: v, sprintfTxt: ".%s(%s)"});
return buildF(this.steps, this.parentF);
};
f.isTerminal = true;
Builder.prototype[terminal] = f;
});
window.Optional = Object.freeze({
of: function(v){ return new Present(v);},
ofNullable: optionalOf,
empty: function(){ return EmptyInstance;},
functionBuilder: function(parentF){return new Builder(parentF);}
});
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment