From: "Michael W. Ryder" <_mwryder@...> Date: 2009-03-15T08:47:56+09:00 Subject: Re: Problem With eval and each_index matt neuburg wrote: > Michael W. Ryder <_mwryder@worldnet.att.net> wrote: > >> I am trying to set a group of variables to values stored in a tab >> delimited string. I have no problem splitting the string into an array, >> call it e, or in putting the variable names in a second array, call it >> v. The problem arises when I try to merge the two together. If I enter: >> irb(main):073:0> p v >> ["name", "street", "city", "state", "zip", "*", "telephone"] >> => nil >> irb(main):074:0> p e >> ["John Doe", "123 Main St", "Anywhere", "US", "01234-5678", "ab123", >> "1234567890"] >> => nil >> irb(main):075:0> eval "#{v[0]} = e[0]" >> => "John Doe" >> irb(main):076:0> p name >> "John Doe" >> => nil >> >> it works as I want. But when I try: >> irb(main):077:0> v.each_index {|i| eval "#{v[i]} = e[0]"} >> => ["name", "street", "city", "state", "zip", "*", "telephone"] >> >> and then enter: puts zip >> it returns with a NameError saying that the variable was undefined. > > Inside a block, local variables are local to the block. So, you're > creating all those local variables and then the block ends and they are > all thrown away. > I can see that if I create the variable before running the method the variable is set even after the method ends. Which of course brings up the question of why is the change visible outside of the block? This behavior is almost like a mix of C and Basic. You have to define a variable in C before you can use it and in Basic once a variable is set it is always visible. > Why do you need variables called "name" (etc.) anyway? Why not use a > hash, so that h["name"] contains the name ("John Doe"), h["street"] > contains the street, and so on? So: > I have been programming in Business Basic for over 20 years and am used to reading a file with a statement like: Read(1,Key="1234")Name$,Street$,City$,State$,Zip$,*,Telephone$ and then using those variables. I was trying to use what I am familiar with while learning Ruby. I realize in Ruby I would have to do read the string of data in, split it on the separator, and then assign it to the proper variables. Using a hash was an option but seemed to be more typing to use as I would have to enter: puts h["name"] vs puts name. > h = Hash.new > v.zip(e).each {|k,v| h[k]=v} > > Notice that even here we define h before we get to the block. That way, > the block's h is our h; it is global to the block. > > An even cooler approach is a struct: > > Person = Struct.new(*(v.map {|i| i.to_sym})) > p = Person.new(*e) > > Now you've got an object, p, where p.name is "John Doe" and so on. > I might try this for some things as it seems more logical than the hash for what I normally do. Thanks for the tip. I hadn't got into structures yet. > m.