I'm exploring a variety of options for a JavaScript routing framework that I'm working on, and I'd like to provide a DSL written in JavaScript for defining the router.
I had the idea of using temporary prototype overrides on the String class (maintain a hash of the previous prototype values, override, run the DSL code, reset the prototype values to what they were) to all for something like this:
DSL.run(function() {
"hello".isSomething();
"foo".isSomethingElse();
});
The other idea was to use define temporary global variables and then remove/reset them after the DSL is done running. That way, if you run the DSL closure with window
(or whatever the global object is) as the this
context, I believe you should be able to do something like:
DSL.run(function() {
defineSomething("hello");
defineSomethingElse("foo");
});
I know I know I know I should be super careful about the prototype overloads and polluting the global namespace, but this seems to be a pretty localized and easily cleanup-able approach to keep that sort of thing from happening. My question is, are there any other considerations that would keep this from being a reality?
One potential problem I could think of is whether this would work in a Node.js setting, where code is stored in separate modules and global variables kept from each other, which I think would eliminate option B, but what about String prototype overloads? Those are shared between modules, right? e.g. if I include module A, which sets String prototype values, those prototype values will be available in the including code, right?
Also, let me know if anyone's done this sort of thing before. I think it's a clever approach to this sort of problem and I haven't seen anything quite like it, but I want to make sure I'm not leaving out something really obvious and damning.
Use delete String.prototype[method]
.
var dsl = function(f){
var _ = String.prototype;
_.isSomething = function(){
console.log('isSomething: '+this);
}
_.isSomethingElse = function(){
console.log('isSomethingElse: '+this);
}
f();
delete _.isSomething;
delete _.isSomethingElse;
}
dsl(function(){
"hello".isSomething(); // isSomething: hello
"foo".isSomethingElse(); // isSomethingElse: foo
});
// "hello".isSomething(); // error "Object has no method 'isSomething'"
// "foo".isSomethingElse(); // error "Object has no method 'isSomethingElse'"