Вам не нужен доступ к исходному определению хеша - вы можете переопределить метод [] на лету после того, как получите его с помощью h.instance_eval, например,
h = {1 => 'one'}
h.instance_eval %q{
alias :brackets :[]
def [] key
if self.has_key? key
return self.brackets(key)
else
h = Hash.new
h.default = {}
return h
end
end
}
Но это не поможет вам с кодом, который у вас есть, потому что вы полагаетесь на необнаруженное значение, чтобы вернуть ложное значение (например, ноль), и если вы делаете какой-либо из "нормальных" элементов авто-оживления, связанных выше вы получите пустой хеш для необнаруженных значений, который оценивается как "true".
Вы можете сделать что-то вроде этого - он только проверяет определенные значения и возвращает их. Вы не можете установить их таким образом, потому что у нас нет никакого способа узнать, находится ли вызов на LHS назначения.
module AVHash
def deep(*args)
first = args.shift
if args.size == 0
return self[first]
else
if self.has_key? first and self[first].is_a? Hash
self[first].send(:extend, AVHash)
return self[first].deep(*args)
else
return nil
end
end
end
end
h = {1=>2, 3=>{4=>5, 6=>{7=>8}}}
h.send(:extend, AVHash)
h.deep(0) #=> nil
h.deep(1) #=> 2
h.deep(3) #=> {4=>5, 6=>{7=>8}}
h.deep(3,4) #=> 5
h.deep(3,10) #=> nil
h.deep(3,6,7) #=> 8
Опять же, вы можете проверять только значения, но не назначать их. Так что это не настоящая автовивификация, как мы все знаем и любим в Perl.