summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--spew/config.go2
-rw-r--r--spew/doc.go17
-rw-r--r--spew/dump.go16
-rw-r--r--spew/example_test.go92
-rw-r--r--spew/format.go12
-rw-r--r--spew/spew.go176
6 files changed, 303 insertions, 12 deletions
diff --git a/spew/config.go b/spew/config.go
index 542f457..e32b224 100644
--- a/spew/config.go
+++ b/spew/config.go
@@ -55,3 +55,5 @@ type ConfigState struct {
// Config is the active configuration in use by spew. The configuration
// can be changed by modifying the contents of spew.Config.
var Config ConfigState = ConfigState{Indent: " "}
+
+var defaultConfig = ConfigState{Indent: " "} \ No newline at end of file
diff --git a/spew/doc.go b/spew/doc.go
index 61c0091..94db62d 100644
--- a/spew/doc.go
+++ b/spew/doc.go
@@ -58,20 +58,29 @@ printing style, use the convenience wrappers Printf, Fprintf, etc with either
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:
- spew.Config.MaxDepth
+ * MaxDepth
Maximum number of levels to descend into nested data structures.
There is no limit by default.
- spew.Config.Indent
+ * Indent
String to use for each indentation level for Dump functions.
It is a single space by default. A popular alternative is "\t".
- spew.Config.DisableMethods
+ * DisableMethods
Disables invocation of error and Stringer interface methods.
Method invocation is enabled by default.
- spew.Config.DisablePointerMethods
+ * DisablePointerMethods
Disables invocation of error and Stringer interface methods on types
which only accept pointer receivers from non-pointer variables.
Pointer method invocation is enabled by default.
diff --git a/spew/dump.go b/spew/dump.go
index 067f98e..361e90e 100644
--- a/spew/dump.go
+++ b/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
-// exactly the same as Dump.
-func Fdump(w io.Writer, a ...interface{}) {
+// fdump is a helper function to consolidate the logic from the various public
+// methods which take varying writers and config states.
+func fdump(cs *ConfigState, w io.Writer, a ...interface{}) {
for _, arg := range a {
if arg == nil {
w.Write(interfaceBytes)
@@ -292,13 +292,19 @@ func Fdump(w io.Writer, a ...interface{}) {
continue
}
- d := dumpState{w: w, cs: &Config}
+ d := dumpState{w: w, cs: cs}
d.pointers = make(map[uintptr]int)
d.dump(reflect.ValueOf(arg))
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
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.
*/
func Dump(a ...interface{}) {
- Fdump(os.Stdout, a...)
+ fdump(&Config, os.Stdout, a...)
}
diff --git a/spew/example_test.go b/spew/example_test.go
index e96d2c1..2a35010 100644
--- a/spew/example_test.go
+++ b/spew/example_test.go
@@ -130,3 +130,95 @@ func ExamplePrintf() {
// ppui8: <**>5
// 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
+}
diff --git a/spew/format.go b/spew/format.go
index 604df9a..4a285e2 100644
--- a/spew/format.go
+++ b/spew/format.go
@@ -316,6 +316,14 @@ func (f *formatState) Format(fs fmt.State, verb rune) {
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
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.
*/
func NewFormatter(v interface{}) fmt.Formatter {
- fs := &formatState{value: v, cs: &Config}
- fs.pointers = make(map[uintptr]int)
- return fs
+ return newFormatter(&Config, v)
}
diff --git a/spew/spew.go b/spew/spew.go
index a599978..46fd904 100644
--- a/spew/spew.go
+++ b/spew/spew.go
@@ -19,6 +19,7 @@ package spew
import (
"fmt"
"io"
+ "os"
)
// 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
}
+
+// 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
+}