Jano Svitok
11/12/2006 5:37:00 PM
On 11/12/06, me@mikehogan.net <me@mikehogan.net> wrote:
> Hi,
>
> How can I redefine Array#[] using an included Module? Here is my
> attempt:
>
> module AbsenceHandling
> def if_absent_call(p)
> @if_absent = p
> self
> end
>
> def [](index)
> result = old_accessor(index)
> if(result.nil? && !@if_absent.nil?)
> result = @if_absent.call(index)
> self[index]=result
> end
> result
> end
> end
>
> class Array
> alias :old_accessor :[]
> include AbsenceHandling
> end
>
>
> x = [1,2,3].if_absent_call(proc{|index|
> "#{index}"
> })
> puts x[5]
Hi,
If a class defines a method, it has higher precedence than methods of
any of its included modules. So the "override" never happens in this
case. You can work around it by defining the [] operator directly in
Array method, via Module#included and Module#define_method. You can
alias the old [] in the included as well.
module AbsenceHandling
def if_absent_call(p)
@if_absent = p
self
end
def self.included(base)
# base = Array in this case
# alias_method and define_method are private, so we must
# use the send trick
base.send(:alias_method, :old_accessor, :[])
base.send(:define_method, :[]) do |index|
result = old_accessor(index)
if(result.nil? && !@if_absent.nil?)
result = @if_absent.call(index)
self[index]=result
end
result
end
end
end
class Array
include AbsenceHandling
end
Note: [] in Array is a special case (as are some other methods in base
C classes) as sometimes their C versions are called directly for the
sake of speed. So e.g. Array#to_s will use the old []