2011-09-01 25 views
16

Próbowałem posortować plik YAML tłumaczący i18n z Ruby, dzięki czemu mogę zarządzać nowymi tłumaczeniami w lepszy i zorganizowany sposób, ale zastanawiałem się, czy jest coś, co ułatwi zadanie.Jak sortować pliki YAML?

Znalazłem pisarz pliku YAML, więc mogę napisać hasz do pliku, ale moim problemem jest prawidłowe sortowanie hasza. Jeśli mam hash h, h.sort zwraca tablicę i nadal nie wymyśliłem prosty sposób to zrobić.

mam pliki YAML tak:

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

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

... 

(Pliki są zdecydowanie większe niż to)

Ale chcę sortować je w ten sposób:

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

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

myślałem, że niektóre proste metody rekurencyjne mogą mi pomóc:

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

jest jakiś wzniosły plugin do tego samego? –

Odpowiedz

9

Właściwie to miłe pytanie. Chcesz dogłębnie sortować hasze. Więc nie lubię ponownie wymyślać koła, a potem szukałem dobrej implementacji i znalazłem taką, którą lubię. Spójrz na to https://gist.github.com/1083930. To działa dobrze.

+0

to działało, dziękuję lucapette! – AndreDurao

+0

To rozwiązanie ma sporą usterkę: sortuje wartości. – Ando

+0

Uwielbiam to rozwiązanie, ale w moim pliku Yaml nie ma podwójnych cytatów (wygląda to tak: 'sub_diagnostics_count:! '# Sous-diagnostics'', który jest nadal interpretowany jako String, ale wygląda źle). Czy jest jakieś rozwiązanie, aby poprawić tę @lucapette? – MrYoshiji

1

W hasłach Ruby 1.8 nie ma określonego zamówienia, więc nie można ich sortować.

Mogłabyś monkey-patch/nadpisać metodę to_yaml z Hash takiego:

#!/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 

Oczywiście, dokładne szczegóły mogą zależeć od wersji YAML/Ruby. Powyższy przykład dotyczy Ruby 1.8.6.

1

Oto kolejna alternatywa dla każdego, kto jest po drugiej stronie tego ..

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

Nie należy korzystać z biblioteki YAML jak sugerowano w innych odpowiedzi. Zmniejszy to formatowanie długich wartości ciągu, usunie komentarze i wypisze nieczytelne znaki, gdy użyjesz akcentów i znaków specjalnych (co zrobisz, ponieważ robisz i18n). Użyj tego gem stworzyłem:

https://github.com/redealumni/i18n_yaml_sorter

To będzie tylko sortować wiersze w pliku, więc wszystko pozostanie tak samo było na oryginalnym YAML (swoich akcentów i YAML skonstruować użyłeś aby wejść struny, wcięcia, itp.). Będzie działać z głęboko zagnieżdżonymi yamlami, a wyniki są całkiem solidne. Klejnot zawiera testy i jest dobry dla ruby ​​1.8 lub 1.9.

Jest dostarczany z pakietem TextMate (Shift + Command + S) i zadaniem prowizji Rails, dzięki czemu możesz sortować pliki łatwo i szybko w edytorze. Jest naprawdę szybki.

Aby zilustrować różnicę:

oryginalny:

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! 

wyniki Według 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." 

wyniki Według 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

Wydaje się interesujące, spróbuję! Obrigado Bernardo. – AndreDurao

+0

Po prostu próbowałem tego klejnotu do sortowania pliku config.yml i nie działało. Wynik został posortowany, ALE również inny. – Ando

+0

Ups, po wielu latach wślizgnąłem się na ten klejnot. Powodem, dla którego ten klejnot nie działa, jest to, że ignoruje odniesienia, co oznacza, że ​​zależności nie są poprawnie posortowane. Aby uczynić plik YAML odpornym na sortowanie kluczy, zmień nazwę nazwanych kluczy w taki sposób, aby pojawiły się przed odniesieniem. EG: (1) Najpierw zmieniono nazwę na 'some_key: & some_name' na' _some_key: & some_name' oraz dodano 'some_key: \ n <<: * some_name'. (2) Następnie przeniosłem wszystkie nazwane klucze i ich wartości na górę pliku oraz w razie potrzeby dodałem numery do klawiszy. Należy zauważyć, że to ręczne justowanie jest potrzebne tylko raz. – Ando

6

https://gist.github.com/1083930 nie działa zgodnie z oczekiwaniami. Głęboko sortuje NIE TYLKO klawisze skrótu, ALE RÓWNIEŻ wartości mieszania. W moich przypadkach użycia, w których konieczne jest głębokie sortowanie hasza, skrótem jest zawsze drzewo, w którym kluczami są etykiety, a wartości to (pod) drzewa (jeśli są hashami) lub liście (w przeciwnym razie). Potrzebuję dokładnego sortowania tylko etykiet drzew.

Mam ten

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}} 

z tym

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

UPDATE kwietnia 2014:

Korzystanie szyn 3 .2.13 , Ruby 1.9 .3p489:

Właśnie użyłem klejnoty i18n_yaml_sorter (https://github.com/redealumni/i18n_yaml_sorter).

Wystarczy dodać do swojej Gemfile:

gem 'i18n_yaml_sorter', group: :development 

Następnie uruchom zadanie natarcia uporządkować swoje pliki locale:

rake i18n:sort 

działało idealnie, choć gem ma Ostatni autor 2 lata temu. Trwało to maksymalnie 5 minut.

1

Istnieje również pakiet atom że zrobi to jak dobrze https://github.com/akfernun/yaml-sortkeys

+3

Link do potencjalnego rozwiązania jest zawsze mile widziany, ale proszę [dodaj kontekst związany z linkiem] (http://meta.stackoverflow.com/a/8259/169503), aby inni użytkownicy mieli pojęcie, co to jest i dlaczego jest tutaj. Zawsze podawaj najważniejszą część ważnego linku, na wypadek, gdyby strona docelowa była nieosiągalna lub stała w trybie offline. Weź pod uwagę, że bycie "stanowiącym coś więcej niż link do zewnętrznej strony" jest możliwym powodem [dlaczego i jak niektóre odpowiedzi zostały usunięte?] (Http://stackoverflow.com/help/deleted-answers). – Tunaki