Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Implement SetOmitEmpty() #89

Merged
merged 1 commit into from
Nov 27, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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