class PrettyPrint
Diese Klasse implementiert einen Pretty-Printing-Algorithmus. Sie findet Zeilenumbrüche und schöne Einrückungen für gruppierte Strukturen.
Standardmäßig geht die Klasse davon aus, dass primitive Elemente Strings sind und jedes Byte in den Strings eine einzelne Spalte in der Breite hat. Sie kann jedoch auch für andere Situationen verwendet werden, indem geeignete Argumente für einige Methoden übergeben werden.
-
Newline-Objekt und Leerzeichen-Generierungsblock für
PrettyPrint.new -
optionales Breitenargument für
PrettyPrint#text
Es gibt mehrere Kandidaten für die Verwendung
-
Textformatierung mit proportionalen Schriftarten
-
Multibyte-Zeichen, die Spalten haben, die sich von der Anzahl der Bytes unterscheiden
-
Nicht-String-Formatierung
Fehler
-
Boxbasierte Formatierung?
-
Anderes (besseres) Modell/Algorithmus?
Melden Sie alle Fehler unter bugs.ruby-lang.org
Referenzen
Christian Lindig, Strictly Pretty, März 2000, lindig.github.io/papers/strictly-pretty-2000.pdf
Philip Wadler, A prettier printer, März 1998, homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
Autor
Tanaka Akira <akr@fsij.org>
Constants
- VERSION
-
Die Versionszeichenfolge
Attribute
Die PrettyPrint::GroupQueue von Gruppen im Stapel, die hübsch gedruckt werden sollen.
Die Anzahl der Leerzeichen für die Einrückung.
Die maximale Breite einer Zeile, bevor sie in eine neue Zeile umgebrochen wird.
Dies ist standardmäßig 79 und sollte ein Integer sein.
Der Wert, der an output angehängt wird, um eine neue Zeile hinzuzufügen.
Dies ist standardmäßig „n“ und sollte ein String sein.
Das Ausgabeobjekt.
Dies ist standardmäßig ”, sollte die Methode << akzeptieren.
Öffentliche Klassenmethoden
Source
# File lib/prettyprint.rb, line 48 def PrettyPrint.format(output=''.dup, maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) q = PrettyPrint.new(output, maxwidth, newline, &genspace) yield q q.flush output end
Dies ist eine Komfortmethode, die dasselbe tut wie die folgende.
begin q = PrettyPrint.new(output, maxwidth, newline, &genspace) ... q.flush output end
Source
# File lib/prettyprint.rb, line 85 def initialize(output=''.dup, maxwidth=79, newline="\n", &genspace) @output = output @maxwidth = maxwidth @newline = newline @genspace = genspace || lambda {|n| ' ' * n} @output_width = 0 @buffer_width = 0 @buffer = [] root_group = Group.new(0) @group_stack = [root_group] @group_queue = GroupQueue.new(root_group) @indent = 0 end
Erstellt einen Puffer für Pretty Printing.
output ist ein Ausgabeziel. Wenn es nicht angegeben ist, wird ” angenommen. Es sollte eine <<-Methode haben, die das erste Argument obj von PrettyPrint#text, das erste Argument sep von PrettyPrint#breakable, das erste Argument newline von PrettyPrint.new und das Ergebnis eines gegebenen Blocks für PrettyPrint.new akzeptiert.
maxwidth gibt die maximale Zeilenlänge an. Wenn sie nicht angegeben ist, wird 79 angenommen. Tatsächliche Ausgaben können jedoch maxwidth überschreiten, wenn lange, nicht umbrechbare Texte bereitgestellt werden.
newline wird für Zeilenumbrüche verwendet. Wenn es nicht angegeben ist, wird „n“ verwendet.
Der Block wird verwendet, um Leerzeichen zu generieren. Wenn er nicht angegeben ist, wird {|width| ‘ ’ * width} verwendet.
Source
# File lib/prettyprint.rb, line 62 def PrettyPrint.singleline_format(output=''.dup, maxwidth=nil, newline=nil, genspace=nil) q = SingleLine.new(output) yield q output end
Dies ist ähnlich wie PrettyPrint::format, aber das Ergebnis hat keine Brüche.
maxwidth, newline und genspace werden ignoriert.
Der Aufruf von breakable im Block bricht keine Zeile und wird als einfacher Aufruf von text behandelt.
Öffentliche Instanzmethoden
Source
# File lib/prettyprint.rb, line 163 def break_outmost_groups while @maxwidth < @output_width + @buffer_width return unless group = @group_queue.deq until group.breakables.empty? data = @buffer.shift @output_width = data.output(@output, @output_width) @buffer_width -= data.width end while !@buffer.empty? && Text === @buffer.first text = @buffer.shift @output_width = text.output(@output, @output_width) @buffer_width -= text.width end end end
Bricht den Puffer in Zeilen um, die kürzer als maxwidth sind.
Source
# File lib/prettyprint.rb, line 227 def breakable(sep=' ', width=sep.length) group = @group_stack.last if group.break? flush @output << @newline @output << @genspace.call(@indent) @output_width = @indent @buffer_width = 0 else @buffer << Breakable.new(sep, width, self) @buffer_width += width break_outmost_groups end end
Dies sagt: „Sie können hier bei Bedarf eine Zeile umbrechen“, und ein width-Spalten-Text sep wird eingefügt, wenn die Zeile an dieser Stelle nicht umbrochen wird.
Wenn sep nicht angegeben ist, wird „ “ verwendet.
Wenn width nicht angegeben ist, wird sep.length verwendet. Sie müssen dies angeben, wenn sep beispielsweise ein Multibyte-Zeichen ist.
Source
# File lib/prettyprint.rb, line 158 def current_group @group_stack.last end
Gibt die zuletzt zum Stapel hinzugefügte Gruppe zurück.
Abstrakte Beispiel
out = ""
=> ""
q = PrettyPrint.new(out)
=> #<PrettyPrint:0x82f85c0 @output="", @maxwidth=79, @newline="\n", @genspace=#<Proc:0x82f8368@/home/vbatts/.rvm/rubies/ruby-head/lib/ruby/2.0.0/prettyprint.rb:82 (lambda)>, @output_width=0, @buffer_width=0, @buffer=[], @group_stack=[#<PrettyPrint::Group:0x82f8138 @depth=0, @breakables=[], @break=false>], @group_queue=#<PrettyPrint::GroupQueue:0x82fb7c0 @queue=[[#<PrettyPrint::Group:0x82f8138 @depth=0, @breakables=[], @break=false>]]>, @indent=0>
q.group {
q.text q.current_group.inspect
q.text q.newline
q.group(q.current_group.depth + 1) {
q.text q.current_group.inspect
q.text q.newline
q.group(q.current_group.depth + 1) {
q.text q.current_group.inspect
q.text q.newline
q.group(q.current_group.depth + 1) {
q.text q.current_group.inspect
q.text q.newline
}
}
}
}
=> 284
puts out
#<PrettyPrint::Group:0x8354758 @depth=1, @breakables=[], @break=false>
#<PrettyPrint::Group:0x8354550 @depth=2, @breakables=[], @break=false>
#<PrettyPrint::Group:0x83541cc @depth=3, @breakables=[], @break=false>
#<PrettyPrint::Group:0x8347e54 @depth=4, @breakables=[], @break=false>
Source
# File lib/prettyprint.rb, line 215 def fill_breakable(sep=' ', width=sep.length) group { breakable sep, width } end
Dies ist ähnlich wie breakable, außer dass die Entscheidung zum Umbrechen oder Nicht-Umbrechen individuell bestimmt wird.
Zwei fill_breakable unter einer Gruppe können zu 4 Ergebnissen führen: (umbruch,umbruch), (umbruch,nicht-umbruch), (nicht-umbruch,umbruch), (nicht-umbruch,nicht-umbruch). Dies unterscheidet sich von breakable, da zwei breakable unter einer Gruppe zu 2 Ergebnissen führen können: (umbruch,umbruch), (nicht-umbruch,nicht-umbruch).
Der Text sep wird eingefügt, wenn an dieser Stelle keine Zeile umgebrochen wird.
Wenn sep nicht angegeben ist, wird „ “ verwendet.
Wenn width nicht angegeben ist, wird sep.length verwendet. Sie müssen dies angeben, wenn sep beispielsweise ein Multibyte-Zeichen ist.
Source
# File lib/prettyprint.rb, line 291 def flush @buffer.each {|data| @output_width = data.output(@output, @output_width) } @buffer.clear @buffer_width = 0 end
Gibt gepufferte Daten aus.
Source
# File lib/prettyprint.rb, line 252 def group(indent=0, open_obj='', close_obj='', open_width=open_obj.length, close_width=close_obj.length) text open_obj, open_width group_sub { nest(indent) { yield } } text close_obj, close_width end
Gruppiert Zeilenumbruchhinweise, die im Block hinzugefügt wurden. Die Zeilenumbruchhinweise werden entweder alle verwendet oder gar nicht.
Wenn indent angegeben ist, wird der Methodenaufruf als verschachtelt betrachtet durch nest(indent) { … }.
Wenn open_obj angegeben ist, wird text open_obj, open_width vor der Gruppierung aufgerufen. Wenn close_obj angegeben ist, wird text close_obj, close_width nach der Gruppierung aufgerufen.
Source
# File lib/prettyprint.rb, line 263 def group_sub group = Group.new(@group_stack.last.depth + 1) @group_stack.push group @group_queue.enq group begin yield ensure @group_stack.pop if group.breakables.empty? @group_queue.delete group end end end
Nimmt einen Block und reiht eine neue Gruppe ein, die um 1 Ebene weiter eingerückt ist.
Source
# File lib/prettyprint.rb, line 280 def nest(indent) @indent += indent begin yield ensure @indent -= indent end end
Erhöht den linken Rand nach einem Zeilenumbruch um indent für Zeilenumbrüche, die im Block hinzugefügt wurden.
Source
# File lib/prettyprint.rb, line 183 def text(obj, width=obj.length) if @buffer.empty? @output << obj @output_width += width else text = @buffer.last unless Text === text text = Text.new @buffer << text end text.add(obj, width) @buffer_width += width break_outmost_groups end end
Fügt obj als Text mit width Spalten Breite hinzu.
Wenn width nicht angegeben ist, wird obj.length verwendet.