Hallo Leute,
nachdem ich gerade wieder an meinem
Papyrus-Projekt gearbeitet habe, stand ich gerade vor der netten Aufgabe, Methodennamen zu sortieren (Papyrus ist ein RDoc-Template). Das soll natürlich kurz und bündig vonstatten gehen, und ist damit eine prima Aufgabe für Code-Golf

Folgendes: Gegeben ist ein unsortiertes Array mit
RDoc::ClassModule-Objekten. Damit ihr die Doku nicht quälen müsst: Diese Klasse bietet eine Methode #method_list (und falls interessant auch #each_method) an, die ihrerseits ein unsortiertes Array von
RDoc::AnyMethod-Objekten zurückgibt. Diese wiederum bieten die Methode #pretty_name, welche den Methodennamen je nach Typ als "::foo" oder "#foo" zurückgibt. Außerdem bieten sie die Methode #full_name, welche den voll qualifizierten Methodennamen à la "Foo::Bar#foo" oder "Foo::Bar::foo" zurückgibt und #name_prefix für das Zeichen "::" oder "#" je nach Typ.
Ziel ist es nun, das ganze in der für Ruby-Dokumentation üblichen Ordnung in ein Array, das nur noch die RDoc::AnyMethod-Objekte enthält, zu sortieren. Das heißt: Auf oberster Ebene wird nach Klassen/Modulnamen geordnet (Klasse oder Modul ist gleichwertig). Innerhalb einer Klasse/Modul werden dann zunächst die Klassenmethoden gelistet, danach folgen die Instanzmethoden. Diese wiederum sollen jeweils alphabetisch sortiert sein.
Konkret also soll eine solche Ordnung entstehen:
1 2 3 4 5 6
|
Bar::class_method Bar::this_is_another_class_method Bar#instance_method Bar#instance_method2 Foo::a_class_meth Foo::Bar#an_inst_meth |
Ich hab mich schon dran versucht, aber mit dem Ergebnis bin ich nicht zufrieden.
|
ary.map{|mod| mod.method_list.sort{|m1, m2| tm1, tm2 = [m1, m2].map{|m|m.pretty_name.tr(":#", "ab")}; tm1 <=> tm2}}.flatten |
Oder im zweiten Anlauf:
|
ary.map{|mod| mod.method_list}.flatten.sort{|m1, m2| m1.full_name.tr(":#", "ab") <=> m2.full_name.tr(":#", "ab")} |
Das geht kürzer

Und weil die bloße Theorie langweilig ist, hier eine vollständige Datei, mit der ihr euren Code testen könnt:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
|
# -*- coding: utf-8 -*- require "rdoc/rdoc" require "pathname"
# Dateien und Verzeichnisse, die dokumentiert werden sollen DOC_TARGETS = [Pathname.pwd + "lib"] # Ausgabeverzeichnis OUTPUT_DIR = Pathname.pwd + "doc"
class Sorter
def initialize(options) @output_dir = Pathname.pwd.expand_path + options.op_dir end
def generate(top_levels) # Klassen und Module abgreifen (ary enthält dann die RDoc::ClassModule-Objekte) ary = RDoc::TopLevel.all_classes + RDoc::TopLevel.all_modules
# ↓↓↓ Hier meinen Sortiercode durch euren ersetzen ↓↓↓ sorted = ary.map{|mod| mod.method_list}.flatten.sort{|m1, m2| m1.full_name.tr(":#", "ab") <=> m2.full_name.tr(":#", "ab")}
# Und hier die Ausgabe File.open(@output_dir + "sorted_method_list.txt", "w") do |file| sorted.each{|meth| file.puts meth.full_name} end end
end
if __FILE__ == $0 options = RDoc::Options.new options.template = "" # Für den Minimalgenerator wird kein Template benötigt options.generator = Sorter options.files = DOC_TARGETS options.op_dir = OUTPUT_DIR RDoc::RDoc.new.document(options) end |
Einfach an der entsprechend markierten Stelle den Sortiercode einsetzen und bei DOC_TARGETS Verzeichnisse oder Ruby-Dateien auflisten, die RDoc parsen soll. Das Ergebnis liegt dann in doc/sorted_method_list.txt.
Valete,
Quintus
EDIT: Ich sehe gerade, die zweite Lösung sortiert nichts ganz richtig, der vergleicht Klassenmethoden direkt mit Klassennamen. Also bitte nicht als Referenz nehmen (aber die erste sollte tun).
_________________
Habe den Mut, dich deines eigenen
Verstandes zu bedienen! — Immanuel Kant
Mein Blog | Auf Twitter:
@qquintilianus | PGP/GPG-Schlüssel: BF3A 614B D62B A4A0 C292 141C B875 5CB1
C592 A85AHelft beim OpenRubyRMK, einem freien Programm zum erstellen von RPGs! (
→ GitHub-Projekt)