>>>>> "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)