Spec-Zone.ru › Ruby 2.5

класс 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]

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

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

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

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

singleline_format(output=''.dup, maxwidth=nil, newline=nil, genspace=nil) { |q| ... } Показать исходный код
# File lib/prettyprint.rb, line 58
def PrettyPrint.singleline_format(output=''.dup, 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 159
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 223
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 154
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 211
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 287
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 248
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 259
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 276
def nest(indent)
  @indent += indent
  begin
    yield
  ensure
    @indent -= indent
  end
end

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

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