This might not be what you're looking for but what if instead of passing a string to your sandbox you pass a function. This even allows the possibility of using eval
for source files.
Your code would work like this:
...
Sandbox.prototype.Run = function(fn){
fn.call(this);
}
var bx = new Sandbox();
bx.run(function(){
this.x = 1;
});
bx.getVar("x") // 1
then if you wanted to use eval
all you would have to is write a function to append the function syntax
/* source.js */
this.x = 1;
this.blah = "Hello, World!";
With:
Sandbox.prototype.evaluate = function(src){
return eval("function(){" + src + "}");
}
bx.Run(Sandbox.evaluate(src));
bx.getVar("x") // 1
bx.getVar("blah") // "Hello, World!"
Also with this method you can pass the sand-boxed code objects and functions to use by passing them to the function which will simulate an entirely new pseudo-environment to work with.
Edit: I did a little research on the perfect answer to your question which is
Can I iterate over the variables declared in a local scope?
And the answer is no (StackOverflow). It looks like it's a limitation of javascript at the moment. Hopefully something like this will emerge in the new spec.
My idea at the moment would be to eval the source to make all the var statements go to the window object which, with some effort, could be iterated over and added to the Sandbox
object manually.
Like this Warning: horribly simplified
(function(){
var src = get_source_file();
eval(src);
iterate_over_each_newly_created_window_property(function(property, value){
bx[property] = value;
window[property] = undefined;
});
})();
Edit 2:
MY IDEA WORKS =)
function Sandbox(){
return this;
}
Sandbox.prototype.run = function(src){
// Take a snapshopt of the window object before
var before = {};
var prop;
for(prop in window){
before[prop] = true;
}
// Then evaluate the source
window.eval(src);
// Then see what changed
var changed = [];
for(prop in window){
if(!before[prop]){
// Add to the sandbox object
this[prop] = window[prop];
delete window[prop];
}
}
}
var bx = new Sandbox();
bx.run("var x = 'Hello, World!';");
alert(bx.x);
A working example (jsFiddle)
function Sandbox(){
this.keys = [];
this.values = [];
return this;
}
Sandbox.prototype.eval = function(src){
var before = {}, prop, fn;
// Take a snapshopt of the window object before
src = "function(" + this.keys.join(",") + "){" + src + "}";
src = src.replace(/var/g, "");
/* I'm not a wisard at regex so a better one should be used avoid this bug
var x, y, z; */
for(prop in window){
before[prop] = true;
}
// Then evaluate the source
fn = window.eval(src);
fn.apply(window, this.values);
// Then see what changed
for(prop in window){
if(!before[prop]){
// Add to the sandbox object
this.keys.push(prop);
this.values.push(window[prop]);
this[prop] = window[prop];
delete window[prop];
}
}
}
var bx = new Sandbox();
bx.eval("var x = 1;");
bx.eval("var y = x;");
alert(bx.x);
alert(bx.y);
Edit 3: Fixed bug to your specifications
Now I know there are bugs in it and some functions that might make it go haywire. Now it's your job to clean up the code for real use. I gave you conceptually how it can be done.