2011-09-01 34 views
16

He intentado ordenar un archivo YAML de traducciones i18n con Ruby para poder administrar nuevas traducciones de una manera mejor y organizada, pero me he estado preguntando si hay algo para facilitar la tarea.¿Cómo puedo ordenar los archivos YAML?

Encontré una grabadora de archivos YAML para poder escribir un hash en un archivo, pero mi problema es ordenar el hash correctamente. Si obtuve hash h, h.sort devuelve una matriz y todavía no he encontrado una forma sencilla de hacerlo.

Tengo archivos YAML como este:

pt-br:  
    global: 
    misc: 
     total: "Total" 
     all: "Todos" 
     close: "Fechar" 
     cancel: "Cancelar" 

    crud: 
     access: "Acessar" 
     back: "Voltar" 
     edit: "Editar" 
     confirm: "Confirmar" 
     send: "Enviar" 

... 

(Los archivos son mucho más grande que esto)

pero quiero que los clasifique de esta manera:

pt-br:  
    global: 
    crud: 
     access: "Acessar" 
     back: "Voltar" 
     confirm: "Confirmar" 
     edit: "Editar" 
     send: "Enviar" 

    misc: 
     all: "Todos" 
     cancel: "Cancelar" 
     close: "Fechar"   
     total: "Total" 

pensé que algún método recursivo simple podría ayudarme así:

def translation_sort(h) 
    if h.class == Hash 
    h = h.sort 
    h.each{|item| translation_sort(item)} 
    end 
    h 
end 

require "yaml" 
h=YAML.load_file(File.open("~/pt-br.sample.yml")) 
translation_sort(h) 
+0

hay ningún plugin sublime para el mismo? –

Respuesta

9

En realidad esta es una buena pregunta. Quieres hacer hashes profundos. Así que no me gusta reinventar la rueda y luego busqué una buena implementación y encontré una que me gusta. Échale un vistazo https://gist.github.com/1083930. Funciona bien.

+0

funcionó, gracias lucapette! – AndreDurao

+0

Esta solución tiene un problema: también ordena los valores. – Ando

+0

Me encanta esta solución pero no hay comillas dobles en mi archivo Yaml (se parece a esto: 'sub_diagnostics_count: '# Sous-diagnostics'' que todavía se interpreta como cuerdas, pero se ve mal). ¿Hay alguna solución para corregir esa @lucapette? – MrYoshiji

1

En Ruby 1.8 hashes no tienen un orden en particular, por lo que no puede simplemente ordenarlos.

Usted podría mono-parche/sobrescribir el método de to_yamlHash así:

#!/usr/local/bin/ruby -w 

require 'yaml' 

class Hash 
    def to_yaml(opts = {}) 
    YAML::quick_emit(self, opts) do |out| 
     out.map(taguri, to_yaml_style) do |map| 
     keys.sort.each do |k| 
      v = self[k] 
      map.add(k, v) 
     end 
     end 
    end 
    end 
end 

dict = YAML.load($<.read) 

puts dict.to_yaml 

Por supuesto, los detalles exactos pueden depender de la versión de YAML/Ruby. El ejemplo anterior es para Ruby 1.8.6.

1

Aquí hay otra alternativa para cualquier otra persona que se encuentra con este ..

require 'yaml' 

yaml = YAML.load(IO.read(File.join(File.dirname(__FILE__), 'example.yml'))) 

@yml_string = "---\n" 

def recursive_hash_to_yml_string(hash, depth=0) 
    spacer = "" 
    depth.times { spacer += " "} 
    hash.keys.sort.each do |sorted_key| 
    @yml_string += spacer + sorted_key + ": " 
    if hash[sorted_key].is_a?(Hash) 
     @yml_string += "\n" 
     recursive_hash_to_yml_string(hash[sorted_key], depth+1) 
    else 
     @yml_string += "#{hash[sorted_key].to_s}\n" 
    end 
    end 
end 

recursive_hash_to_yml_string(yaml) 

open(File.join(File.dirname(__FILE__), 'example.yml'), 'w') { |f| 
    f.write @yml_string 
} 
9

no debería usar la biblioteca YAML como se sugiere en las otras respuestas. Perjudicará el formateo de los valores de cadena larga, eliminará sus comentarios y escupirá escapes de caracteres ilegibles cuando use acentos y caracteres especiales (lo cual hará, ya que está haciendo i18n). Utilice esta joya que creó:

https://github.com/redealumni/i18n_yaml_sorter

Sólo se clasificará las líneas en el archivo, por lo que todo seguirá siendo la misma forma en que estaba en la yaml originales (los acentos, el YAML construcción que utilizó para entrar las cuerdas, sangría, etc.). Funcionará con yamls profundamente anidados y los resultados son bastante sólidos. La gema incluye pruebas y es bueno para ruby ​​1.8 o 1.9.

Viene con un paquete TextMate (Shift + Command + S) y una tarea de raíles Rails para que pueda ordenar los archivos de forma fácil e instantánea en su editor. Es realmente rápido

Para ilustrar la diferencia:

original:

pt-BR: 
    # Note how this is a nice way of inputing 
    # paragraphs of text in YAML. 
    apples: > 
     Maçãs são boas, 
     só não coma 
     seus iPods! 
    grapes: Não comemos elas. 
    bananas: | 
     Bananas são "legais": 
     - Elas são <b> doces </b>. 
     isto: não é chave 

     Por isto todos gostam de bananas! 

Resultados por YAML :: dump:

pt-BR: 
    apples: "Ma\xC3\xA7\xC3\xA3s s\xC3\xA3o boas, s\xC3\xB3 n\xC3\xA3o coma seus iPods!\n" 
    bananas: "Bananas s\xC3\xA3o \"legais\":\n - Elas s\xC3\xA3o <b> doces </b>.\n isto: n\xC3\xA3o \xC3\xA9 chave\n\n\ Por isto todos gostam de bananas!\n" 
    grapes: "N\xC3\xA3o comemos elas." 

Resultados por i18n_yaml_sorter:

pt-BR: 
    # Note how this is a nice way of inputing 
    # paragraphs of text in YAML. 
    apples: > 
     Maçãs são boas, 
     só não coma 
     seus iPods! 
    bananas: | 
     Bananas são "legais": 
     - Elas são <b> doces </b>. 
     isto: não é chave 

     Por isto todos gostam de bananas! 
    grapes: Não comemos elas. 
+0

parece interesante, voy a intentarlo! Obrigado Bernardo. – AndreDurao

+0

he intentado esta joya para clasificar un archivo config.yml y no funcionó. El resultado fue ordenado PERO también diferente. – Ando

+0

Vaya, me resbalé en esta joya de nuevo, después de muchos años. La razón por la cual esta gema no funciona es porque ignora las referencias, lo que significa que las dependencias no están ordenadas correctamente. Para hacer que su archivo YAML sea resistente a la clasificación de claves, cambie el nombre de las claves con nombre de forma que aparezcan antes de hacer referencia a ellas. EG: (1) Primero renombré 'some_key: & some_name' a' _some_key: & some_name' y agregué 'some_key: \ n <<: * some_name'. (2) Luego moví todas las claves con nombre y sus valores a la parte superior del archivo, y agregué números a las claves cuando era necesario. Tenga en cuenta que este ajuste manual solo se necesita una vez. – Ando

6

https://gist.github.com/1083930 no está funcionando como esperaba. Profundamente ordena NO SOLAMENTE las claves hash PERO TAMBIÉN los valores hash. En mis casos de uso en la clasificación de profundidad un hash que se necesita, el hash es siempre un árbol donde las claves son las etiquetas y los valores son (sub) árboles (si los hashes) o las hojas (de lo contrario). Necesito ordenar profundamente solo las etiquetas de los árboles.

Tengo este

before: {"a":[2,10,{"5":null,"1":null,"3":null}],"x":{"5":null,"1":null,"3":null},"a2":{"5":[2,10,5],"1":null,"3":null}} 
after: {"a":[2,10,{"5":null,"1":null,"3":null}],"a2":{"1":null,"3":null,"5":[2,10,5]},"x":{"1":null,"3":null,"5":null}} 

con este

require 'active_support' 

def deeply_sort_hash(object) 
    return object unless object.is_a?(Hash) 
    hash = RUBY_VERSION >= '1.9' ? Hash.new : ActiveSupport::OrderedHash.new 
    object.each { |k, v| hash[k] = deeply_sort_hash(v) } 
    sorted = hash.sort { |a, b| a[0].to_s <=> b[0].to_s } 
    hash.class[sorted] 
end 
6

actualización de abril de 2014:

Usando Rails 3 .2.13 , Ruby 1.9 .3p489:

Acabo de utilizar la gema i18n_yaml_sorter (https://github.com/redealumni/i18n_yaml_sorter).

Basta con añadir a su Gemfile:

gem 'i18n_yaml_sorter', group: :development 

A continuación, ejecute la tarea rastrillo para ordenar los archivos de sus locales':

rake i18n:sort 

funcionado perfectamente, a pesar de que la gema tiene sido el último autor de hace 2 años. Tardaron 5 minutos como máximo.

1

También hay un paquete átomo que va a hacer esto, así https://github.com/akfernun/yaml-sortkeys

+3

Un enlace a una posible solución siempre es bienvenido, pero por favor [agregue contexto alrededor del enlace] (http://meta.stackoverflow.com/a/8259/169503) para que los demás usuarios tengan una idea de qué es y por qué está allá. Siempre cite la parte más relevante de un enlace importante, en caso de que el sitio objetivo no esté disponible o esté permanentemente fuera de línea. Tenga en cuenta que ser apenas más que un enlace a un sitio externo es una posible razón para [¿Por qué y cómo se eliminan algunas respuestas?] (Http://stackoverflow.com/help/deleted-answers). – Tunaki

Cuestiones relacionadas