Ao lidar com hashes, o Rails expõe um método bacana chamado except
que duplica o hash original e retorna sua cópia removendo os argumentos fornecidos.
Eu queria expor um operador semelhante para excluir hashes dentro de hashes dada a chave aninhada. Tentei abordar o problema duplicando ingenuamente o except
método do Rails :
class Hash
def except_nested_key(key)
dup.except_nested_key!(key)
end
def except_nested_key!(key)
each { (k, v) v.delete(key) if v.is_a? Hash }
self
end
end
O problema com essa abordagem é que ambos dup
e clone
fazem uma cópia superficial do objeto, o que significa que, embora as referências do objeto original estejam sendo copiadas, os objetos aos quais essas referências se referem não estão. O que significa que, independentemente do método chamado, ambos executam ações destrutivas no objeto original.
Felizmente, podemos conseguir uma cópia profunda graças a Marshal . Da documentação Ruby:
“A biblioteca de empacotamento converte coleções de objetos Ruby em um fluxo de bytes, permitindo que sejam armazenados fora do script atualmente ativo. Esses dados podem ser lidos posteriormente e os objetos originais reconstituídos.”
Fazendo uso de Marshal, podemos reimplementar o método anterior da seguinte forma:
class Hash
def except_nested_key(key)
copy = Marshal.load(Marshal.dump(self))
copy.each { |(k, v)| v.delete(key) if v.is_a? Hash }
end
end