topics: functional programming, concurrency, web-development, REST, dynamic languages

Sunday, June 15, 2008

fun with with - part II

Here is one implementation of a function 'scope' which lets us write code like:

with (scope({ sn : dk.ourclient.supernavigator,
u : com.trifork.utils})) {


with(sn) include()(model,view)
with(u) include()(Format)

run(function(mod,view,fm){
//do stuff
});
}

The function that is given to 'run' will be called with variable 'mod' bound to dk.ourclient.supernavigator.model, 'view' bound to dk.ourclient.supernavigator.view and with 'fm' bound to com.trifork.utils.Format.

Note that it is important that the function given to run is executed in a scope that does not see the functions introduced by the outer 'with' statement - this would be dangerous. In order t acheive this, the variable 'run' 'include' and 'sn' and 'u' are written so that they can only be used one time: once called they delete the reference to them selves. Similarly, suppose com.trifork.utils has a property 'include' then if we did:

with(u) include()(Format,include)
we would expect the 'include' from u, and not the include function from our "package DSL".

This code does that (though I haven't tested it thoroughly):

function scope(spec){
if (spec.hasOwnProperty('module')) {
throw new Error('Reserved word "module" may not be used.');
}
if (spec.hasOwnProperty('run')) {
throw new Error('Reserved word "run" may not be used.');
}

var objects = [];

for (var p in spec) if (spec.hasOwnProperty(p)) {
spec[p] = object(spec[p])
spec[p].include = function(){
delete this.include;
return function(){
for (var i=0,N=arguments.length;i<N;i++){
objects.push(arguments[i]);
}
};
};
}
spec.run = function(fn){
for(var p in this) {if (this.hasOwnProperty(p)) {
delete this[p];
}}
return fn.apply(objects[0],objects);
}
return spec;
}

No comments: