类 PrettyPrint
此类实现了美化打印算法。它可以为分组的结构查找换行符和合适的缩进。
默认情况下,该类假定原始元素是字符串,并且字符串中的每个字节在宽度上都占单列。但是,通过为某些方法提供合适的参数,它可以用于其他情况
-
PrettyPrint.new
的换行符对象和空格生成块 -
PrettyPrint#text
的可选宽度参数
有几种可能的用法
-
使用比例字体的文本格式化
-
具有与字节数不同的列数的多字节字符
-
非字符串格式化
缺陷¶ ↑
-
基于盒子的格式化?
-
其他(更好)的模型/算法?
请在 bugs.ruby-lang.org 上报告任何错误
参考¶ ↑
Christian Lindig, Strictly Pretty, 2000 年 3 月, lindig.github.io/papers/strictly-pretty-2000.pdf
Philip Wadler, A prettier printer, 1998 年 3 月, homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier
作者¶ ↑
Tanaka Akira <akr@fsij.org>
常量
- VERSION
属性
待美化打印的堆栈中分组的 PrettyPrint::GroupQueue
要缩进的空格数
一行在被分割成换行符之前的最大宽度
默认为 79,应该是一个 Integer
附加到 output
以添加新行的值。
默认为“n”,应该是一个 String
输出对象。
默认为“”,应该接受 << 方法
公共类方法
源代码
# File lib/prettyprint.rb, line 47 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
这是一个方便的方法,与以下方法相同
begin q = PrettyPrint.new(output, maxwidth, newline, &genspace) ... q.flush output end
源代码
# File lib/prettyprint.rb, line 84 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
创建一个用于美化打印的缓冲区。
output
是一个输出目标。如果未指定,则假定为“”。它应该有一个 << 方法,该方法接受 PrettyPrint#text
的第一个参数 obj
,PrettyPrint#breakable
的第一个参数 sep
,PrettyPrint.new
的第一个参数 newline
,以及为 PrettyPrint.new
给定的块的结果。
maxwidth
指定最大行长。如果未指定,则假定为 79。但是,如果提供较长的不可中断的文本,则实际输出可能会溢出 maxwidth
。
newline
用于换行符。如果未指定,则使用“n”。
该块用于生成空格。如果未给出,则使用 {|width| ‘ ’ * width}。
源代码
# File lib/prettyprint.rb, line 61 def PrettyPrint.singleline_format(output=''.dup, maxwidth=nil, newline=nil, genspace=nil) q = SingleLine.new(output) yield q output end
这类似于 PrettyPrint::format
,但结果没有换行符。
maxwidth
、newline
和 genspace
被忽略。
块中 breakable
的调用不会换行,并且被视为只是调用 text
。
公共实例方法
源代码
# File lib/prettyprint.rb, line 162 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
将缓冲区分解为短于 maxwidth
的行
源代码
# File lib/prettyprint.rb, line 226 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
这表示“如果需要,可以在此处换行”,并且如果该点没有换行,则会插入一个 width
列的文本 sep
。
如果未指定 sep
,则使用“ ”。
如果未指定 width
,则使用 sep.length
。例如,当 sep
是一个多字节字符时,您将需要指定此值。
源代码
# File lib/prettyprint.rb, line 157 def current_group @group_stack.last end
返回最近添加到堆栈中的组。
人为示例
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>
源代码
# File lib/prettyprint.rb, line 214 def fill_breakable(sep=' ', width=sep.length) group { breakable sep, width } end
这类似于 breakable
,只是是否中断的决定是单独确定的。
一个组下的两个 fill_breakable
可能会导致 4 种结果:(中断,中断),(中断,不中断),(不中断,中断),(不中断,不中断)。这与 breakable
不同,因为一个组下的两个 breakable
可能会导致 2 种结果:(中断,中断),(不中断,不中断)。
如果此时没有换行,则会插入文本 sep
。
如果未指定 sep
,则使用“ ”。
如果未指定 width
,则使用 sep.length
。例如,当 sep
是一个多字节字符时,您将需要指定此值。
源代码
# File lib/prettyprint.rb, line 290 def flush @buffer.each {|data| @output_width = data.output(@output, @output_width) } @buffer.clear @buffer_width = 0 end
输出缓冲的数据。
源代码
# File lib/prettyprint.rb, line 251 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
对块中添加的换行提示进行分组。所有换行提示都将被使用或不使用。
如果指定了 indent
,则方法调用将被视为由 nest(indent) { … } 嵌套。
如果指定了 open_obj
,则在分组之前调用 text open_obj, open_width
。如果指定了 close_obj
,则在分组之后调用 text close_obj, close_width
。
源代码
# File lib/prettyprint.rb, line 262 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
接受一个块并排队一个缩进 1 级的新组。
源代码
# File lib/prettyprint.rb, line 279 def nest(indent) @indent += indent begin yield ensure @indent -= indent end end
对于块中添加的换行符,在换行后使用 indent
增加左边距。
源代码
# File lib/prettyprint.rb, line 182 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
这会将 obj
添加为 width
列宽度的文本。
如果未指定 width
,则使用 obj.length。