1[![!Build Status](https://travis-ci.org/sanity-io/litter.svg?branch=master)](https://travis-ci.org/sanity-io/litter) 2 3# Litter 4 5**Litter is a pretty printer library for Go data structures to aid in debugging and testing.** 6 7--- 8 9Litter is provided by 10 11<a href="https://www.sanity.io/?utm_source=GitHub&utm_campaign=litter" rel="nofollow" target="_blank"> 12 <img src="https://www.sanity.io/static/images/logo_red.svg?v=2" width="300"><br /> 13 Sanity: The Headless CMS Construction Kit 14</a> 15 16--- 17 18Litter named for the fact that it outputs *literals*, which you *litter* your output with. As a side benefit, all Litter output is syntactically correct Go. You can use Litter to emit data during debug, and it's also really nice for "snapshot data" in unit tests, since it produces consistent, sorted output. Litter was inspired by [Spew](https://github.com/davecgh/go-spew), but focuses on terseness and readability. 19 20### Basic example 21 22This: 23 24```go 25type Person struct { 26 Name string 27 Age int 28 Parent *Person 29} 30 31litter.Dump(Person{ 32 Name: "Bob", 33 Age: 20, 34 Parent: &Person{ 35 Name: "Jane", 36 Age: 50, 37 }, 38}) 39``` 40 41will output: 42 43``` 44Person{ 45 Name: "Bob", 46 Age: 20, 47 Parent: &Person{ 48 Name: "Jane", 49 Age: 50, 50 }, 51} 52``` 53 54### Use in tests 55 56Litter is a great alternative to JSON or YAML for providing "snapshots" or example data. For example: 57 58```go 59func TestSearch(t *testing.T) { 60 result := DoSearch() 61 62 actual := litterOpts.Sdump(result) 63 expected, err := ioutil.ReadFile("testdata.txt") 64 if err != nil { 65 // First run, write test data since it doesn't exist 66 if !os.IsNotExist(err) { 67 t.Error(err) 68 } 69 ioutil.Write("testdata.txt", actual, 0644) 70 actual = expected 71 } 72 if expected != actual { 73 t.Errorf("Expected %s, got %s", expected, actual) 74 } 75} 76``` 77 78The first run will use Litter to write the data to `testdata.txt`. On subsequent runs, the test will compare the data. Since Litter always provides a consistent view of a value, you can compare the strings directly. 79 80### Circular references 81 82Litter detects circular references or aliasing, and will replace additional references to the same object with aliases. For example: 83 84```go 85type Circular struct { 86 Self *Circular 87} 88 89selfref := Circular{} 90selfref.Self = &selfref 91 92litter.Dump(selfref) 93``` 94 95will output: 96 97``` 98Circular { // p0 99 Self: p0, 100} 101``` 102 103## Installation 104 105```bash 106$ go get -u github.com/sanity-io/litter 107``` 108 109## Quick start 110 111Add this import line to the file you're working in: 112 113```go 114import "github.com/sanity-io/litter" 115``` 116 117To dump a variable with full newlines, indentation, type, and aliasing information, use `Dump` or `Sdump`: 118 119```go 120litter.Dump(myVar1) 121str := litter.Sdump(myVar1) 122``` 123 124### `litter.Dump(value, ...)` 125 126Dumps the data structure to STDOUT. 127 128### `litter.Sdump(value, ...)` 129 130Returns the dump as a string 131 132## Configuration 133 134You can configure litter globally by modifying the default `litter.Config` 135 136```go 137// Strip all package names from types 138litter.Config.StripPackageNames = true 139 140// Hide private struct fields from dumped structs 141litter.Config.HidePrivateFields = true 142 143// Hide fields matched with given regexp if it is not nil. It is set up to hide fields generate with protoc-gen-go 144litter.Config.FieldExclusions = regexp.MustCompile(`^(XXX_.*)$`) 145 146// Sets a "home" package. The package name will be stripped from all its types 147litter.Config.HomePackage = "mypackage" 148 149// Sets separator used when multiple arguments are passed to Dump() or Sdump(). 150litter.Config.Separator = "\n" 151 152// Use compact output: strip newlines and other unnecessary whitespace 153litter.Config.Compact = true 154 155// Prevents duplicate pointers from being replaced by placeholder variable names (except in necessary, in the case 156// of circular references) 157litter.Config.DisablePointerReplacement = true 158``` 159 160### `litter.Options` 161 162Allows you to configure a local configuration of litter to allow for proper compartmentalization of state at the expense of some comfort: 163 164``` go 165 sq := litter.Options { 166 HidePrivateFields: true, 167 HomePackage: "thispack", 168 Separator: " ", 169 } 170 171 sq.Dump("dumped", "with", "local", "settings") 172``` 173 174## Custom dumpers 175 176Implement the interface Dumper on your types to take control of how your type is dumped. 177 178``` go 179type Dumper interface { 180 LitterDump(w io.Writer) 181} 182``` 183 184Just write your custom dump to the provided stream, using multiple lines divided by `"\n"` if you need. Litter 185might indent your output according to context, and optionally decorate your first line with a pointer comment 186where appropriate. 187 188A couple of examples from the test suite: 189 190``` go 191type CustomMultiLineDumper struct {} 192 193func (cmld *CustomMultiLineDumper) LitterDump(w io.Writer) { 194 w.Write([]byte("{\n multi\n line\n}")) 195} 196 197type CustomSingleLineDumper int 198 199func (csld CustomSingleLineDumper) LitterDump(w io.Writer) { 200 w.Write([]byte("<custom>")) 201} 202```` 203