I Ruby 2 podrías hacer lo siguiente:
my_hash = {a: {aa: 1, ab: 2, ac: 3}} my_hash.each do |key, aa:, ab: 4, **| puts key puts aa puts ab end
En Ruby 3, esto ahora da como resultado que missing keywords :aa, :ab
. ¿Cuál sería la mejor manera de refactorizar un código como este en Ruby 3?
Algo como lo siguiente no funcionaría porque no admite la configuración de valores predeterminados:
my_hash.each do |key, values| values in {aa: aa, ab: ab} end
La mejor manera que se me ocurre es poner el código existente en un contenedor:
lambda = ->(key, aa:, ab: 4, **) do puts key puts aa puts ab end my_hash.each do |key, values| lambda.call(key, **values) end
¿Alguna opción mejor?
No puedo pensar en una forma de convertir el hash en argumentos de palabras clave.
Pero, ¿por qué no usar el hash tal como es, es decir, sin tratar sus claves como palabras clave? A menos que su código real sea más complejo, fetch
parece hacer lo que quiere:
my_hash = {a: {aa: 1, ab: 2, ac: 3}} my_hash.each do |key, values| puts key puts values.fetch(:aa) puts values.fetch(:ab, 4) end
Lo anterior funciona bien tanto en Ruby 2 como en 3. Al igual que su ejemplo, generará un error si falta :aa
y usará un valor predeterminado de 4
si falta :ab
.
||
Según lo declarado por @Stefan, no funcionará si el valor puede contener
nil
ofalse
my_hash = {a: {aa: 1, ac: 3}} my_hash.each do |key, values| puts key puts values[:aa] puts values[:ab] || 4 end
key?
my_hash = {a: {aa: 1, ac: 3}} default_values_hash = { :ab => 4 } my_hash.each do |key, values| puts key puts values[:aa] puts values.key?(:ab) ? values[:ab] : default_values_hash[:ab] end
default
my_hash = {a: {aa: 1, ab: 2, ac: 3}} my_hash.each do |key, values| values.default = :notfound puts key puts values[:aa] puts values[:ab] == :notfound ? 4 : values[:ab] end
my_hash = {a: {aa: 1, ac: 3}} my_hash.each do |key, values| values.default = :notfound puts key puts values[:aa] puts values[:ab] == :notfound ? 4 : values[:ab] end
default-proc
my_hash = {a: {aa: 1, ab: 2, ac: 3}} default_values_hash = { :ab => 4 } my_hash.each do |key, values| values.default_proc = proc { |hash, key| default_values_hash[key] || :notfound } puts key puts values[:aa] puts values[:ab] end
merge
my_hash = {a: {aa: 1, ac: 3}} default_values_hash = { :ab => 4 } my_hash.each do |key, values| values = default_values_hash.merge(values) puts key puts values[:aa] puts values[:ab] end
Todo el código anterior funciona tanto en Ruby 2 como en 3
Nota: ¿Sugeriría la key?
método para probar y verificar si existe la clave y manejar el caso en consecuencia, ya que sería mucho más rápido en comparación con otros casos que requieren pasos adicionales internamente.
Podemos asignar cada valor a una variable y verificar si es hash o no, luego podemos imprimir los valores nuevamente en el ciclo interno
my_hash = {a: { aa: 1, ab: 2, ac:3 }} may_hash.each do |key, value| puts key if value.kind_of(Hash) value.each do |inner_key, inner_value| puts inner_key puts inner_value end else puts value end end
En esto podemos refactorizar el hash externo y el hash interno al mismo tiempo.