Skip to content

Commit

Permalink
Implement SetOmitEmpty() (#89)
Browse files Browse the repository at this point in the history
  • Loading branch information
apstndb authored Nov 27, 2024
1 parent c9d35c3 commit 331add6
Show file tree
Hide file tree
Showing 3 changed files with 84 additions and 4 deletions.
9 changes: 9 additions & 0 deletions pp.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ type PrettyPrinter struct {
thousandsSeparator bool
// This skips unexported fields of structs.
exportedOnly bool

// This skips empty fields of structs.
omitEmpty bool
}

// New creates a new PrettyPrinter that can be used to pretty print values
Expand All @@ -66,6 +69,7 @@ func newPrettyPrinter(callerLevel int) *PrettyPrinter {
coloringEnabled: true,
decimalUint: true,
exportedOnly: false,
omitEmpty: false,
}
}

Expand Down Expand Up @@ -149,6 +153,11 @@ func (pp *PrettyPrinter) SetExportedOnly(enabled bool) {
pp.exportedOnly = enabled
}

// SetOmitEmpty makes empty fields in struct not be printed.
func (pp *PrettyPrinter) SetOmitEmpty(enabled bool) {
pp.omitEmpty = enabled
}

func (pp *PrettyPrinter) SetThousandsSeparator(enabled bool) {
pp.thousandsSeparator = enabled
}
Expand Down
63 changes: 63 additions & 0 deletions pp_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -160,3 +160,66 @@ func TestStructPrintingWithTags(t *testing.T) {
}

}

func TestStructPrintingWithOmitEmpty(t *testing.T) {
type Bar struct{ StringField string }
type Foo struct {
StringField string
StringPtr *string

StructField Bar
StructPtr *Bar
InterfactField interface{}
}

stringVal := "foo"

testCases := []struct {
name string
foo Foo
omitIfEmptyOmitted bool
fullOmitted bool
want string
}{
{
name: "all set",
foo: Foo{
StringField: "foo",
StringPtr: &stringVal,
StructField: Bar{
StringField: "baz",
},
StructPtr: &Bar{
StringField: "foobar",
},
InterfactField: &Bar{StringField: "fizzbuzz"},
},
want: "pp.Foo{\n StringField: \"foo\",\n StringPtr: &\"foo\",\n StructField: pp.Bar{\n StringField: \"baz\",\n },\n StructPtr: &pp.Bar{\n StringField: \"foobar\",\n },\n InterfactField: &pp.Bar{\n StringField: \"fizzbuzz\",\n },\n}",
},
{
name: "zero",
foo: Foo{},
want: "pp.Foo{}",
},
}

for _, tc := range testCases {
tc := tc
t.Run(tc.name, func(t *testing.T) {
output := new(bytes.Buffer)
pp := New()
pp.SetOutput(output)
pp.SetColoringEnabled(false)
pp.SetOmitEmpty(true)

pp.Print(tc.foo)

result := output.String()

if result != tc.want {
t.Errorf("result differ, want: %q, got: %q", tc.want, result)
}
})
}

}
16 changes: 12 additions & 4 deletions printer.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ const (
)

func (pp *PrettyPrinter) format(object interface{}) string {
return newPrinter(object, &pp.currentScheme, pp.maxDepth, pp.coloringEnabled, pp.decimalUint, pp.exportedOnly, pp.thousandsSeparator).String()
return newPrinter(object, &pp.currentScheme, pp.maxDepth, pp.coloringEnabled, pp.decimalUint, pp.exportedOnly, pp.thousandsSeparator, pp.omitEmpty).String()
}

func newPrinter(object interface{}, currentScheme *ColorScheme, maxDepth int, coloringEnabled bool, decimalUint bool, exportedOnly bool, thousandsSeparator bool) *printer {
func newPrinter(object interface{}, currentScheme *ColorScheme, maxDepth int, coloringEnabled bool, decimalUint bool, exportedOnly bool, thousandsSeparator bool, omitEmpty bool) *printer {
buffer := bytes.NewBufferString("")
tw := new(tabwriter.Writer)
tw.Init(buffer, indentWidth, 0, 1, ' ', 0)
Expand All @@ -42,6 +42,7 @@ func newPrinter(object interface{}, currentScheme *ColorScheme, maxDepth int, co
decimalUint: decimalUint,
exportedOnly: exportedOnly,
thousandsSeparator: thousandsSeparator,
omitEmpty: omitEmpty,
}

if thousandsSeparator {
Expand All @@ -63,6 +64,7 @@ type printer struct {
decimalUint bool
exportedOnly bool
thousandsSeparator bool
omitEmpty bool
localizedPrinter *message.Printer
}

Expand Down Expand Up @@ -212,7 +214,13 @@ func (p *printer) printStruct() {
if p.exportedOnly && field.PkgPath != "" {
continue
}
// ignore fields if zero value, or explicitly set

// ignore empty fields if needed
if p.omitEmpty && valueIsZero(value) {
continue
}

// ignore fields with struct tags if zero value, or explicitly set
if tag := field.Tag.Get("pp"); tag != "" {
parts := strings.Split(tag, ",")
if len(parts) == 2 && parts[1] == "omitempty" && valueIsZero(value) {
Expand Down Expand Up @@ -469,7 +477,7 @@ func (p *printer) colorize(text string, color uint16) string {
}

func (p *printer) format(object interface{}) string {
pp := newPrinter(object, p.currentScheme, p.maxDepth, p.coloringEnabled, p.decimalUint, p.exportedOnly, p.thousandsSeparator)
pp := newPrinter(object, p.currentScheme, p.maxDepth, p.coloringEnabled, p.decimalUint, p.exportedOnly, p.thousandsSeparator, false)
pp.depth = p.depth
pp.visited = p.visited
if value, ok := object.(reflect.Value); ok {
Expand Down

0 comments on commit 331add6

Please sign in to comment.