Separate code space/sandbox?

P

Patrik Sundberg

Hi,

I'm interested in figuring out a way to get a separate scope. I do not
need any other traditional sandbox features, i.e. any code goes, I
just want code evaluated in the scope to no affect the parent scope
(at all). Example illustrating what I am after:

a = 10
SeparatedScope.new do
a = a + 1
p a
end
p a

yielding:
11
10

I'd like it to have the same initialization/separation also for
instance variables and even global variables if possible.

Is something like that already available? If not, any good ideas for
how to implement it?

I did have a quick look at sandbox by _why, seems may do what I want
but not so keen on the interpreter patching etc so looking for
opportunities.

Regards,
Patrik
 
B

Bill Kelly

From: "Patrik Sundberg said:
I'm interested in figuring out a way to get a separate scope. I do not
need any other traditional sandbox features, i.e. any code goes, I
just want code evaluated in the scope to no affect the parent scope
(at all). Example illustrating what I am after:

a = 10
SeparatedScope.new do
a = a + 1
p a
end
p a

yielding:
11
10

I'd like it to have the same initialization/separation also for
instance variables and even global variables if possible.

This isn't very pretty, but...

class SeparatedScope
def initialize(code)
eval(code)
end
end

a = 10
SeparatedScope.new %{
a = 11
p a
}
p a

....

Note there's no access to outer scope variables at all in
this case, thus the inner "a = 11" instead of "a = a + 1".


:(


Regards,

Bill
 
P

Patrik Sundberg

Bill said:
Note there's no access to outer scope variables at all in
this case, thus the inner "a = 11" instead of "a = a + 1".


:(

yeah, that doesn't quite fly for my purpose - i want an initialization
from current scope, then no impact on the parent scope.
 
C

Caleb Clausen

Hi,

I'm interested in figuring out a way to get a separate scope. I do not
need any other traditional sandbox features, i.e. any code goes, I
just want code evaluated in the scope to no affect the parent scope
(at all). Example illustrating what I am after:

a = 10
SeparatedScope.new do
a = a + 1
p a
end
p a

yielding:
11
10

I'd like it to have the same initialization/separation also for
instance variables and even global variables if possible.

Here's a macro which seems to do the job. Comments follow.

#file separated_scope_user.rb
require 'rubygems'
require 'macro'
Macro.require 'example/separated_scope'

#file separated_scope.rb
macro separated_scope
code=yield
localnames=[]
code.depthwalk{|parent,i,j,node|
if RedParse::VarNode===node
node.name<<'_'
localnames<<node.name
end
}
:(
^localnames.uniq.inject:)(nil)){|sum,lvar|
RedParse::AssignNode[ RedParse::VarNode[lvar],'=',sum ]
}
eval local_variables.map{|lvar| lvar+"_="+lvar}.join(';')
^code
)
end

a = 10
separated_scope do
a = a + 1
p a #=>11
end
p a #=>10

Commentary:
1) This is considerably more complicated (=uglier) than Bill's
attempt. There's even an eval lurking in there, which oughtn't be
necessary when using macros. However, it does seem to fulfill all your
requirements.

2) A more sophisticated variable renaming scheme may be required if
you want your program to have variables which end with an underscore.

3) Use of eval inside a separated_scope will confuse things. Variables
used in the eval arg will refer to the outer scope, not the separated
scope.

4) Macros are not a standard part of ruby syntax; they require my
macro preprocessor, rubymacros. do a 'gem install rubymacros' to get
it.
Also see http://github.com/coatl/rubymacros

5) Code that defines or uses macros must be pulled into the
interpreter using a special version of require: Macro.require. That's
why there's a separate file which requires 'macro', then calls
Macro.require.
 
P

Patrik Sundberg

Caleb said:
Commentary:
1) This is considerably more complicated (=uglier) than Bill's
attempt. There's even an eval lurking in there, which oughtn't be
necessary when using macros. However, it does seem to fulfill all your
requirements.

2) A more sophisticated variable renaming scheme may be required if
you want your program to have variables which end with an underscore.

3) Use of eval inside a separated_scope will confuse things. Variables
used in the eval arg will refer to the outer scope, not the separated
scope.

4) Macros are not a standard part of ruby syntax; they require my
macro preprocessor, rubymacros. do a 'gem install rubymacros' to get
it.
Also see http://github.com/coatl/rubymacros

5) Code that defines or uses macros must be pulled into the
interpreter using a special version of require: Macro.require. That's
why there's a separate file which requires 'macro', then calls
Macro.require.

Awesome! I had not seen rubymacros before. I'll dig into this and try to
understand it in more detail.

Thank you very much for the help.
 
C

Caleb Clausen

Awesome! I had not seen rubymacros before. I'll dig into this and try to
understand it in more detail.

If you get stuck or can't understand something, don't hesitate to ask me.
 
C

Caleb Clausen

Sweet I want to use macros. How about one to support ++

Hmm, I had thought that ruby's immutable numeric types meant this was
impossible, but maybe it is feasible to implement as a macro... (not
as a method).

The big problem is that I haven't (uh, yet) written the magic that
will allow users to define their own operators. (Or (re)define
existing operators as macros...)

But other than that, this ought to be possible... you'd need to use
different names until operator macros are defined, tho.
The preincrement version could be written like this:

macro preincr(n)
:( ^n+=1 )
end

postincrement is somewhat more difficult. Here's a first pass:

macro postincr(n)
:( (res=^n;^n+=1;res) )
end

(Warning: both increment macros are untested.)

but postincr is problematic. A call like:
postincr( a().b )
would cause a().b to be evaluated twice, which isn't right. Solving
this, so that side effects in the arg to postincr are evaluated only
once, is more complicated, and I won't attempt it here.

And nobody wants to type preincr or postincr (or even incr) when they
could just use +=1, so we'd really need user-defined operators
here....


Is that a self-portrait? ;)
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,164
Messages
2,570,898
Members
47,439
Latest member
shasuze

Latest Threads

Top