PrettyPrint 類別

此類別實作漂亮列印演算法。它會為群組結構尋找換行符號和漂亮的縮排。

預設情況下,類別會假設原始元素為字串,且字串中的每個位元組寬度為單一欄位。但它可透過提供一些方法的合適引數,用於其他情況

有幾個候選用途

錯誤

請在 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 <[email protected]>

常數

VERSION

屬性

genspace[R]

一個 lambda 或 Proc,它會接收一個引數,為 Integer,並傳回對應的空白數。

預設為

lambda {|n| ' ' * n}
group_queue[R]

要漂亮列印的 PrettyPrint::GroupQueue 堆疊群組

indent[R]

要縮排的空白數

maxwidth[R]

換行前,一行文字的最大寬度

預設為 79,應為 Integer

newline[R]

附加到 output 以換行的值。

預設為「n」,應為 String

output[R]

輸出物件。

預設為「」,應接受 << 方法

公開類別方法

format(output=''.dup, maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) { |q| ... } 按一下以切換來源

這是一個便利方法,與下列相同

begin
  q = PrettyPrint.new(output, maxwidth, newline, &genspace)
  ...
  q.flush
  output
end
# 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
new(output=''.dup, maxwidth=79, newline="\n", &genspace) 按一下以切換來源

建立一個用於美化列印的緩衝區。

output 是輸出目標。如果未指定,則假設為「」。它應有一個 << 方法,該方法接受 PrettyPrint#text 的第一個引數 objPrettyPrint#breakable 的第一個引數 sepPrettyPrint.new 的第一個引數 newline,以及 PrettyPrint.new 給定區塊的結果。

maxwidth 指定最大行長度。如果未指定,則假設為 79。但是,如果提供了長且不可換行的文字,實際輸出可能會超過 maxwidth

newline 用於換行。如果未指定,則使用「n」。

該區塊用於產生空格。如果未給定,則使用 {|width| ‘ ’ * width}。

# 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
singleline_format(output=''.dup, maxwidth=nil, newline=nil, genspace=nil) { |q| ... } 按一下以切換來源

這類似於 PrettyPrint::format,但結果沒有換行。

maxwidthnewlinegenspace 會被忽略。

在區塊中呼叫 breakable 不會換行,而只會視為呼叫 text

# 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

公開實例方法

break_outmost_groups() 按一下以切換來源

將緩衝區換成小於 maxwidth 的行

# 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
breakable(sep=' ', width=sep.length) 按一下以切換來源

這表示「必要時您可以在此處斷行」,而且如果未在該點斷行,則會插入一個 width 欄位文字 sep

如果未指定 sep,則會使用「 」。

如果未指定 width,則會使用 sep.length。例如,當 sep 是多位元組字元時,您必須指定此值。

# 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
current_group() 按一下以切換來源

傳回最近新增至堆疊的群組。

虛構範例

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 157
def current_group
  @group_stack.last
end
fill_breakable(sep=' ', width=sep.length) 按一下以切換來源

這類似於 breakable,但個別決定是否斷行。

群組下的兩個 fill_breakable 可能導致 4 個結果:(斷行、斷行)、(斷行、不斷行)、(不斷行、斷行)、(不斷行、不斷行)。這與 breakable 不同,因為群組下的兩個 breakable 可能導致 2 個結果:(斷行、斷行)、(不斷行、不斷行)。

如果未在此點斷行,則會插入文字 sep

如果未指定 sep,則會使用「 」。

如果未指定 width,則會使用 sep.length。例如,當 sep 是多位元組字元時,您必須指定此值。

# File lib/prettyprint.rb, line 214
def fill_breakable(sep=' ', width=sep.length)
  group { breakable sep, width }
end
flush() 按一下以切換來源

輸出緩衝資料。

# File lib/prettyprint.rb, line 290
def flush
  @buffer.each {|data|
    @output_width = data.output(@output, @output_width)
  }
  @buffer.clear
  @buffer_width = 0
end
group(indent=0, open_obj='', close_obj='', open_width=open_obj.length, close_width=close_obj.length) { || ... } 按一下以切換來源

群組在區塊中新增的斷行提示。所有斷行提示都必須使用或不使用。

如果指定 indent,則方法呼叫會被視為由 nest(indent) { … } 巢狀。

如果指定 open_obj,則會在群組化之前呼叫 text open_obj, open_width。如果指定 close_obj,則會在群組化之後呼叫 text close_obj, close_width

# 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
group_sub() { || ... } 按一下以切換來源

取得區塊並排入一個新的群組,該群組的縮排再深入 1 個層級。

# 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
nest(indent) { || ... } 按一下以切換來源

在區塊中新增換行符號後,使用 indent 增加左側邊界。

# File lib/prettyprint.rb, line 279
def nest(indent)
  @indent += indent
  begin
    yield
  ensure
    @indent -= indent
  end
end
text(obj, width=obj.length) 按一下以切換來源

這會將 obj 新增為寬度為 width 欄位的文字。

如果未指定 width,則會使用 obj.length。

# 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