[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

eval statement

Jonathan Wills

2/6/2009 6:53:00 PM

Trying to switch a project of mine from python to ruby. Love ruby so
far, but I'm finding that the eval statement is a bit more difficult to
use than python's exec statement. Here is one of the problems I'm
having, RUBY_VERSION=1.9.1

a = 1
eval('a=2')
puts a

This will print out '2', as I want. However if I remove the first line,

eval('a=2')
puts a

r.rb:2:in `<main>': undefined local variable or method `a' for
main:Object (NameError)


Now if in the first case eval can change a variable in its scope, why
can't it also create a variable in that same scope? I may also not be
totally clear on the way ruby handles scoping, which might be part of
what I am having trouble understanding.

Any help understanding the eval statement would be appreciated. I will
probably have more questions about it, but I'll leave at this for now.

thanks,
-Jonathan
--
Posted via http://www.ruby-....

25 Answers

Jan-Erik R.

2/6/2009 7:17:00 PM

0

Jonathan Wills schrieb:
> Trying to switch a project of mine from python to ruby. Love ruby so
> far, but I'm finding that the eval statement is a bit more difficult to
> use than python's exec statement. Here is one of the problems I'm
> having, RUBY_VERSION=1.9.1
>
> a = 1
> eval('a=2')
> puts a
>
> This will print out '2', as I want. However if I remove the first line,
>
> eval('a=2')
> puts a
>
> r.rb:2:in `<main>': undefined local variable or method `a' for
> main:Object (NameError)
>
>
> Now if in the first case eval can change a variable in its scope, why
> can't it also create a variable in that same scope? I may also not be
> totally clear on the way ruby handles scoping, which might be part of
> what I am having trouble understanding.
>
> Any help understanding the eval statement would be appreciated. I will
> probably have more questions about it, but I'll leave at this for now.
>
> thanks,
> -Jonathan
why do you want to use eval?
eval is evil and in most cases not needed in Ruby

Jonathan Wills

2/6/2009 7:26:00 PM

0


> why do you want to use eval?
> eval is evil and in most cases not needed in Ruby

I want my program to run user-supplied ruby code, and eval is the only
thing I know of that can do this. If there is a better way I would be
willing to try it. I know in python that the exec statement is
considered 'evil', but all that means is you have to be careful.
--
Posted via http://www.ruby-....

Mike Gold

2/6/2009 7:34:00 PM

0

Jonathan Wills wrote:
>
> a = 1
> eval('a=2')
> puts a
>
> This will print out '2', as I want. However if I remove the first line,
>
> eval('a=2')
> puts a

The thing to remember is that local variables are always determined at
parse time.

The contents of 'a=2' is not seen by the parser when the file is read,
so in the second case the 'a' in 'puts a' is determined to be a method
call: "call method 'a', then call method puts".

Constants and instance variables are different, as they are determined
by their naming scheme and therefore behave more as you expected.

irb(main):001:0> eval("@a = 2")
=> 2
irb(main):002:0> @a
=> 2
irb(main):003:0> eval("X = 3")
=> 3
irb(main):004:0> X
=> 3

--
Posted via http://www.ruby-....

Jan-Erik R.

2/6/2009 7:38:00 PM

0

Mike Gold schrieb:
> Jonathan Wills wrote:
>> a = 1
>> eval('a=2')
>> puts a
>>
>> This will print out '2', as I want. However if I remove the first line,
>>
>> eval('a=2')
>> puts a
>
> The thing to remember is that local variables are always determined at
> parse time.
>
> The contents of 'a=2' is not seen by the parser when the file is read,
> so in the second case the 'a' in 'puts a' is determined to be a method
> call: "call method 'a', then call method puts".
>
> Constants and instance variables are different, as they are determined
> by their naming scheme and therefore behave more as you expected.
>
> irb(main):001:0> eval("@a = 2")
> => 2
> irb(main):002:0> @a
> => 2
> irb(main):003:0> eval("X = 3")
> => 3
> irb(main):004:0> X
> => 3
>
be careful when using eval in irb. It can lead to hasty conclusions (is
this correct english? Google Translate sucks =D) which are not correct
in a pure ruby environment (because under the hood irb uses lots of evil
evals)

Gary Wright

2/6/2009 7:40:00 PM

0


On Feb 6, 2009, at 1:52 PM, Jonathan Wills wrote:
> Now if in the first case eval can change a variable in its scope, why
> can't it also create a variable in that same scope? I may also not be
> totally clear on the way ruby handles scoping, which might be part of
> what I am having trouble understanding.

Because eval creates a new nested scope rather than sharing the
enclosing scope.

Variable visibility between nested scopes is like a one-way mirror:
you can manipulate variables created in a parent scope but you can not
see or manipulate variables created in a 'child' scope.


David A. Black

2/6/2009 7:53:00 PM

0

Hi --

On Sat, 7 Feb 2009, Jonathan Wills wrote:

>
>> why do you want to use eval?
>> eval is evil and in most cases not needed in Ruby
>
> I want my program to run user-supplied ruby code, and eval is the only
> thing I know of that can do this. If there is a better way I would be
> willing to try it. I know in python that the exec statement is
> considered 'evil', but all that means is you have to be careful.

Yes, but what does *that* mean? :-)


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.r...
Coming in 2009: The Well-Grounded Rubyist (http://manning....)

http://www.wis... => Independent, social wishlist management!

Jonathan Wills

2/6/2009 7:55:00 PM

0

>
> Because eval creates a new nested scope rather than sharing the
> enclosing scope.
>
> Variable visibility between nested scopes is like a one-way mirror:
> you can manipulate variables created in a parent scope but you can not
> see or manipulate variables created in a 'child' scope.

Ok, I see that now, good to know. Now I have another question. I want
to be able to create an arbitrary number of 'clean' bindings in which I
can run ruby code. Basically I want the user to be able to supply an
unspecified number of ruby files, all of which will get run, and not
have to worry about namespace collisions. Additionally I want access to
the scopes that those files were executed in after they are done. I
know I can create a binding from my current scope, but if I put anything
in it, it can get modified when I do my_binding.eval.

In python this was quite simple by passing clean dictionaries to the
exec statement, but perhaps I will have to rethink my design :(

thanks,
-Jonathan
--
Posted via http://www.ruby-....

David A. Black

2/6/2009 8:00:00 PM

0

Hi --

On Sat, 7 Feb 2009, Mike Gold wrote:

> Jonathan Wills wrote:
>>
>> a = 1
>> eval('a=2')
>> puts a
>>
>> This will print out '2', as I want. However if I remove the first line,
>>
>> eval('a=2')
>> puts a
>
> The thing to remember is that local variables are always determined at
> parse time.
>
> The contents of 'a=2' is not seen by the parser when the file is read,
> so in the second case the 'a' in 'puts a' is determined to be a method
> call: "call method 'a', then call method puts".

Actually it can't tell whether it's a method or a variable, so you
get:

undefined local variable or method `a' for main:Object (NameError)

> Constants and instance variables are different, as they are determined
> by their naming scheme and therefore behave more as you expected.
>
> irb(main):001:0> eval("@a = 2")
> => 2
> irb(main):002:0> @a
> => 2
> irb(main):003:0> eval("X = 3")
> => 3
> irb(main):004:0> X
> => 3

They're that way because of how they're scoped, but the assignments
themselves are handled by eval the same way as the local ones; that
is, there's no extra information available prior to the execution.


David

--
David A. Black / Ruby Power and Light, LLC
Ruby/Rails consulting & training: http://www.r...
Coming in 2009: The Well-Grounded Rubyist (http://manning....)

http://www.wis... => Independent, social wishlist management!

Christopher Dicely

2/6/2009 9:30:00 PM

0

On Fri, Feb 6, 2009 at 11:55 AM, Jonathan Wills <runningwild@gmail.com> wrote:
>>
>> Because eval creates a new nested scope rather than sharing the
>> enclosing scope.
>>
>> Variable visibility between nested scopes is like a one-way mirror:
>> you can manipulate variables created in a parent scope but you can not
>> see or manipulate variables created in a 'child' scope.
>
> Ok, I see that now, good to know. Now I have another question. I want
> to be able to create an arbitrary number of 'clean' bindings in which I
> can run ruby code. Basically I want the user to be able to supply an
> unspecified number of ruby files, all of which will get run, and not
> have to worry about namespace collisions. Additionally I want access to
> the scopes that those files were executed in after they are done. I
> know I can create a binding from my current scope, but if I put anything
> in it, it can get modified when I do my_binding.eval.

You can get a binding from any object that has a method to tell you
its binding. Something like this (off the top of my head) might work:
---
class ExecutionContext
private_class_method :new

@@contexts = {}

def self.[](key)
@@contexts[key]
end

def self.new_binding(key)
new(key).binding
end

def initialize(key)
raise KeyError if @@contexts[key]
@@contexts[key] = self
end

def get_binding
binding
end
end
---

So, when you want a new binding to use, you call
ExecutionContext.new_binding(key), and to get back the a binding used
previously, you call ExecutionContext[key].get_binding, where "key" is
the key given when you called new_binding to generate the binding.

But while these are mostly "fresh" bindings, they are nothing at all
like safe sandboxes. You may need something like this:
http://github.com/why/sandbox/t...

Jonathan Wills

2/6/2009 9:46:00 PM

0

Christopher Dicely wrote:
> On Fri, Feb 6, 2009 at 11:55 AM, Jonathan Wills <runningwild@gmail.com>
> wrote:
>> can run ruby code. Basically I want the user to be able to supply an
>> unspecified number of ruby files, all of which will get run, and not
>> have to worry about namespace collisions. Additionally I want access to
>> the scopes that those files were executed in after they are done. I
>> know I can create a binding from my current scope, but if I put anything
>> in it, it can get modified when I do my_binding.eval.
>
> You can get a binding from any object that has a method to tell you
> its binding. Something like this (off the top of my head) might work:
> ---
> class ExecutionContext
> private_class_method :new
>
> @@contexts = {}
>
> def self.[](key)
> @@contexts[key]
> end
>
> def self.new_binding(key)
> new(key).binding
> end
>
> def initialize(key)
> raise KeyError if @@contexts[key]
> @@contexts[key] = self
> end
>
> def get_binding
> binding
> end
> end
> ---
>
> So, when you want a new binding to use, you call
> ExecutionContext.new_binding(key), and to get back the a binding used
> previously, you call ExecutionContext[key].get_binding, where "key" is
> the key given when you called new_binding to generate the binding.
>
> But while these are mostly "fresh" bindings, they are nothing at all
> like safe sandboxes. You may need something like this:
> http://github.com/why/sandbox/t...

Interesting. Someone else has shown me a similar way of getting a fresh
context. Do you know what exactly about it is unlike a sandbox? I know
that with this approach that code that I run can use the require
statement and it will drop such files into my scope, but are there any
other sort of problems?

Are there any plans for ruby to support a sandboxed eval like I can get
in python? I might be willing to contribute such a thing if it could
get added into the standard interpreter.

thanks
--
Posted via http://www.ruby-....