Вот еще лучшее решение для рекурсивного слияния , которое использует уточнения и имеет метод взрыва наряду с поддержкой блоков .Этот код работает на pure Ruby.
module HashRecursive
refine Hash do
def merge(other_hash, recursive=false, &block)
if recursive
block_actual = Proc.new {|key, oldval, newval|
newval = block.call(key, oldval, newval) if block_given?
[oldval, newval].all? {|v| v.is_a?(Hash)} ? oldval.merge(newval, &block_actual) : newval
}
self.merge(other_hash, &block_actual)
else
super(other_hash, &block)
end
end
def merge!(other_hash, recursive=false, &block)
if recursive
self.replace(self.merge(other_hash, recursive, &block))
else
super(other_hash, &block)
end
end
end
end
using HashRecursive
После выполнения using HashRecursive
вы можете использовать значения по умолчанию Hash::merge
и Hash::merge!
, как если бы они не были изменены.Вы можете использовать blocks с этими методами, как и раньше.
Новым является то, что вы можете передать логический recursive
(второй аргумент) этим измененным методам, и они будут рекурсивно объединять хэши.
Пример использование для ответа на вопрос.Это очень просто:
hash_a = { :a => { :b => { :c => "d" } } }
hash_b = { :a => { :b => { :x => "y" } } }
puts hash_a.merge(hash_b) # Won't override hash_a
# output: { :a => { :b => { :x => "y" } } }
puts hash_a # hash_a is unchanged
# output: { :a => { :b => { :c => "d" } } }
hash_a.merge!(hash_b, recursive=true) # Will override hash_a
puts hash_a # hash_a was changed
# output: { :a => { :b => { :c => "d", :x => "y" } } }
Для примера advanced посмотрите этот ответ .
Также взгляните на мою рекурсивную версиюHash::each
(Hash::each_pair
) здесь .