Implement support for unqiue config instances.
This commit adds a new type, SpewState, which can be used to create instances with unique configuration options. The methods of SpewState are equivalent to the top-level functions. Full documentation and examples are included.
This commit is contained in:
parent
40eb25a95d
commit
034a2a5a5e
|
@ -55,3 +55,5 @@ type ConfigState struct {
|
||||||
// Config is the active configuration in use by spew. The configuration
|
// Config is the active configuration in use by spew. The configuration
|
||||||
// can be changed by modifying the contents of spew.Config.
|
// can be changed by modifying the contents of spew.Config.
|
||||||
var Config ConfigState = ConfigState{Indent: " "}
|
var Config ConfigState = ConfigState{Indent: " "}
|
||||||
|
|
||||||
|
var defaultConfig = ConfigState{Indent: " "}
|
17
spew/doc.go
17
spew/doc.go
|
@ -58,20 +58,29 @@ printing style, use the convenience wrappers Printf, Fprintf, etc with either
|
||||||
|
|
||||||
Configuration Options
|
Configuration Options
|
||||||
|
|
||||||
|
Configuration of spew is handled by fields in the ConfigState type. For
|
||||||
|
convenience, all of the top-level functions use a global state available
|
||||||
|
via the spew.Config global.
|
||||||
|
|
||||||
|
It is also possible to create a SpewState instance which provides a unique
|
||||||
|
ConfigState accessible via the Config method. The methods of SpewState are
|
||||||
|
equivalent to the top-level functions. This allows concurrent configuration
|
||||||
|
options. See the SpewState documentation for more details.
|
||||||
|
|
||||||
The following configuration options are available:
|
The following configuration options are available:
|
||||||
spew.Config.MaxDepth
|
* MaxDepth
|
||||||
Maximum number of levels to descend into nested data structures.
|
Maximum number of levels to descend into nested data structures.
|
||||||
There is no limit by default.
|
There is no limit by default.
|
||||||
|
|
||||||
spew.Config.Indent
|
* Indent
|
||||||
String to use for each indentation level for Dump functions.
|
String to use for each indentation level for Dump functions.
|
||||||
It is a single space by default. A popular alternative is "\t".
|
It is a single space by default. A popular alternative is "\t".
|
||||||
|
|
||||||
spew.Config.DisableMethods
|
* DisableMethods
|
||||||
Disables invocation of error and Stringer interface methods.
|
Disables invocation of error and Stringer interface methods.
|
||||||
Method invocation is enabled by default.
|
Method invocation is enabled by default.
|
||||||
|
|
||||||
spew.Config.DisablePointerMethods
|
* DisablePointerMethods
|
||||||
Disables invocation of error and Stringer interface methods on types
|
Disables invocation of error and Stringer interface methods on types
|
||||||
which only accept pointer receivers from non-pointer variables.
|
which only accept pointer receivers from non-pointer variables.
|
||||||
Pointer method invocation is enabled by default.
|
Pointer method invocation is enabled by default.
|
||||||
|
|
16
spew/dump.go
16
spew/dump.go
|
@ -281,9 +281,9 @@ func (d *dumpState) dump(v reflect.Value) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
// fdump is a helper function to consolidate the logic from the various public
|
||||||
// exactly the same as Dump.
|
// methods which take varying writers and config states.
|
||||||
func Fdump(w io.Writer, a ...interface{}) {
|
func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
|
||||||
for _, arg := range a {
|
for _, arg := range a {
|
||||||
if arg == nil {
|
if arg == nil {
|
||||||
w.Write(interfaceBytes)
|
w.Write(interfaceBytes)
|
||||||
|
@ -292,13 +292,19 @@ func Fdump(w io.Writer, a ...interface{}) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
d := dumpState{w: w, cs: &Config}
|
d := dumpState{w: w, cs: cs}
|
||||||
d.pointers = make(map[uintptr]int)
|
d.pointers = make(map[uintptr]int)
|
||||||
d.dump(reflect.ValueOf(arg))
|
d.dump(reflect.ValueOf(arg))
|
||||||
d.w.Write(newlineBytes)
|
d.w.Write(newlineBytes)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
fdump(&Config, w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Dump displays the passed parameters to standard out with newlines, customizable
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
indentation, and additional debug information such as complete types and all
|
indentation, and additional debug information such as complete types and all
|
||||||
|
@ -320,5 +326,5 @@ spew.Config. See ConfigState for options documentation.
|
||||||
See Fdump if you would prefer dump to an arbitrary io.Writer.
|
See Fdump if you would prefer dump to an arbitrary io.Writer.
|
||||||
*/
|
*/
|
||||||
func Dump(a ...interface{}) {
|
func Dump(a ...interface{}) {
|
||||||
Fdump(os.Stdout, a...)
|
fdump(&Config, os.Stdout, a...)
|
||||||
}
|
}
|
||||||
|
|
|
@ -130,3 +130,95 @@ func ExamplePrintf() {
|
||||||
// ppui8: <**>5
|
// ppui8: <**>5
|
||||||
// circular: {1 <*>{1 <*><shown>}}
|
// circular: {1 <*>{1 <*><shown>}}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use a SpewState.
|
||||||
|
func ExampleSpewState() {
|
||||||
|
// A SpewState does not need initialization.
|
||||||
|
ss := new(spew.SpewState) // or var ss spew.SpewState
|
||||||
|
|
||||||
|
// Modify the indent level of the SpewState only. The global configuration
|
||||||
|
// is not modified.
|
||||||
|
ssc := ss.Config()
|
||||||
|
ssc.Indent = "\t"
|
||||||
|
|
||||||
|
// Output using the SpewState instance.
|
||||||
|
v := map[string]int{"one": 1}
|
||||||
|
ss.Printf("v: %v\n", v)
|
||||||
|
ss.Dump(v)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// v: map[one:1]
|
||||||
|
// (map[string]int) {
|
||||||
|
// (string) "one": (int) 1
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use a SpewState.Dump to dump variables to
|
||||||
|
// stdout
|
||||||
|
func ExampleSpewState_Dump() {
|
||||||
|
// See the top-level Dump example for details on the types used in this
|
||||||
|
// example.
|
||||||
|
|
||||||
|
// A SpewState does not need initialization.
|
||||||
|
ss := new(spew.SpewState) // or var ss spew.SpewState
|
||||||
|
ss2 := new(spew.SpewState) // or var ss2 spew.SpewState
|
||||||
|
|
||||||
|
// Modify the indent level of the first SpewState only.
|
||||||
|
ssc := ss.Config()
|
||||||
|
ssc.Indent = "\t"
|
||||||
|
|
||||||
|
// Setup some sample data structures for the example.
|
||||||
|
bar := Bar{Flag(flagTwo), uintptr(0)}
|
||||||
|
s1 := Foo{bar, map[interface{}]interface{}{"one": true}}
|
||||||
|
|
||||||
|
// Dump using the SpewState instances.
|
||||||
|
ss.Dump(s1)
|
||||||
|
ss2.Dump(s1)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// (spew_test.Foo) {
|
||||||
|
// unexportedField: (spew_test.Bar) {
|
||||||
|
// flag: (spew_test.Flag) flagTwo,
|
||||||
|
// data: (uintptr) <nil>
|
||||||
|
// },
|
||||||
|
// ExportedField: (map[interface {}]interface {}) {
|
||||||
|
// (string) "one": (bool) true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// (spew_test.Foo) {
|
||||||
|
// unexportedField: (spew_test.Bar) {
|
||||||
|
// flag: (spew_test.Flag) flagTwo,
|
||||||
|
// data: (uintptr) <nil>
|
||||||
|
// },
|
||||||
|
// ExportedField: (map[interface {}]interface {}) {
|
||||||
|
// (string) "one": (bool) true
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
|
// This example demonstrates how to use SpewState.Printf to display a variable
|
||||||
|
// with a format string and inline formatting.
|
||||||
|
func ExampleSpewState_Printf() {
|
||||||
|
// See the top-level Dump example for details on the types used in this
|
||||||
|
// example.
|
||||||
|
|
||||||
|
// A SpewState does not need initialization.
|
||||||
|
ss := new(spew.SpewState) // or var ss spew.SpewState
|
||||||
|
ss2 := new(spew.SpewState) // or var ss2 spew.SpewState
|
||||||
|
|
||||||
|
// Modify the method handling of the first SpewState only.
|
||||||
|
ssc := ss.Config()
|
||||||
|
ssc.DisableMethods = true
|
||||||
|
|
||||||
|
// This is of type Flag which implements a Stringer and has raw value 1.
|
||||||
|
f := flagTwo
|
||||||
|
|
||||||
|
// Dump using the SpewState instances.
|
||||||
|
ss.Printf("f: %v\n", f)
|
||||||
|
ss2.Printf("f: %v\n", f)
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// f: 1
|
||||||
|
// f: flagTwo
|
||||||
|
}
|
||||||
|
|
|
@ -316,6 +316,14 @@ func (f *formatState) Format(fs fmt.State, verb rune) {
|
||||||
f.buffer.WriteTo(fs)
|
f.buffer.WriteTo(fs)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// newFormatter is a helper function to consolidate the logic from the various
|
||||||
|
// public methods which take varying config states.
|
||||||
|
func newFormatter(cs *ConfigState, v interface{}) fmt.Formatter {
|
||||||
|
fs := &formatState{value: v, cs: cs}
|
||||||
|
fs.pointers = make(map[uintptr]int)
|
||||||
|
return fs
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
interface. As a result, it integrates cleanly with standard fmt package
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
@ -333,7 +341,5 @@ use of the custom formatter by calling one of the convenience functions such as
|
||||||
Printf, Println, or Printf.
|
Printf, Println, or Printf.
|
||||||
*/
|
*/
|
||||||
func NewFormatter(v interface{}) fmt.Formatter {
|
func NewFormatter(v interface{}) fmt.Formatter {
|
||||||
fs := &formatState{value: v, cs: &Config}
|
return newFormatter(&Config, v)
|
||||||
fs.pointers = make(map[uintptr]int)
|
|
||||||
return fs
|
|
||||||
}
|
}
|
||||||
|
|
176
spew/spew.go
176
spew/spew.go
|
@ -19,6 +19,7 @@ package spew
|
||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
@ -113,3 +114,178 @@ func convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
}
|
}
|
||||||
return formatters
|
return formatters
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// SpewState provides a context which can have its own configuration options.
|
||||||
|
// The configuration options can be manipulated via the Config method. The
|
||||||
|
// methods of SpewState are equivalent to the top-level functions.
|
||||||
|
//
|
||||||
|
// A SpewState does not need any special initialization, so new(SpewState) or
|
||||||
|
// just declaring a SpewState variable, is sufficient to initialilize a
|
||||||
|
// SpewState using the default configuration options.
|
||||||
|
type SpewState struct {
|
||||||
|
cs *ConfigState
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config returns a pointer to the active ConfigState for the SpewState
|
||||||
|
// instance. Set the fields of the returned structure to the desired
|
||||||
|
// configuration settings for the instance.
|
||||||
|
func (s *SpewState) Config() (cs *ConfigState) {
|
||||||
|
if s.cs == nil {
|
||||||
|
cs := defaultConfig
|
||||||
|
s.cs = &cs
|
||||||
|
}
|
||||||
|
return s.cs
|
||||||
|
}
|
||||||
|
|
||||||
|
// Errorf is a wrapper for fmt.Errorf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. It returns
|
||||||
|
// the formatted string as a value that satisfies error. See NewFormatter
|
||||||
|
// for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Errorf(format, s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Errorf(format string, a ...interface{}) (err error) {
|
||||||
|
return fmt.Errorf(format, s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprint is a wrapper for fmt.Fprint that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprint(w, s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Fprint(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprint(w, s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintf is a wrapper for fmt.Fprintf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintf(w, format, s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Fprintf(w io.Writer, format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintf(w, format, s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fprintln is a wrapper for fmt.Fprintln that treats each argument as if it
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Fprintln(w, s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Fprintln(w io.Writer, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Fprintln(w, s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print is a wrapper for fmt.Print that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Print(s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Print(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Print(s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Printf is a wrapper for fmt.Printf that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Printf(format, s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Printf(format string, a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Printf(format, s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Println is a wrapper for fmt.Println that treats each argument as if it were
|
||||||
|
// passed with a Formatter interface returned by s.NewFormatter. It returns
|
||||||
|
// the number of bytes written and any write error encountered. See
|
||||||
|
// NewFormatter for formatting details.
|
||||||
|
//
|
||||||
|
// This function is shorthand for the following syntax:
|
||||||
|
//
|
||||||
|
// fmt.Println(s.NewFormatter(a), s.NewFormatter(b))
|
||||||
|
func (s *SpewState) Println(a ...interface{}) (n int, err error) {
|
||||||
|
return fmt.Println(s.convertArgs(a)...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
NewFormatter returns a custom formatter that satisfies the fmt.Formatter
|
||||||
|
interface. As a result, it integrates cleanly with standard fmt package
|
||||||
|
printing functions. The formatter is useful for inline printing of smaller data
|
||||||
|
types similar to the standard %v format specifier.
|
||||||
|
|
||||||
|
The custom formatter only responds to the %v and %+v verb combinations. Any
|
||||||
|
other variations such as %x, %q, and %#v will be sent to the the standard fmt
|
||||||
|
package for formatting. In addition, the custom formatter ignores the width and
|
||||||
|
precision arguments (however they will still work on the format specifiers not
|
||||||
|
handled by the custom formatter).
|
||||||
|
|
||||||
|
Typically this function shouldn't be called directly. It is much easier to make
|
||||||
|
use of the custom formatter by calling one of the convenience functions such as
|
||||||
|
s.Printf, s.Println, or s.Printf.
|
||||||
|
*/
|
||||||
|
func (s *SpewState) NewFormatter(v interface{}) fmt.Formatter {
|
||||||
|
// The Config method creates the config state if needed, so call it instead
|
||||||
|
// of using s.cs directly to ensure the zero value SpewState is sane.
|
||||||
|
return newFormatter(s.Config(), v)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fdump formats and displays the passed arguments to io.Writer w. It formats
|
||||||
|
// exactly the same as Dump.
|
||||||
|
func (s *SpewState) Fdump(w io.Writer, a ...interface{}) {
|
||||||
|
// The Config method creates the config state if needed, so call it instead
|
||||||
|
// of using s.cs directly to ensure the zero value SpewState is sane.
|
||||||
|
fdump(s.Config(), w, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Dump displays the passed parameters to standard out with newlines, customizable
|
||||||
|
indentation, and additional debug information such as complete types and all
|
||||||
|
pointer addresses used to indirect to the final value. It provides the
|
||||||
|
following features over the built-in printing facilities provided by the fmt
|
||||||
|
package:
|
||||||
|
|
||||||
|
* Pointers are dereferenced and followed
|
||||||
|
* Circular data structures are detected and handled properly
|
||||||
|
* Custom error/Stringer interfaces are optionally invoked, including
|
||||||
|
on unexported types
|
||||||
|
* Custom types which only implement the error/Stringer interfaces via
|
||||||
|
a pointer receiver are optionally invoked when passing non-pointer
|
||||||
|
variables
|
||||||
|
|
||||||
|
The configuration options are controlled by accessing the ConfigState associated
|
||||||
|
with s via the Config method. See ConfigState for options documentation.
|
||||||
|
|
||||||
|
See Fdump if you would prefer dump to an arbitrary io.Writer.
|
||||||
|
*/
|
||||||
|
func (s *SpewState) Dump(a ...interface{}) {
|
||||||
|
// The Config method creates the config state if needed, so call it instead
|
||||||
|
// of using s.cs directly to ensure the zero value SpewState is sane.
|
||||||
|
fdump(s.Config(), os.Stdout, a...)
|
||||||
|
}
|
||||||
|
|
||||||
|
// convertArgs accepts a slice of arguments and returns a slice of the same
|
||||||
|
// length with each argument converted to a spew Formatter interface using
|
||||||
|
// the ConfigState associated with s.
|
||||||
|
func (s *SpewState) convertArgs(args []interface{}) (formatters []interface{}) {
|
||||||
|
// The Config method creates the config state if needed, so call it instead
|
||||||
|
// of using s.cs directly to ensure the zero value SpewState is sane.
|
||||||
|
cs := s.Config()
|
||||||
|
formatters = make([]interface{}, len(args))
|
||||||
|
for index, arg := range args {
|
||||||
|
formatters[index] = newFormatter(cs, arg)
|
||||||
|
}
|
||||||
|
return formatters
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue