Daniel Finnie
12/16/2006 11:00:00 PM
I did something like that for the current Ruby Quiz, but it doesn't do
the []=, which I think is cool. The code is a bit shorter though:
class ArrayValue
instance_methods.each do |m|
undef_method(m) unless m =~ /^_*(method_missing|send|id)_*$/
end
def initialize(origArray, origIndex)
@origArray, @origIndex = origArray, origIndex
end
def set(newObj)
@origArray[@origIndex] = newObj
end
def get
@origArray[@origIndex]
end
def method_missing(method, *args)
get.send(method, *args)
rescue
super
end
end
class Array
def to_av()
ret = []
each_index {|x| ret << ArrayValue.new(self, x) }
ret
end
end
Sample usage:
daniel@daniel-desktop:~$ irb -r 'arrayvalue.rb'
irb(main):001:0> ary = [1, 2, 3, 4, "SomeString", :ASymbol]
=> [1, 2, 3, 4, "SomeString", :ASymbol]
# Set the first String to 42.
irb(main):002:0> ary.to_av.find{|x| x.kind_of?(String)}.set(42)
=> 42
# Changes are reflected in the original array.
irb(main):003:0> ary
=> [1, 2, 3, 4, 42, :ASymbol]
# Set the 3rd Numeric value to 43
irb(main):004:0> ary.to_av.select{|x| x.kind_of?(Numeric)}[2].set(43)
=> 43
# Changes are reflected in the original array.
irb(main):005:0> ary
=> [1, 2, 43, 4, 42, :ASymbol]
Logan Capaldo wrote:
> On Sun, Dec 17, 2006 at 04:00:49AM +0900, Devin Mullins wrote:
>> Daniel Finnie wrote:
>>> How this would work:
>>> Currently, the following would default to "i" if the element doesn't exist.
>>> [4, 6, 9].fetch(4, "i")
>>> This would do the same thing:
>>> [4, 6, 9][4].default("i") or [4, 6, 9].fetch(4).default("i")
>> I get along fine with:
>> [4, 6, 9].fetch(4)||'i'
>>
>> Sure, it has false misses on instances of FalseClass, but I live with
>> the pain. Besides, what if the above array contained nil?
>>
>>> This would allow things like:
>>> ary = [4, nil, 6, nil]
>>> ary.select{|x| x.nil?}[1].set(2)
>>> ary # => [4, nil, 6, 2]
>> May I suggest:
>> ary.select{|x| x.nil?}[1] = 2
>> as a better interface.
>>
>> = isn't overridable, but []= is.
>>
>> I see more potential in your second thing... Build it as a stand-alone
>> Ruby library first.
>>
>> Devin
> Here, I'll evenget you started:
>
> % cat view.rb
> class ArrayView
> class ArrayIndexRef
> def initialize( array, index )
> @array = array
> @index = index
> end
>
> def value
> @array[@index]
> end
>
> def value=(new_value)
> @array[@index] = new_value
> end
> end
>
> def initialize( array )
> @array = array
> @references = []
> end
>
> def [](*args)
> if args.length == 1 and args.kind_of? Range or args.length > 1
> @references[*args].map { |x| x.value }
> else
> @references[*args].value
> end
> end
>
> def []=(index, value)
> @references[index].value = value
> end
>
> def each
> @references.each do |x|
> yield x.value
> end
> end
>
>
> def add_ref( index )
> @references << ArrayIndexRef.new( @array, index )
> end
> end
>
>
> class Array
> def select_view
> r = ArrayView.new( self )
> each_with_index do |item, index|
> r.add_ref( index ) if yield( item )
> end
> r
> end
> end
>
> a = (1..10).to_a
>
> p a
> b = a.select_view { |x| (x % 2).zero? }
> b[0] = 42
> p a
>
> % ruby view.rb
> [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
> [1, 42, 3, 4, 5, 6, 7, 8, 9, 10]
>
>