>>>>> "Jeff" == Jeff Gray <Gray> writes:

    Jeff> I happened upon a situation where I wanted to apply a sequence of operations
    Jeff> to two instance variables without replicating the code.  Here's the trivial
    Jeff> equivalent case, written using eval:
    Jeff> --
    Jeff> class Foo
    Jeff>   def initialize
    Jeff>     @a = 1
    Jeff>     @b = 2
    Jeff>   end

    Jeff>   def inc_iv
    Jeff>     [:@a, :@b].each { |iv|
    Jeff>       eval "#{iv} += 1"
    Jeff>     }
    Jeff>   end
    Jeff> end
    Jeff> --

    Jeff> Could someone suggest a way to rewrite "inc_iv" without
    Jeff> using eval, without turning the guts of the each block into
    Jeff> a method, and without flattening the [:@a, :@b].each{}
    Jeff> construct?

Interesting problem.  Here's one solution, but you might find it a bit
verbose....


    class Ref
      def initialize(getter, setter)
        @getter, @setter = getter, setter
      end
      def value
        @getter.call
      end
      def value=(new_value)
        @setter.call(new_value)
      end
    end
    
    class Foo
      attr_reader :a, :b
    
      def initialize
        @a = 1
        @b = 2
      end
    
      def inc_iv
        [ Ref.new(proc {@a}, proc {|v| @a = v }),
          Ref.new(proc {@b}, proc {|v| @b = v })
        ].each { |iv|
          iv.value += 1
        }
      end
    end
    
    f = Foo.new
    f.inc_iv
    p f.a
    p f.b

If you find the Ref.new(...) syntax a little verbose, you could write
a function to generate it automatically, but that function would
probably have to use eval ;-)

-- 
-- Jim Weirich     jweirich / one.net    http://w3.one.net/~jweirich
---------------------------------------------------------------------
"Beware of bugs in the above code; I have only proved it correct, 
not tried it." -- Donald Knuth (in a memo to Peter van Emde Boas)