Eval question

Hi,

I am setting up a few variables based on user input with the following
code snippet:

···

==================================
vars = %w{a b c}

vars.each do |var|
  print "#{var} = "
  val = gets
  eval("$#{var}=#{val.chomp}")
end

#use a, b, c here for something

What I don't like about this code is the use of global variables.
However, I have to use them - or otherwise a,b,c will be already out of
scope at the place I need them.

Another possibility would be to use constants, i.e.

vars = %w{A B C}

which would work well - however, since I am repeating the process more
times, from the second iteration on I am getting warnings that A, B, C
etc were already initialized, which is not nice.

I guess yet another possibility would be to wrap a class around this
stuff and use instance_eval or something like that - but a class that
serves solely this purpose looks to heavy to me...

Any other ideas?

TIA,
Peter

__
http://www.rubyrailways.com

Peter Szinek wrote:

Hi,

I am setting up a few variables based on user input with the following
code snippet:

==================================
vars = %w{a b c}

vars.each do |var|
  print "#{var} = "
  val = gets
  eval("$#{var}=#{val.chomp}")
end

#use a, b, c here for something

What I don't like about this code is the use of global variables.
However, I have to use them - or otherwise a,b,c will be already out of
scope at the place I need them.

Use a hash?

vars = {
   "a" => nil,
   "b" => nil,
   "c" => nil,
}

def get_input vars
   vars.keys.each do |var|
     print "#{var} = "
     val = gets
     vars[var] = val.chomp
     eval("$#{var}=#{val.chomp}")
   end
end

get_input vars
p vars
__END__
a = 1
b = 2
c = 3
{"a"=>"1", "b"=>"2", "c"=>"3"}

You can use instance_eval with the hash, as you suggested:

module AcessibleKeys
   def method_missing(m, *rest)
     if rest.empty?
       fetch(m.to_s)
     else
       super
     end
   end
end

vars.extend AcessibleKeys

get_input vars
p vars

vars.instance_eval do
   puts "a+b+c = #{a+b+c}"
end
__END__
a = 1
b = 2
c = 3
{"a"=>"1", "b"=>"2", "c"=>"3"}
a+b+c = 123

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Pass a binding?

a = 1
b = 2
c = 3

def goforit(w, bind)
  w.each do |v|
    eval("#{v} = 'heehee'", bind)
  end
end

goforit %w{a b c}, binding
puts a, b, c

m.

···

Peter Szinek <peter@rubyrailways.com> wrote:

Hi,

I am setting up a few variables based on user input with the following
code snippet:

==================================
vars = %w{a b c}

vars.each do |var|
  print "#{var} = "
  val = gets
  eval("$#{var}=#{val.chomp}")
end

#use a, b, c here for something

What I don't like about this code is the use of global variables.
However, I have to use them - or otherwise a,b,c will be already out of
scope at the place I need them.

Another possibility would be to use constants, i.e.

vars = %w{A B C}

which would work well - however, since I am repeating the process more
times, from the second iteration on I am getting warnings that A, B, C
etc were already initialized, which is not nice.

I guess yet another possibility would be to wrap a class around this
stuff and use instance_eval or something like that - but a class that
serves solely this purpose looks to heavy to me...

Any other ideas?

--
matt neuburg, phd = matt@tidbits.com, Matt Neuburg’s Home Page
Tiger - http://www.takecontrolbooks.com/tiger-customizing.html
AppleScript - http://www.amazon.com/gp/product/0596102119
Read TidBITS! It's free and smart. http://www.tidbits.com

Just two tiny improvements
* Do not use globals
* Do not use eval
#!/usr/bin/ruby

vars = %w{a b c}

vars.each do |var|
    print "#{var} = "
    val = gets.chomp
    instance_variable_set "@#{var}", val
end

puts "a = #{@a}"

Maybe you prefer this?
But if you want to access the instance variables by name you can also define
an attribute_reader/writer/accessor inside the vars.each loop.

Cheers
Robert

···

On 11/11/06, Peter Szinek <peter@rubyrailways.com> wrote:

Hi,

I am setting up a few variables based on user input with the following
code snippet:

==================================
vars = %w{a b c}

vars.each do |var|
  print "#{var} = "
  val = gets
  eval("$#{var}=#{val.chomp}")
end

#use a, b, c here for something

What I don't like about this code is the use of global variables.
However, I have to use them - or otherwise a,b,c will be already out of
scope at the place I need them.

Another possibility would be to use constants, i.e.

vars = %w{A B C}

which would work well - however, since I am repeating the process more
times, from the second iteration on I am getting warnings that A, B, C
etc were already initialized, which is not nice.

I guess yet another possibility would be to wrap a class around this
stuff and use instance_eval or something like that - but a class that
serves solely this purpose looks to heavy to me...

Any other ideas?

TIA,
Peter

__

http://www.rubyrailways.com

--
The reasonable man adapts himself to the world; the unreasonable one
persists in trying to adapt the world to himself. Therefore all progress
depends on the unreasonable man.

- George Bernard Shaw

Hey Joel, that looks great! Thanks a lot (for solving the mystery of the
sprintf problem, too :slight_smile:

···

Use a hash?

vars = {
  "a" => nil,
  "b" => nil,
  "c" => nil,
}

def get_input vars
  vars.keys.each do |var|
    print "#{var} = "
    val = gets
    vars[var] = val.chomp
    eval("$#{var}=#{val.chomp}")
  end
end

get_input vars
p vars
__END__
a = 1
b = 2
c = 3
{"a"=>"1", "b"=>"2", "c"=>"3"}

You can use instance_eval with the hash, as you suggested:

module AcessibleKeys
  def method_missing(m, *rest)
    if rest.empty?
      fetch(m.to_s)
    else
      super
    end
  end
end

vars.extend AcessibleKeys

get_input vars
p vars

vars.instance_eval do
  puts "a+b+c = #{a+b+c}"
end
__END__
a = 1
b = 2
c = 3
{"a"=>"1", "b"=>"2", "c"=>"3"}
a+b+c = 123