Asfand Yar Qazi wrote:
> Hi,
> 
> I'd like to evaluate a string of Ruby code (stored in a YAML file, as it 
> happens) safely.  Note the purpose is simply to avoid variable name 
> clashes and stop lots of eval'ed Ruby code from overloading the heap 
> with lots of objects (i.e. when the anonymous module is deleted, the 
> temporary variables defined within it are also gone.)
> 
> The purpose is NOT for safety reasons, so we don't have to worry about 
> that.
> 
> Am I doing it the right way?  Or does anybody know a better way?  Any 
> better way of passing in arguments to the code in the string?
> 
> Anyway, here goes:
> 
> def eval_string(s, *args_to_pass)
>     m = Module.new
>     m.const_set("ARGS", arg_to_pass)
>     m.class_eval(s.to_str)
> end # Soon m will be GC'ed, and all temp objects gone! MUHAHA
> 
> s.eval_string(<<EOL, [1, 2, 3, 4, 5])
> a = ARGS
> b = a.collect {|i| i*3}
> c = b.join("||")
> puts(c)
> EOL

Here's another way of passing in args, using a fixed method name 
("main") rather than a fixed constant name ("ARGS"):

def eval_string(s, *args_to_pass)
     m = Module.new
     def m.method_added(name)
       module_function(name)
     end
     m.class_eval(s.to_str)
     m.main(*args_to_pass)
end

eval_string(<<EOL, [1, 2, 3, 4, 5])
   def main(*args)
     b = args.collect {|i| i*3}
     c = b.join("||")
     puts(c)
   end
EOL

That's nice if you want to break up main into several methods, define 
constants, etc.

Here's an even simpler way, just wrapping the code in a proc, which may 
be suitable for small snippets of code:

def eval_string(s, *args_to_pass)
     pr = eval("proc do |*args| #{s.to_str} end")
     pr[*args_to_pass]
end

eval_string(<<EOL, [1, 2, 3, 4, 5])
   b = args.collect {|i| i*3}
   c = b.join("||")
   puts(c)
EOL

Warning: the binding of the "pr" local variable and the two arg 
variables is still in effect wthin the proc, so this may not be 
suitable. Or you could use very obscure names and hope.