From: Eric Mahurin Date: 2008-06-08T05:12:05+09:00 Subject: Re: A crosspost from the Perl Community ------=_Part_18188_8528315.1212869601222 Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Content-Disposition: inline On 6/7/08, Eric Mahurin wrote: > > Here would be an fairly efficient instance variable lvalue reference class: > > class InstanceVariable > def initialize(obj, var); @obj=obj; @var=var; end > def []; @obj.instance_variable_get(@var); end > def []=(val); @obj.instance_variable_set(@var, val); end > end > node = Object.new > node.instance_variable_set(:@next, nil) > node2 = Object.new > link = InstanceVariable.new(node, :@next) > p link[] # => nil > link[] = node2 > p link[].equal?(node2) # => true > p node.instance_variable_get(:@next).equal?(node2) # => true > > Here would be a more general class for referencing any lvalue: > > class LValue > def initialize(&lvalue); @lvalue = lvalue; end > def []; eval(@lvalue[].to_s, @lvalue.binding); end > def []=(val); eval("proc {|v| #{@lvalue[].to_s} = v}", > @lvalue.binding)[val]; end > end > > def swap(a, b); b[], a[] = a[], b[]; end > > x = 1 > y = 2 > swap(LValue.new { :x }, LValue.new { :y }) > p x # => 2 > p y # => 1 Here is a little richer and more efficient solution: class Ref def initialize(get=nil, &set); @get = get||set; @set = set; end def []; @get[]; end def []=(val); @set[val]; end end def Ref(get=nil, &set); Ref.new(get, set); end def LValue(&lvalue) Ref.new(eval("proc { #{lvalue[].to_s} }", lvalue.binding), &eval("proc { |val| #{lvalue[].to_s} = val}")) end def InstVar(obj, var) Ref.new(lambda { obj.instance_variable_get(var) }) { |val| obj.instance_variable_set(var, val) } end def Attr(obj, attr, *args) get = obj.method(attr) set = obj.method("#{attr.to_s}=") if args.empty? Ref.new(get, &set) else # curry *args Ref.new(lambda { get[*args] }) { |val| set[*(args.clone< 2 p y # => 1 x = [1, 2, 3, 4] y = [5, 6, 7, 8] swap(Attr(x, :[], 0..2), Attr(y, :[], 3..3)) # swap x[0..2] and y[3..3] p x # => [8, 4] p y # => [5, 6, 7, 1, 2, 3] x = Struct.new(:a).new(1) y = Object.new; y.instance_variable_set(:@b, 2) swap(Attr(x, :a), InstVar(y, :@b)) # swap x.a and y.@b p x.a # => 2 p y.instance_variable_get(:@b) # => 1 ------=_Part_18188_8528315.1212869601222--