package pretty

import "github.com/kylelemons/godebug/pretty"

Package pretty pretty-prints Go structures.

This package uses reflection to examine a Go value and can print out in a nice, aligned fashion. It supports three modes (normal, compact, and extended) for advanced use.

See the Reflect and Print examples for what the output looks like.

Index

Examples

Variables

var (
	// DefaultFormatter is the default set of overrides for stringification.
	DefaultFormatter = map[reflect.Type]interface{}{
		reflect.TypeOf(time.Time{}):          fmt.Sprint,
		reflect.TypeOf(net.IP{}):             fmt.Sprint,
		reflect.TypeOf((*error)(nil)).Elem(): fmt.Sprint,
	}

	// CompareConfig is the default configuration used for Compare.
	CompareConfig = &Config{
		Diffable:          true,
		IncludeUnexported: true,
		Formatter:         DefaultFormatter,
	}

	// DefaultConfig is the default configuration used for all other top-level functions.
	DefaultConfig = &Config{
		Formatter: DefaultFormatter,
	}
)

Default Config objects

Functions

func Compare

func Compare(a, b interface{}) string

Compare returns a string containing a line-by-line unified diff of the values in a and b, using the CompareConfig.

Each line in the output is prefixed with '+', '-', or ' ' to indicate which side it's from. Lines from the a side are marked with '-', lines from the b side are marked with '+' and lines that are the same on both sides are marked with ' '.

Example (Debugging)

Code:play 

package main

import (
	"fmt"

	"github.com/kylelemons/godebug/pretty"
)

func main() {
	type ShipManifest struct {
		Name     string
		Crew     map[string]string
		Androids int
		Stolen   bool
	}

	reported := &ShipManifest{
		Name: "Spaceship Heart of Gold",
		Crew: map[string]string{
			"Zaphod Beeblebrox": "Galactic President",
			"Trillian":          "Human",
			"Ford Prefect":      "A Hoopy Frood",
			"Arthur Dent":       "Along for the Ride",
		},
		Androids: 1,
		Stolen:   true,
	}

	expected := &ShipManifest{
		Name: "Spaceship Heart of Gold",
		Crew: map[string]string{
			"Trillian":      "Human",
			"Rowan Artosok": "Captain",
		},
		Androids: 1,
		Stolen:   false,
	}

	fmt.Println(pretty.Compare(reported, expected))
}

Output:

 {
  Name: "Spaceship Heart of Gold",
  Crew: {
-  Arthur Dent: "Along for the Ride",
-  Ford Prefect: "A Hoopy Frood",
+  Rowan Artosok: "Captain",
   Trillian: "Human",
-  Zaphod Beeblebrox: "Galactic President",
  },
  Androids: 1,
- Stolen: true,
+ Stolen: false,
 }
Example (Testing)

Code:play 

package main

import (
	"fmt"

	"github.com/kylelemons/godebug/pretty"
)

var t = struct {
	Errorf func(string, ...interface{})
}{
	Errorf: func(format string, args ...interface{}) {
		fmt.Println(fmt.Sprintf(format, args...) + "\n")
	},
}

func main() {
	// Code under test:

	type ShipManifest struct {
		Name     string
		Crew     map[string]string
		Androids int
		Stolen   bool
	}

	// AddCrew tries to add the given crewmember to the manifest.
	AddCrew := func(m *ShipManifest, name, title string) {
		if m.Crew == nil {
			m.Crew = make(map[string]string)
		}
		m.Crew[title] = name
	}

	// Test function:
	tests := []struct {
		desc        string
		before      *ShipManifest
		name, title string
		after       *ShipManifest
	}{
		{
			desc:   "add first",
			before: &ShipManifest{},
			name:   "Zaphod Beeblebrox",
			title:  "Galactic President",
			after: &ShipManifest{
				Crew: map[string]string{
					"Zaphod Beeblebrox": "Galactic President",
				},
			},
		},
		{
			desc: "add another",
			before: &ShipManifest{
				Crew: map[string]string{
					"Zaphod Beeblebrox": "Galactic President",
				},
			},
			name:  "Trillian",
			title: "Human",
			after: &ShipManifest{
				Crew: map[string]string{
					"Zaphod Beeblebrox": "Galactic President",
					"Trillian":          "Human",
				},
			},
		},
		{
			desc: "overwrite",
			before: &ShipManifest{
				Crew: map[string]string{
					"Zaphod Beeblebrox": "Galactic President",
				},
			},
			name:  "Zaphod Beeblebrox",
			title: "Just this guy, you know?",
			after: &ShipManifest{
				Crew: map[string]string{
					"Zaphod Beeblebrox": "Just this guy, you know?",
				},
			},
		},
	}

	for _, test := range tests {
		AddCrew(test.before, test.name, test.title)
		if diff := pretty.Compare(test.before, test.after); diff != "" {
			t.Errorf("%s: post-AddCrew diff: (-got +want)\n%s", test.desc, diff)
		}
	}

}

Output:

add first: post-AddCrew diff: (-got +want)
 {
  Name: "",
  Crew: {
-  Galactic President: "Zaphod Beeblebrox",
+  Zaphod Beeblebrox: "Galactic President",
  },
  Androids: 0,
  Stolen: false,
 }

add another: post-AddCrew diff: (-got +want)
 {
  Name: "",
  Crew: {
-  Human: "Trillian",
+  Trillian: "Human",
   Zaphod Beeblebrox: "Galactic President",
  },
  Androids: 0,
  Stolen: false,
 }

overwrite: post-AddCrew diff: (-got +want)
 {
  Name: "",
  Crew: {
-  Just this guy, you know?: "Zaphod Beeblebrox",
-  Zaphod Beeblebrox: "Galactic President",
+  Zaphod Beeblebrox: "Just this guy, you know?",
  },
  Androids: 0,
  Stolen: false,
 }

func Fprint

func Fprint(w io.Writer, vals ...interface{}) (n int64, err error)

Fprint writes the representation of the given value to the writer according to the DefaultConfig.

func Print

func Print(vals ...interface{})

Print writes the DefaultConfig representation of the given values to standard output.

Example

Code:play 

package main

import (
	"github.com/kylelemons/godebug/pretty"
)

func main() {
	type ShipManifest struct {
		Name     string
		Crew     map[string]string
		Androids int
		Stolen   bool
	}

	manifest := &ShipManifest{
		Name: "Spaceship Heart of Gold",
		Crew: map[string]string{
			"Zaphod Beeblebrox": "Galactic President",
			"Trillian":          "Human",
			"Ford Prefect":      "A Hoopy Frood",
			"Arthur Dent":       "Along for the Ride",
		},
		Androids: 1,
		Stolen:   true,
	}

	pretty.Print(manifest)

}

Output:

{Name:     "Spaceship Heart of Gold",
 Crew:     {Arthur Dent:       "Along for the Ride",
            Ford Prefect:      "A Hoopy Frood",
            Trillian:          "Human",
            Zaphod Beeblebrox: "Galactic President"},
 Androids: 1,
 Stolen:   true}

func Sprint

func Sprint(vals ...interface{}) string

Sprint returns a string representation of the given value according to the DefaultConfig.

Types

type Config

type Config struct {
	// Verbosity options
	Compact  bool // One-line output. Overrides Diffable.
	Diffable bool // Adds extra newlines for more easily diffable output.

	// Field and value options
	IncludeUnexported   bool // Include unexported fields in output
	PrintStringers      bool // Call String on a fmt.Stringer
	PrintTextMarshalers bool // Call MarshalText on an encoding.TextMarshaler
	SkipZeroFields      bool // Skip struct fields that have a zero value.

	// Output transforms
	ShortList int // Maximum character length for short lists if nonzero.

	// Type-specific overrides
	//
	// Formatter maps a type to a function that will provide a one-line string
	// representation of the input value.  Conceptually:
	//   Formatter[reflect.TypeOf(v)](v) = "v as a string"
	//
	// Note that the first argument need not explicitly match the type, it must
	// merely be callable with it.
	//
	// When processing an input value, if its type exists as a key in Formatter:
	//   1) If the value is nil, no stringification is performed.
	//      This allows overriding of PrintStringers and PrintTextMarshalers.
	//   2) The value will be called with the input as its only argument.
	//      The function must return a string as its first return value.
	//
	// In addition to func literals, two common values for this will be:
	//   fmt.Sprint        (function) func Sprint(...interface{}) string
	//   Type.String         (method) func (Type) String() string
	//
	// Note that neither of these work if the String method is a pointer
	// method and the input will be provided as a value.  In that case,
	// use a function that calls .String on the formal value parameter.
	Formatter map[reflect.Type]interface{}
}

A Config represents optional configuration parameters for formatting.

Some options, notably ShortList, dramatically increase the overhead of pretty-printing a value.

Example (CustomFormatter)

Code:play 

package main

import (
	"fmt"
	"net"
	"reflect"

	"github.com/kylelemons/godebug/pretty"
)

func main() {
	pretty.DefaultFormatter[reflect.TypeOf(&net.IPNet{})] = func(n *net.IPNet) string {
		return fmt.Sprintf("CIDR=%s", n)
	}
	pretty.Print(&net.IPNet{
		IP:   net.IPv4(192, 168, 1, 100),
		Mask: net.CIDRMask(24, 32),
	})

}

Output:

CIDR=192.168.1.100/24
Example (FmtFormatter)

Code:play 

package main

import (
	"fmt"
	"net"
	"reflect"

	"github.com/kylelemons/godebug/pretty"
)

func main() {
	pretty.DefaultFormatter[reflect.TypeOf(&net.IPNet{})] = fmt.Sprint
	pretty.DefaultFormatter[reflect.TypeOf(net.HardwareAddr{})] = fmt.Sprint
	pretty.Print(&net.IPNet{
		IP:   net.IPv4(192, 168, 1, 100),
		Mask: net.CIDRMask(24, 32),
	})
	pretty.Print(net.HardwareAddr{1, 2, 3, 4, 5, 6})

}

Output:

192.168.1.100/24
01:02:03:04:05:06

func (*Config) Compare

func (cfg *Config) Compare(a, b interface{}) string

Compare returns a string containing a line-by-line unified diff of the values in got and want according to the cfg.

func (*Config) Fprint

func (cfg *Config) Fprint(w io.Writer, vals ...interface{}) (n int64, err error)

Fprint writes the representation of the given value to the writer according to the cfg.

func (*Config) Print

func (cfg *Config) Print(vals ...interface{})

Print writes the configured presentation of the given values to standard output.

func (*Config) Sprint

func (cfg *Config) Sprint(vals ...interface{}) string

Sprint returns a string representation of the given value according to cfg.

Example

Code:play 

package main

import (
	"fmt"

	"github.com/kylelemons/godebug/pretty"
)

func main() {
	type Pair [2]int
	type Map struct {
		Name      string
		Players   map[string]Pair
		Obstacles map[Pair]string
	}

	m := Map{
		Name: "Rock Creek",
		Players: map[string]Pair{
			"player1": {1, 3},
			"player2": {0, -1},
		},
		Obstacles: map[Pair]string{
			Pair{0, 0}: "rock",
			Pair{2, 1}: "pond",
			Pair{1, 1}: "stream",
			Pair{0, 1}: "stream",
		},
	}

	// Specific output formats
	compact := &pretty.Config{
		Compact: true,
	}
	diffable := &pretty.Config{
		Diffable: true,
	}

	// Print out a summary
	fmt.Printf("Players: %s\n", compact.Sprint(m.Players))

	// Print diffable output
	fmt.Printf("Map State:\n%s", diffable.Sprint(m))

}

Output:

Players: {player1:[1,3],player2:[0,-1]}
Map State:
{
 Name: "Rock Creek",
 Players: {
  player1: [
   1,
   3,
  ],
  player2: [
   0,
   -1,
  ],
 },
 Obstacles: {
  [0,0]: "rock",
  [0,1]: "stream",
  [1,1]: "stream",
  [2,1]: "pond",
 },
}

Source Files

doc.go public.go reflect.go structure.go

Version
v1.0.0
Published
Apr 30, 2019
Platform
js/wasm
Imports
11 packages
Last checked
3 hours ago

Tools for package owners.