2011-08-21 12 views
11

La biblioteca Rails I18n transforma un archivo YAML en una estructura de datos a la que se puede acceder mediante una llamada de ruta de puntos mediante la función t().Acceso a Ruby Hash mediante el uso de la secuencia de puntos clave

t('one.two.three.four') 

¿Alguien sabe cómo hacer esto con un Ruby Hash? ¿O solo es posible directamente a través de un objeto YAML?

Respuesta

22

Sólo dividir en un punto en la ruta y iterar sobre esto para encontrar el hash correcto?

path.split(".").inject(hash) { |hash, key| hash[key] } 

alternativa, se puede construir una nueva almohadilla por iteración recursiva sobre toda la estructura:

def convert_hash(hash, path = "") 
    hash.each_with_object({}) do |(k, v), ret| 
    key = path + k 

    if v.is_a? Hash 
     ret.merge! convert_hash(v, key + ".") 
    else 
     ret[key] = v 
    end 
    end 
end 
10

Sí, no creo que esté incorporado, en ningún otro lado. Pero yo uso algo como esto en uno de mis proyectos:

class Hash 
    def dig(dotted_path) 
    parts = dotted_path.split '.', 2 
    match = self[parts[0]] 
    if !parts[1] or match.nil? 
     return match 
    else 
     return match.dig(parts[1]) 
    end 
    end 
end 

Y entonces lo llamo como

my_hash = {'a' => {'b' => 'a-b', 'c' => 'a-c', 'd' => {'e' => 'a-d-e'}}, 'f' => 'f'} 
my_hash.dig('a.d.e') # outputs 'a-d-e' (by calling my_hash['a']['d']['e']) 
+2

un método similar ahora está disponible en Ruby 2.3 y se llama exactamente [dig] (http://ruby-doc.org/core-2.3.0/Hash.html#method-i-dig) –

1

que sugeriría un vistazo a este GIST:
https://gist.github.com/potatosalad/760726

Se añade implode y explode métodos para el objeto Hash que transforma las claves anidadas en claves de ruta de puntos de un solo nivel, y viceversa.

2

Hay una gema demasiado keypath-ruby

gem 'key_path', :git => 'https://github.com/nickcharlton/keypath-ruby.git' 

Si examina el código (y adivinar un poco sobre lo t es), parece que usted puede hacer esto:

t.value_at_keypath('one.two.three.four') 
0

También existe HashDot.

HashDot permite el uso de la sintaxis de notación de puntos en hash. Es más rápido y más transitable que un objeto creado con OpenStruct.

a = {b: {c: {d: 1}}} 
a.b.c.d => 1 
2

Este código no sólo permite la notación de puntos para recorrer un Hash sino también entre corchetes para atravesar matrices con índices. También evita la recursión por eficiencia.

class Hash 

    def key_path(dotted_path) 
    result = self 
    dotted_path.split('.').each do |dot_part| 
     dot_part.split('[').each do |part| 
     if part.include?(']') 
      index = part.to_i 
      result = result[index] rescue nil 
     else 
      result = result[part] rescue nil 
     end 
     end 
    end 

    result 
    end 

end 

Ejemplo:

a = {"b" => {"c" => [0, [1, 42]]}} 
a.key_path("b.c[-1][1]") # => 42 
6

Rubí 2.3 introduce el dig method que mira en anidados arrays/hashes, devuelve nil cuando no se encuentran datos.

Por ejemplo:

test_data = {a: {b: {c: {d: 1}, e: 2}}} 
path = 'a.b.c.d'.split('.').map(&:to_sym) 
# path => [:a, :b, :c, :d] 
test_data.dig(*path) 

Por supuesto, si las teclas de uso de cadenas anidadas, no se necesita el paso to_sym.

Cuestiones relacionadas