Spec-Zone.ru › Ruby 2.2

класс PrettyPrint

Родитель:
Объект

Этот класс реализует алгоритм красивой печати. Он находит переводы строк и хорошие отступы для группированных структур.

По умолчанию класс предполагает, что примитивные элементы являются строками, и каждый байт в строках имеет ширину в одну колонку. Но его можно использовать и в других ситуациях, передав соответствующие аргументы для некоторых методов:

  • объект перевода строки и блок генерации пробелов для ::new

  • опциональный аргумент ширины для #text

  • #breakable

Существует несколько возможных применений:

  • форматирование текста с использованием пропорциональных шрифтов

  • многобайтовые символы, у которых количество колонок отличается от количества байтов

  • форматирование, не связанное со строками

Ошибки

  • Форматирование на основе прямоугольников?

  • Другая (лучшая) модель/алгоритм?

Сообщите об ошибках на сайте bugs.ruby-lang.org

Ссылки

Christian Lindig, Строго красивая печать, март 2000, www.st.cs.uni-sb.de/~lindig/papers/#pretty

Philip Wadler, Более красивый принтер, март 1998, homepages.inf.ed.ac.uk/wadler/topics/language-design.html#prettier

Автор

Tanaka Akira <akr@fsij.org>

Атрибуты

genspace[R]

Lambda или Proc, принимающий один аргумент типа Fixnum и возвращающий соответствующее число пробелов.

По умолчанию это:

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

PrettyPrint::GroupQueue групп в стеке для красивой печати

indent[R]

Количество пробелов для отступа

maxwidth[R]

Максимальная ширина строки, прежде чем она разделяется новой строкой

По умолчанию 79, и должно быть Fixnum

newline[R]

Значение, которое добавляется к output для добавления новой строки.

По умолчанию «n», и должно быть String

output[R]

Объект вывода.

По умолчанию '', и должен принимать метод <<

Общественные методы класса

format(output='', maxwidth=79, newline="\n", genspace=lambda {|n| ' ' * n}) { |q| ... } Показать исходный код
# File lib/prettyprint.rb, line 43
def PrettyPrint.format(output='', 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
new(output='', maxwidth=79, newline="\n", &genspace) Показать исходный код
# File lib/prettyprint.rb, line 80
def initialize(output='', 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 является целевым объектом вывода. Если он не указан, предполагается ''. Он должен иметь метод <<, который принимает первый аргумент obj метода #text, первый аргумент sep метода #breakable, первый аргумент newline метода ::new и результат заданного блока для ::new.

maxwidth задаёт максимальную длину строки. Если она не указана, предполагается 79. Однако фактические выводы могут превышать maxwidth, если предоставлены длинные неразрывные тексты.

newline используется для разрывов строк. Если не указано, используется «n».

Блок используется для генерации пробелов. {|width| ' ' * width} используется, если он не задан.

singleline_format(output='', maxwidth=nil, newline=nil, genspace=nil) { |q| ... } Показать исходный код
# File lib/prettyprint.rb, line 57
def PrettyPrint.singleline_format(output='', maxwidth=nil, newline=nil, genspace=nil)
  q = SingleLine.new(output)
  yield q
  output
end

Это аналогично ::format, но результат не имеет разрывов.

maxwidth, newline и genspace игнорируются.

Вызов breakable в блоке не разрывает строку и обрабатывается как просто вызов text.

Общественные методы экземпляра

break_outmost_groups() Показать исходный код
# File lib/prettyprint.rb, line 158
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

breakable(sep=' ', width=sep.length) Показать исходный код
# File lib/prettyprint.rb, line 222
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 не указано, используется « ».

Если width не указано, используется sep.length. Вам нужно будет указать это, когда sep — многобайтовый символ, например.

current_group() Показать исходный код
# File lib/prettyprint.rb, line 153
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>
fill_breakable(sep=' ', width=sep.length) Показать исходный код
# File lib/prettyprint.rb, line 210
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 — многобайтовый символ, например.

flush() Показать исходный код
# File lib/prettyprint.rb, line 286
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) { || ... } Показать исходный код
# File lib/prettyprint.rb, line 247
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 вызывается после группировки.

group_sub() { || ... } Показать исходный код
# File lib/prettyprint.rb, line 258
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 уровень.

nest(indent) { || ... } Показать исходный код
# File lib/prettyprint.rb, line 275
def nest(indent)
  @indent += indent
  begin
    yield
  ensure
    @indent -= indent
  end
end

Увеличивает отступ слева после новой строки с indent для разрывов строк, добавленных в блоке.

text(obj, width=obj.length) Показать исходный код
# File lib/prettyprint.rb, line 178
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.

Ruby Core © 1993–2017 Yukihiro Matsumoto
Licensed under the Ruby License.
Ruby Standard Library © contributors
Licensed under their own licenses.

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API