From: "Morris, Chris" Date: 2002-05-22T21:51:28+09:00 Subject: RE: Rewrite this without using eval... > -- > class Foo > def initialize > @a = 1 > @b = 2 > end > > def inc_iv > [:@a, :@b].each { |iv| > eval "#{iv} += 1" > } > end > end > -- > > Could someone suggest a way to rewrite "inc_iv" without using > eval, without > turning the guts of the each block into a method, and without > flattening the > [:@a, :@b].each{} construct? It's interesting (and presumably you're aware of all this, but I'll ramble on cuz I've learned something here doing this...). If @a and @b reference objects that are themselves modified, then inc_iv can become: def inc_iv [@a, @b].each { |s| s.do_thing! } like: C:\temp>type rb.rb class Foo def initialize @a = 1 @b = 2 @c = 'tomato' @d = 'cucumber' end def inc_iv [:@a, :@b].each { |iv| eval "#{iv} += 1" } end def rev_str [@c, @d].each { |s| s.reverse! } end def dump p @c, @d end end f = Foo.new f.rev_str f.dump C:\temp>rb "otamot" "rebmucuc" s in its block is pointed to the same object that @c is pointed to, and the reverse! call does not redirect to a new object, but modifies the existing object. iv in its block is pointed to the same object that @a is pointed to, but the += operator always returns a new object and re-points the variable (iv) to the new object, while @a stays pointed to its original object. I hacked together MyNumeric to wrap a Numeric to allow the inc_iv to work -- it avoids eval, but requires a bit of work and most probably isn't a sufficient wrapper. (As an aside, just having the ability to so quickly do a hack like this is very cool -- Ruby is fun). C:\temp>type rb3.rb class MyNumeric def initialize(numeric) @x = numeric end def inspect @x end def method_missing(methid, *args, &block) @x = @x.send(methid, *args, &block) self end end class Foo def initialize @a = MyNumeric.new(1) @b = MyNumeric.new(2) end def inc_iv [@a, @b].each { |iv| p iv.type.name if ARGV.include?('-d') p iv.id if ARGV.include?('-d') iv += 1 p iv.type.name if ARGV.include?('-d') p iv.id if ARGV.include?('-d') } end def dump p @a, @b end end f = Foo.new f.inc_iv f.dump C:\temp>rb3 2 3 C:\temp>rb3 -d "MyNumeric" 22238768 "MyNumeric" 22238768 "MyNumeric" 22238756 "MyNumeric" 22238756 2 3 Chris