class Object
def deep_clone
Marshal.load(Marshal.dump(self))
end
end
class Hash
def nested_key(desired_key, &block)
return false unless Hash === self
self.each_pair do |k,v|
if k == desired_key or v.nested_key(desired_key, &block)
yield(k,v)
return true
end
end
return false
end
def deep_values(key)
hash = self.deep_clone
ret = []
begin
ar = []
result = hash.nested_key(key) { |k, v| ar << k }
break unless result
ar = ar.reverse
hk = ""
ar.size.times { |i| hk << "[ar[#{i}]]" }
str = "hash" << hk
ret << eval(str)
key_to_delete = [ar.pop]
hk = ""
ar.size.times { |i| hk << "[ar[#{i}]]" }
str = "hash" << hk
str = str << ".delete(key_to_delete.first)"
eval(str)
end while result
hash.clear
ret
end
def deep_delete(key)
hash = self
begin
ar = []
result = hash.nested_key(key) { |k, v| ar << k }
break unless result
ar = ar.reverse
key_to_delete = [ar.pop]
hk = ""
ar.size.times { |i| hk << "[ar[#{i}]]" }
str = "hash" << hk
str = str << ".delete(key_to_delete.first)"
eval(str)
end while result
end
end
puts
hash = {
:level_1 => {
:level_2 => { :search => 'test1',
:level_3 => {
:search => 'test2', :level_4 => {:search => 'test3'}
}
}
}
}
require 'pp'
p hash
puts
pp hash
puts
hash.nested_key(:search) { |k, v| puts "#{k} :: #{v.inspect}" }
puts
puts "DEEP VALUES"
p hash.deep_values(:search)
puts
puts "DEEP VALUES DELETED"
hash.deep_delete(:search)
p hash
puts
puts "DEEP VALUES"
p hash.deep_values(:search)