Spec-Zone.ru › Elixir 1.4

Inspect.Algebra

Набор функций для создания и обработки документов алгебры.

Этот модуль реализует функциональность, описанную в «Strictly Pretty» (2000) Кристиана Линдига с небольшими дополнениями, такими как поддержка узлов String и пользовательская функция отрисовки, которая максимизирует использование горизонтального пространства.

iex> Inspect.Algebra.empty
:doc_nil

iex> "foo"
"foo"

С помощью функций этого модуля мы можем объединять различные элементы и отрисовывать их:

iex> doc = Inspect.Algebra.concat(Inspect.Algebra.empty, "foo")
iex> Inspect.Algebra.format(doc, 80)
["foo"]

Функции nest/2, space/2 и line/2 помогут вам структурировать документ. Однако алгебра документов становится интересной при использовании функций, таких как break/1, которая преобразует заданную строку в разрыв строки в зависимости от имеющегося места для печати. Давайте склеим два документа вместе с разрывом и затем отрисуем их:

iex> doc = Inspect.Algebra.glue("a", " ", "b")
iex> Inspect.Algebra.format(doc, 80)
["a", " ", "b"]

Обратите внимание, что разрыв был представлен так же, как он есть, так как мы не достигли ограничения строки. Как только это произойдёт, он заменяется символом новой строки:

iex> doc = Inspect.Algebra.glue(String.duplicate("a", 20), " ", "b")
iex> Inspect.Algebra.format(doc, 10)
["aaaaaaaaaaaaaaaaaaaa", "\n", "b"]

Наконец, этот модуль также содержит функции, связанные с Elixir, в некоторой степени связанные с форматированием Elixir, а именно surround/3 и surround_many/5.

Детали реализации

Оригинальная реализация алгоритма на Haskell Wadler полагается на ленивые вычисления для развертывания групп документов на двух альтернативах: :flat (разрывы как пробелы) и :break (разрывы как новые строки). Реализация того же логики на строгом языке, таком как Elixir, приводит к экспоненциальному росту возможных документов, если группы документов не закодированы явно как :flat или :break. Эти группы затем сводятся к простому документу, где макет уже определен, согласно Lindig.

Эта реализация немного изменяет семантику алгоритма Линдига, чтобы разрешить элементам, принадлежащим к одной группе, печататься вместе в одной строке, даже если они не помещаются в строку полностью. Это было достигнуто путем изменения :break для обозначения возможного разрыва и :flat для принудительного создания плоской структуры. Затем определение того, работает ли разрыв как новая строка, сводится к проверке, достаточно ли места до следующего разрыва, который не находится внутри группы (которая всё ещё плоская).

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

Резюме

Типы

t()

Функции

break()

Возвращает сущность документа, представляющую стандартный разрыв

break(string)

Возвращает сущность документа, представляющую разрыв, основанный на заданном string

color(doc, color_key, opts)

Изменяет цвет документа, если color_key имеет цвет в опциях

concat(docs)

Объединяет список документов, возвращая новый документ

concat(doc1, doc2)

Объединяет две сущности документа, возвращая новый документ

empty()

Возвращает сущность документа, используемую для представления пустоты

fold_doc(docs, folder_fun)

Складывает список документов в документ с использованием заданной функции складывания

format(doc, width)

Форматирует заданный документ для заданной ширины

glue(doc1, doc2)

Объединяет два документа, вставляя между ними стандартный разрыв

glue(doc1, break_string, doc2)

Объединяет два документа (doc1 и doc2) вместе, вставляя между ними заданный разрыв break_string

group(doc)

Возвращает группу, содержащую указанный документ doc

line(doc1, doc2)

Вставляет обязательный разрыв строки между двумя документами

nest(doc, level)

Вкладывает данный документ на заданный level уровень

space(doc1, doc2)

Вставляет обязательный одиночный пробел между двумя документами

surround(left, doc, right)

Оборачивает документ символами

surround_many(left, docs, right, opts, fun, separator \\ ",")

Применяет отображение и объединяет коллекцию элементов

to_doc(term, opts)

Преобразует термин Elixir в документ алгебры в соответствии с протоколом Inspect

Типы

t()

t() ::
  :doc_nil |
  :doc_line |
  doc_cons() |
  doc_nest() |
  doc_break() |
  doc_group() |
  doc_color() |
  binary()

Функции

break()

break() :: doc_break()

Возвращает сущность документа, представляющую стандартный разрыв.

То же самое, что вызов break/1 со стандартным разрывом.

break(string)

break(binary()) :: doc_break()

Возвращает сущность документа, представляющую разрыв, основанный на заданном string.

Этот разрыв может быть представлен как разрыв строки или как заданная string, в зависимости от mode выбранной компоновки или предоставленного разделителя.

Примеры

Давайте создадим документ, объединив две строки с разрывом между ними:

iex> doc = Inspect.Algebra.concat(["a", Inspect.Algebra.break("\t"), "b"])
iex> Inspect.Algebra.format(doc, 80)
["a", "\t", "b"]

Обратите внимание, что разрыв был представлен заданной строкой, так как мы не достигли ограничения строки. Как только это произойдёт, он будет заменён новой строкой:

iex> break = Inspect.Algebra.break("\t")
iex> doc = Inspect.Algebra.concat([String.duplicate("a", 20), break, "b"])
iex> Inspect.Algebra.format(doc, 10)
["aaaaaaaaaaaaaaaaaaaa", "\n", "b"]

color(doc, color_key, opts)

color(t(), Inspect.Opts.color_key(), Inspect.Opts.t()) :: doc_color()

Изменяет цвет документа, если color_key имеет цвет в опциях.

concat(docs)

concat([t()]) :: t()

Объединяет список документов, возвращая новый документ.

Примеры

iex> doc = Inspect.Algebra.concat(["a", "b", "c"])
iex> Inspect.Algebra.format(doc, 80)
["a", "b", "c"]

concat(doc1, doc2)

concat(t(), t()) :: t()

Объединяет две сущности документа, возвращая новый документ.

Примеры

iex> doc = Inspect.Algebra.concat("hello", "world")
iex> Inspect.Algebra.format(doc, 80)
["hello", "world"]

empty()

empty() :: :doc_nil

Возвращает сущность документа, используемую для представления пустоты.

Примеры

iex> Inspect.Algebra.empty
:doc_nil

fold_doc(docs, folder_fun)

fold_doc([t()], (t(), t() -> t())) :: t()

Складывает список документов в документ с использованием заданной функции складывания.

Список документов складывается «справа»; в этом случае эта функция похожа на List.foldr/3, за исключением того, что не ожидает начального аккумулятора и использует последний элемент docs в качестве начального аккумулятора.

Примеры

iex> docs = ["A", "B", "C"]
iex> docs = Inspect.Algebra.fold_doc(docs, fn(doc, acc) ->
...>   Inspect.Algebra.concat([doc, "!", acc])
...> end)
iex> Inspect.Algebra.format(docs, 80)
["A", "!", "B", "!", "C"]

format(doc, width)

format(t(), non_neg_integer() | :infinity) :: iodata()

Форматирует заданный документ для заданной ширины.

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

Примеры

iex> doc = Inspect.Algebra.glue("hello", " ", "world")
iex> Inspect.Algebra.format(doc, 30) |> IO.iodata_to_binary()
"hello world"
iex> Inspect.Algebra.format(doc, 10) |> IO.iodata_to_binary()
"hello\nworld"

glue(doc1, doc2)

glue(t(), t()) :: t()

Объединяет два документа, вставляя между ними стандартный разрыв.

Разрыв, который вставляется между left и right, - это тот, который возвращается функцией break/0.

Примеры

iex> doc = Inspect.Algebra.glue("hello", "world")
iex> Inspect.Algebra.format(doc, 80)
["hello", " ", "world"]

glue(doc1, break_string, doc2)

glue(t(), binary(), t()) :: t()

Объединяет два документа (doc1 и doc2) вместе, вставляя между ними заданный разрыв break_string.

Подробнее о том, как вставляется разрыв, см. break/1.

Примеры

iex> doc = Inspect.Algebra.glue("hello", "  ", "world")
iex> Inspect.Algebra.format(doc, 80)
["hello", " ", "world"]

group(doc)

group(t()) :: doc_group()

Возвращает группу, содержащую указанный документ doc.

Примеры

iex> doc = Inspect.Algebra.group(
...>   Inspect.Algebra.concat(
...>     Inspect.Algebra.group(
...>       Inspect.Algebra.concat(
...>         "Hello,",
...>         Inspect.Algebra.concat(
...>           Inspect.Algebra.break,
...>           "A"
...>         )
...>       )
...>     ),
...>     Inspect.Algebra.concat(
...>       Inspect.Algebra.break,
...>       "B"
...>     )
...> ))
iex> Inspect.Algebra.format(doc, 80)
["Hello,", " ", "A", " ", "B"]
iex> Inspect.Algebra.format(doc, 6)
["Hello,", "\n", "A", " ", "B"]

line(doc1, doc2)

line(t(), t()) :: t()

Вставляет обязательный разрыв строки между двумя документами.

Примеры

iex> doc = Inspect.Algebra.line("Hughes", "Wadler")
iex> Inspect.Algebra.format(doc, 80)
["Hughes", "\n", "Wadler"]

nest(doc, level)

nest(t(), non_neg_integer()) :: doc_nest()

Вкладывает данный документ на заданный level уровень.

Вложение будет добавлено к разрывам строк.

Примеры

iex> doc = Inspect.Algebra.nest(Inspect.Algebra.glue("hello", "world"), 5)
iex> Inspect.Algebra.format(doc, 5)
["hello", "\n     ", "world"]

space(doc1, doc2)

space(t(), t()) :: t()

Вставляет обязательный одиночный пробел между двумя документами.

Примеры

iex> doc = Inspect.Algebra.space("Hughes", "Wadler")
iex> Inspect.Algebra.format(doc, 5)
["Hughes", " ", "Wadler"]

surround(left, doc, right)

surround(t(), t(), t()) :: t()

Окружает документ символами.

Помещает заданный документ doc между документами left и right, заключая и вложенно его. Документ помечается как группа, чтобы максимально компактно показать все вместе.

Примеры

iex> doc = Inspect.Algebra.surround("[", Inspect.Algebra.glue("a", "b"), "]")
iex> Inspect.Algebra.format(doc, 3)
["[", "a", "\n ", "b", "]"]

surround_many(left, docs, right, opts, fun, separator \\ ",")

surround_many(t(), [any()], t(), Inspect.Opts.t(), (term(), Inspect.Opts.t() -> t()), t()) :: t()

Отображает и склеивает коллекцию элементов.

Использует заданные документы left и right в качестве окружающих, а документ-разделитель separator для разделения элементов в docs. Можно передать ограничение: когда это ограничение достигнуто, функция перестаёт склеивать и выводит "..." вместо этого.

Примеры

iex> doc = Inspect.Algebra.surround_many("[", Enum.to_list(1..5), "]",
...>         %Inspect.Opts{limit: :infinity}, fn i, _opts -> to_string(i) end)
iex> Inspect.Algebra.format(doc, 5) |> IO.iodata_to_binary
"[1,\n 2,\n 3,\n 4,\n 5]"

iex> doc = Inspect.Algebra.surround_many("[", Enum.to_list(1..5), "]",
...>         %Inspect.Opts{limit: 3}, fn i, _opts -> to_string(i) end)
iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary
"[1, 2, 3, ...]"

iex> doc = Inspect.Algebra.surround_many("[", Enum.to_list(1..5), "]",
...>         %Inspect.Opts{limit: 3}, fn i, _opts -> to_string(i) end, "!")
iex> Inspect.Algebra.format(doc, 20) |> IO.iodata_to_binary
"[1! 2! 3! ...]"

to_doc(term, opts)

to_doc(any(), Inspect.Opts.t()) :: t()

Преобразует терм Elixir в документ алгебры в соответствии с протоколом Inspect.

© 2012 Plataformatec
Licensed under the Apache License, Version 2.0.
https://hexdocs.pm/elixir/1.4.5/Inspect.Algebra.html

Spec-Zone.ru

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