[lnkForumImage]
TotalShareware - Download Free Software

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


 

Forums >

comp.lang.ruby

binding question

email55555 email55555

12/8/2004 9:44:00 PM

I have this example codes:

b = binding
['x', 'y'].each { |e| eval("#{e} = 123", b) }
p local_variables
p x
p y

Run the codes from irb, everything works.
However, save it to a file like pgm.rb and ruby it as "ruby pgm.rb", I
got the error message as:
["b", "x", "y"] #==> it does print the local_variables correctely.
pgm.rb:4: undefined local variable or method 'x' for main:Object (NameError)

Why? local_variables array does show me the "x", why it fail on "p x" ??


10 Answers

Eric Hodel

12/8/2004 9:52:00 PM

0

On 08 Dec 2004, at 13:44, email55555 email55555 wrote:

> I have this example codes:
>
> b = binding
> ['x', 'y'].each { |e| eval("#{e} = 123", b) }
> p local_variables
> p x
> p y
>
> Run the codes from irb, everything works.
> However, save it to a file like pgm.rb and ruby it as "ruby pgm.rb", I
> got the error message as:
> ["b", "x", "y"] #==> it does print the local_variables correctely.
> pgm.rb:4: undefined local variable or method 'x' for main:Object
> (NameError)
>
> Why? local_variables array does show me the "x", why it fail on "p x"
> ??

"name =" creates a local variable in Ruby, and you have defined no
method 'x'. They may also exist in the binding, but Ruby doesn't allow
you to get at them that way.

eval("#{e} = 123", binding) looks ugly, so you should expect strange
things to happen.



email55555 email55555

12/8/2004 10:21:00 PM

0

Hi Eric,

I know it is ugly. But:

(1) Why it works on irb and not on "ruby pgm.rb" ?

(2) What is the correct way to "dynamically" create local variable ?
For example: how to create local variables from an given local
vairable name strings array ?

Thanks.


Eric Hodel

12/8/2004 11:35:00 PM

0

On 08 Dec 2004, at 14:21, email55555 email55555 wrote:

> Hi Eric,
>
> I know it is ugly. But:
>
> (1) Why it works on irb and not on "ruby pgm.rb" ?

irb is written in Ruby, so it is not 100% identical to ruby itself.

> (2) What is the correct way to "dynamically" create local variable ?
> For example: how to create local variables from an given local
> vairable name strings array ?

What are you really trying to do? We may be able to come up with a
cleaner way of doing what you want.



Florian Gross

12/9/2004 12:35:00 AM

0

email55555 email55555 wrote:

> I know it is ugly. But:
>
> (1) Why it works on irb and not on "ruby pgm.rb" ?

IRB wraps everything you do in eval(). It also does a bunch of other
magic to make everything work correctly in common cases.

> (2) What is the correct way to "dynamically" create local variable ?
> For example: how to create local variables from an given local
> vairable name strings array ?

The problem is that Ruby decides on compile time whether 'a' refers to
the variable 'a' (if it has seen an assignment to it earlier) or whether
it is the method call 'a()'.

A solution would be to set the variable to nil before you use it, but
I think it is generally a bad idea to assign to variables of your caller.

Are you sure you can not use a Hash instead? Also note that methods in
Ruby can trivially return multiple values like this:

def plus_minus(a, b)
return(a + b, a - b)
end

sum, sub = plus_minus(1, 3)
sum # => 4
sub # => -2

email55555 email55555

12/9/2004 12:43:00 AM

0

I am learning Tk from the book "Practical Programming in Tcl and Tk".
I try to translate the book's examples from Tcl to Ruby. (as exercice
for myself)

Here is one of kind example: (TCL)

foreach name {one two three four five} {
label .$name -text $name -bg white
pack .$name -side top
}
pack .five -before .one


Ruby version: (Of course, there are many ways to write it)

%w[one two three four five].each {|name| ??? =
TkLabel.new(:text=>name, :bg=>'white') { pack(:side=>:top) } }
Tk.pack five, :before=>one ## trouble... "five", "one" are not local variables.

As you can see, the problem is how can I create local variable one,
two ... five
to correspond the 5 TkLabels immediately (dynamically)? ( what to
replace the ??? )

So, I came out by using eval binding to force automatically create
local variables base on it name.
Unfortunately, it does not work.

So, what's your suggestion? Do not using array ? write them one by one ?
or ...

variables = %w[one two three four five].map {|e|
TkLabel.new(:text=>name, :bg=>'white') {pack(:side=>:top)}}
Tk.pack variable[4] :before=>variables[0]


Florian Gross

12/9/2004 12:58:00 AM

0

email55555 email55555 wrote:

> I am learning Tk from the book "Practical Programming in Tcl and Tk".
> I try to translate the book's examples from Tcl to Ruby. (as exercice
> for myself)
>
> Here is one of kind example: (TCL)
>
> foreach name {one two three four five} {
> label .$name -text $name -bg white
> pack .$name -side top
> }
> pack .five -before .one
>
> [...]
> So, what's your suggestion? Do not using array ? write them one by one ?
> or ...
>
> variables = %w[one two three four five].map {|e|
> TkLabel.new(:text=>name, :bg=>'white') {pack(:side=>:top)}}
> Tk.pack variable[4] :before=>variables[0]

Yes, I'd use an Array like in your sample. Tk is a bit more chaotic in
this matter which is probably why they are using variables instead.

You could also use a Hash like this:

labels = Hash.new
%w[one two three four five].each do |name|
label = TkLabel.new(:text => name, :bg => 'white') do
pack(:side=>:top)
end
labels[name] = label
end

Tk.pack(label["four"], :before => label["one"])

Carlos

12/9/2004 1:27:00 AM

0

email55555 email55555 wrote:

>I have this example codes:
>
>b = binding
>['x', 'y'].each { |e| eval("#{e} = 123", b) }
>p local_variables
>p x
>p y
>
>Run the codes from irb, everything works.
>However, save it to a file like pgm.rb and ruby it as "ruby pgm.rb", I
>got the error message as:
>["b", "x", "y"] #==> it does print the local_variables correctely.
>pgm.rb:4: undefined local variable or method 'x' for main:Object (NameError)
>
>Why? local_variables array does show me the "x", why it fail on "p x" ??
>
>
>

Because ruby determines at compile time if `x' should be treated as a
method call or as a variable lookup.
If previously in the code there was an assignment to `x', then ruby
considers it a variable. But at compile time it can not eval the string,
so it thinks that `x' is a method.



Brian Schröder

12/9/2004 11:43:00 AM

0

On Thu, 9 Dec 2004 10:02:30 +0900
Florian Gross <flgr@ccan.de> wrote:

> email55555 email55555 wrote:
>
> > I am learning Tk from the book "Practical Programming in Tcl and Tk".
> > I try to translate the book's examples from Tcl to Ruby. (as exercice
> > for myself)
> >
> > Here is one of kind example: (TCL)
> >
> > foreach name {one two three four five} {
> > label .$name -text $name -bg white
> > pack .$name -side top
> > }
> > pack .five -before .one
> >
> > [...]
> > So, what's your suggestion? Do not using array ? write them one by one ?
> > or ...
> >
> > variables = %w[one two three four five].map {|e|
> > TkLabel.new(:text=>name, :bg=>'white') {pack(:side=>:top)}}
> > Tk.pack variable[4] :before=>variables[0]
>
> Yes, I'd use an Array like in your sample. Tk is a bit more chaotic in
> this matter which is probably why they are using variables instead.
>
> You could also use a Hash like this:
>
> labels = Hash.new
> %w[one two three four five].each do |name|
> label = TkLabel.new(:text => name, :bg => 'white') do
> pack(:side=>:top)
> end
> labels[name] = label
> end
>
> Tk.pack(label["four"], :before => label["one"])
>

Or even (Warning: Typed directly into the mail)


labels = %w[one two three four five].inject({}) { | result, name |
result[name] = TkLabel.new(:text => name, :bg => 'white') do
pack(:side => :top)
end
result
}

Tk.pack(label["four"], :before => label["one"])


regards,

Brian

--
Brian Schröder
http://www.brian-sch...



Florian Gross

12/9/2004 1:48:00 PM

0

Brian Schröder wrote:

> labels = %w[one two three four five].inject({}) { | result, name |
> result[name] = TkLabel.new(:text => name, :bg => 'white') do
> pack(:side => :top)
> end
> result
> }

I'm always a bit skeptic about using .inject with in-place operations --
it seems to defy its purpose. Sure, it makes code a bit shorter, but is
it really worth that? I'm not certain.

Brian Schröder

12/9/2004 2:46:00 PM

0

On Thu, 9 Dec 2004 22:52:28 +0900
Florian Gross <flgr@ccan.de> wrote:

> Brian Schröder wrote:
>
> > labels = %w[one two three four five].inject({}) { | result, name |
> > result[name] = TkLabel.new(:text => name, :bg => 'white') do
> > pack(:side => :top)
> > end
> > result
> > }
>
> I'm always a bit skeptic about using .inject with in-place operations --
> it seems to defy its purpose. Sure, it makes code a bit shorter, but is
> it really worth that? I'm not certain.
>

Thats obviously a matter of taste. I like this code, because I'm injecting a
seed and a lambda into the array thereby transforming it into something else.
To me that is what inject is all about. I don't see a fundamental difference
between the above and

(0..10).inject(0) { | r, v | r + v }

best regards,

Brian


--
Brian Schröder
http://www.brian-sch...