prettyprint

package module
v0.0.0-...-c98cbe8 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 17, 2026 License: BSD-3-Clause Imports: 1 Imported by: 0

README

go-ruby-prettyprint/prettyprint

prettyprint — go-ruby-prettyprint

Docs License Go Coverage

A pure-Go (no cgo) reimplementation of Ruby's prettyprint standard library — the Wadler/Lindig pretty-printing engine that lays out a stream of text, breakable separators and groups into a width-constrained, nicely indented document. It is a faithful, byte-identical port of MRI 4.0.5's prettyprint.rb: each group prints on one line when it fits within the maximum width and is otherwise broken at its breakable points, with nesting preserved — without any Ruby runtime.

It is the layout backend for go-embedded-ruby (rbgo), a standalone, reusable module with no dependency on the Ruby runtime — a sibling of go-ruby-yaml, go-ruby-regexp and go-ruby-marshal.

What it is — and isn't. This is the layout engine only — the deterministic group/breakable/indent/width-fitting algorithm (the buffer, the group stack and the depth-bucketed group queue). The pp object inspector that uses it — walking an object graph and emitting text/group/breakable calls — is the host's job and stays in rbgo. This library is the standalone Go backend pp binds to.

Features

Faithful port of PrettyPrint, validated against the ruby binary on every supported platform:

  • Groups that print flat when they fit and break at their breakables when they overflow maxwidth — the exact break_outmost_groups / depth-bucketed GroupQueue algorithm MRI uses, so nested groups break outermost-first.
  • Breakablesbreakable(sep, width) line-break hints that emit their separator when the line is not broken, with the width argument for multibyte or proportional separators.
  • Nesting / indentationnest(indent) and the group(indent, …) indent argument, with a pluggable genspace block for the indentation string.
  • Open/close textgroup(indent, open, close) wrapping the block in bracketing text counted toward the fit decision.
  • Fill modefill_breakable, where each break is decided individually.
  • The single-line formattersingleline_format, where breakables become their separator text and nothing ever breaks.
  • Custom newline and custom maxwidth, matching MRI's PrettyPrint.new / PrettyPrint.format signatures.

CGO-free, dependency-free, 100% test coverage, gofmt + go vet clean, and green across the six 64-bit Go targets (amd64, arm64, riscv64, loong64, ppc64le, s390x) and three operating systems (Linux, macOS, Windows).

Install

go get github.com/go-ruby-prettyprint/prettyprint

Usage

package main

import (
	"fmt"

	"github.com/go-ruby-prettyprint/prettyprint"
)

func main() {
	// PrettyPrint.format(''.dup, 10) { |q| ... }
	out := prettyprint.Format(10, "\n", nil, func(q *prettyprint.PrettyPrint) {
		q.Group(2, "[", 1, "]", 1, func() {
			q.TextString("111")
			q.BreakableString()
			q.TextString("222")
			q.BreakableString()
			q.TextString("333")
		})
	})
	fmt.Printf("%q\n", out) // "[111\n  222\n  333]"

	// The single-line formatter never breaks: breakables become their separator.
	flat := prettyprint.SingleLineFormat(func(q *prettyprint.SingleLine) {
		q.GroupDefault(func() {
			q.TextString("[")
			q.Breakable("", 0)
			q.TextString("1")
			q.BreakableString()
			q.TextString("2")
			q.TextString("]")
		})
	})
	fmt.Printf("%q\n", flat) // "[1 2]"
}
API map (MRI → Go)
Ruby (PrettyPrint) Go
PrettyPrint.new(out, maxwidth, nl, &gs) New(maxwidth, newline, genspace) / NewDefault()
PrettyPrint.format(...) Format(maxwidth, newline, genspace, fn) / FormatDefault
PrettyPrint.singleline_format(...) SingleLineFormat(fn)
#text(obj, width) Text(obj, width) / TextString(obj)
#breakable(sep, width) Breakable(sep, width) / BreakableString()
#group(indent, open, close, ow, cw) Group(indent, open, ow, close, cw, fn) / GroupDefault(fn)
#group_sub GroupSub(...) / NestedGroup(fn)
#nest(indent) Nest(indent, fn)
#fill_breakable(sep, width) FillBreakable(sep, width) / FillBreakableString()
#current_group CurrentGroup()
#break_outmost_groups BreakOutmostGroups()
#flush Flush()
PrettyPrint::VERSION VERSION

The default genspace is DefaultGenSpace (n ASCII spaces); pass nil to New / Format to use it.

Tests & coverage

The suite is 100% statement-covered and combines two layers:

  • Deterministic, ruby-free tests — golden programs with byte-exact expected output (verified against ruby -rprettyprint), plus white-box tests for the group-queue terminal arms. These alone hold the 100% gate on every platform, including Windows and the qemu cross-arch lanes where no ruby is present.
  • MRI differential oracleoracle_test.go runs a shared corpus through both this package and a generated PrettyPrint.format / singleline_format script and asserts the output is identical. It binmodes stdout/stdin (so Windows text-mode never rewrites the bytes), skips when ruby is absent, and gates on RUBY_VERSION >= "4.0".
go test -race -coverprofile=cover.out ./...
go tool cover -func=cover.out | tail -1   # total: (statements) 100.0%

License

BSD-3-Clause — see LICENSE. Copyright the go-ruby-prettyprint/prettyprint authors.

WebAssembly

Being pure Go (CGO=0), this library also compiles to WebAssembly — both GOOS=js GOARCH=wasm (browser / Node.js) and GOOS=wasip1 GOARCH=wasm (WASI). CI builds both targets on every push, alongside the six 64-bit native/qemu arches.

GOOS=js     GOARCH=wasm go build ./...   # browser / Node
GOOS=wasip1 GOARCH=wasm go build ./...   # WASI (wasmtime, wasmer, wasmedge, …)

Documentation

Overview

Package prettyprint is a pure-Go (no cgo) reimplementation of Ruby's `prettyprint` standard library — the Wadler/Lindig pretty-printing engine that MRI's `pp` object inspector is built on.

It is a faithful, byte-identical port of MRI 4.0.5's prettyprint.rb. The engine collects a stream of text, breakable separators and groups, then lays it out so that each group is printed on a single line when it fits within a maximum width and is otherwise broken at its breakable points, with nesting (indentation) preserved. The companion SingleLine variant emits the same stream with no breaks at all (breakables become their separator text).

This package implements only the layout engine. The `pp` object inspector that consumes it lives in the host (go-embedded-ruby / rbgo); this library is the standalone, reusable backend it binds to.

References

  • Christian Lindig, Strictly Pretty, March 2000.
  • Philip Wadler, A prettier printer, March 1998.

Index

Constants

View Source
const VERSION = "0.2.0"

VERSION mirrors PrettyPrint::VERSION in MRI 4.0.5.

Variables

This section is empty.

Functions

func DefaultGenSpace

func DefaultGenSpace(n int) string

DefaultGenSpace returns a string of n spaces — the default genspace block, `lambda {|n| ' ' * n}`.

func Format

func Format(maxwidth int, newline string, genspace GenSpace, fn func(*PrettyPrint)) string

Format is the convenience entry point of PrettyPrint.format: it builds a buffer, runs fn against it, flushes and returns the rendered string.

func FormatDefault

func FormatDefault(fn func(*PrettyPrint)) string

FormatDefault is Format with MRI's defaults (maxwidth 79, "\n", space genspace).

func SingleLineFormat

func SingleLineFormat(fn func(*SingleLine)) string

SingleLineFormat is the convenience entry point of PrettyPrint.singleline_format: it runs fn against a SingleLine buffer (whose breakables never break) and returns the rendered string.

Types

type GenSpace

type GenSpace func(n int) string

GenSpace generates the indentation string for a given number of columns. It corresponds to the `genspace` block of PrettyPrint.new. The default, DefaultGenSpace, returns n ASCII spaces.

type PrettyPrint

type PrettyPrint struct {
	// contains filtered or unexported fields
}

PrettyPrint is the layout buffer. It is the port of the PrettyPrint class: callers build a document with PrettyPrint.Text, PrettyPrint.Breakable, PrettyPrint.Group and PrettyPrint.Nest, then read it back with PrettyPrint.String (after PrettyPrint.Flush).

func New

func New(maxwidth int, newline string, genspace GenSpace) *PrettyPrint

New creates a pretty-printing buffer.

maxwidth is the maximum line length (MRI default 79); outputs may still overflow it where a single non-breakable text is wider. newline is the line break string (default "\n"). genspace generates indentation; when nil, DefaultGenSpace is used. The zero values matching MRI's defaults are produced by NewDefault.

func NewDefault

func NewDefault() *PrettyPrint

NewDefault creates a buffer with MRI's defaults: maxwidth 79, "\n" newline and the space-generating block.

func (*PrettyPrint) BreakOutmostGroups

func (q *PrettyPrint) BreakOutmostGroups()

BreakOutmostGroups breaks buffered groups until the pending output fits within maxwidth, draining the breakables (and the trailing texts) of each broken group to the output. It is the port of PrettyPrint#break_outmost_groups.

func (*PrettyPrint) Breakable

func (q *PrettyPrint) Breakable(sep string, width int)

Breakable records a candidate break that prints sep (width columns) when the enclosing group does not break. It is the port of PrettyPrint#breakable.

func (*PrettyPrint) BreakableString

func (q *PrettyPrint) BreakableString()

BreakableString is Breakable with sep " " and width 1, the all-defaults form.

func (*PrettyPrint) CurrentGroup

func (q *PrettyPrint) CurrentGroup() *group

CurrentGroup returns the group most recently pushed on the stack, the port of PrettyPrint#current_group.

func (*PrettyPrint) FillBreakable

func (q *PrettyPrint) FillBreakable(sep string, width int)

FillBreakable groups a single breakable so the break decision is made individually at this point. It is the port of PrettyPrint#fill_breakable.

func (*PrettyPrint) FillBreakableString

func (q *PrettyPrint) FillBreakableString()

FillBreakableString is FillBreakable with sep " " and width 1.

func (*PrettyPrint) Flush

func (q *PrettyPrint) Flush()

Flush writes every buffered element to the output and empties the buffer. It is the port of PrettyPrint#flush.

func (*PrettyPrint) Group

func (q *PrettyPrint) Group(indent int, openObj string, openWidth int, closeObj string, closeWidth int, fn func())

Group runs fn inside a new group nested by indent, optionally emitting openObj (openWidth columns) before and closeObj (closeWidth columns) after. It is the port of PrettyPrint#group.

func (*PrettyPrint) GroupDefault

func (q *PrettyPrint) GroupDefault(fn func())

GroupDefault runs fn in a fresh group with no extra indent and no open/close text — the common `group { ... }` form.

func (*PrettyPrint) GroupSub

func (q *PrettyPrint) GroupSub(_ int, _ string, _ int, _ string, _ int, fn func())

GroupSub queues a new group one level deeper than the current one and runs fn inside it, removing the group again afterwards if it registered no breakables. It is the port of PrettyPrint#group_sub. The leading parameters mirror the rbgo binding's signature and are unused; callers normally pass zero/empty.

func (*PrettyPrint) Indent

func (q *PrettyPrint) Indent() int

Indent reports the current indentation in columns.

func (*PrettyPrint) Maxwidth

func (q *PrettyPrint) Maxwidth() int

Maxwidth reports the configured maximum line width.

func (*PrettyPrint) Nest

func (q *PrettyPrint) Nest(indent int, fn func())

Nest increases the left margin by indent for the breaks added inside fn. It is the port of PrettyPrint#nest.

func (*PrettyPrint) NestedGroup

func (q *PrettyPrint) NestedGroup(fn func())

NestedGroup is an alias of PrettyPrint.GroupDefault kept for the rbgo binding's NestedGroup entry point.

func (*PrettyPrint) Newline

func (q *PrettyPrint) Newline() string

Newline reports the configured line-break string.

func (*PrettyPrint) String

func (q *PrettyPrint) String() string

String returns the rendered output accumulated so far. Call PrettyPrint.Flush first to drain any still-buffered elements.

func (*PrettyPrint) Text

func (q *PrettyPrint) Text(obj string, width int)

Text adds obj as a run of width columns. It is the port of PrettyPrint#text. Use PrettyPrint.TextString to default width to len(obj).

func (*PrettyPrint) TextString

func (q *PrettyPrint) TextString(obj string)

TextString adds obj with its byte length as the width, matching MRI's `text(obj, width=obj.length)` default.

type SingleLine

type SingleLine struct {
	// contains filtered or unexported fields
}

SingleLine renders the same builder calls as PrettyPrint but never breaks a line: breakables emit their separator as plain text and groups/nests are transparent. It is the port of PrettyPrint::SingleLine.

func NewSingleLine

func NewSingleLine() *SingleLine

NewSingleLine creates a SingleLine buffer.

func (*SingleLine) Breakable

func (s *SingleLine) Breakable(sep string, _ int)

Breakable appends sep (no line break). width is ignored.

func (*SingleLine) BreakableString

func (s *SingleLine) BreakableString()

BreakableString appends a single space.

func (*SingleLine) First

func (s *SingleLine) First() bool

First reports whether this is the first query of the innermost group, then records that it no longer is — the port of SingleLine#first?.

func (*SingleLine) Flush

func (s *SingleLine) Flush()

Flush is a no-op, present for parity with PrettyPrint.Flush; SingleLine writes directly and buffers nothing.

func (*SingleLine) Group

func (s *SingleLine) Group(_ int, openObj string, _ int, closeObj string, _ int, fn func())

Group emits openObj, runs fn, then closeObj. indent and the width arguments are ignored.

func (*SingleLine) GroupDefault

func (s *SingleLine) GroupDefault(fn func())

GroupDefault runs fn in a group with no open/close text.

func (*SingleLine) Nest

func (s *SingleLine) Nest(_ int, fn func())

Nest runs fn; indent is ignored.

func (*SingleLine) String

func (s *SingleLine) String() string

String returns the rendered output.

func (*SingleLine) Text

func (s *SingleLine) Text(obj string, _ int)

Text appends obj. The width argument is accepted for API parity and ignored.

func (*SingleLine) TextString

func (s *SingleLine) TextString(obj string)

TextString appends obj, the width-defaulting form.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL