Denmaseno 8 years ago
parent
commit
ef2ed5b740
2 changed files with 157 additions and 0 deletions
  1. 119 0
      dump.go
  2. 38 0
      dump_test.go

+ 119 - 0
dump.go

@@ -0,0 +1,119 @@
+package util
+
+import (
+	"bytes"
+	"fmt"
+	"io"
+	"reflect"
+	"strings"
+
+	util "github.com/senomas/go-util"
+)
+
+const (
+	// MaxFieldLen const
+	MaxFieldLen = 100
+	// MaxSliceLen const
+	MaxSliceLen = 100
+	tabSpace    = "  "
+)
+
+// Dump value
+func Dump(v interface{}) string {
+	var bb bytes.Buffer
+	fdump(&bb, 0, 0, "", reflect.ValueOf(v))
+	return bb.String()
+}
+
+// Fdump value
+// func Fdump(w io.Writer, v interface{}) {
+// 	fdump(w, 0, 0, "", reflect.ValueOf(v), "", "")
+// }
+
+func fdump(w io.Writer, rx int, rd int, tab string, value reflect.Value) {
+	rx++
+	if rx > 100 {
+		fmt.Fprint(w, "/* too many recursive */")
+	}
+	if rd > 10 {
+		fmt.Fprint(w, "/* too deep */")
+	}
+	if value.Kind() == reflect.Interface && !value.IsNil() {
+		elm := value.Elem()
+		if elm.Kind() == reflect.Ptr && !elm.IsNil() && elm.Elem().Kind() == reflect.Ptr {
+			value = elm
+		}
+	}
+	if value.Kind() == reflect.Ptr {
+		value = value.Elem()
+	}
+	if value.Kind() == reflect.String {
+		fmt.Fprintf(w, "\"%s\" /* Type:%s */", value, value.Type().String())
+	} else if kindIn(value.Kind(), reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64) {
+		fmt.Fprintf(w, "%+v /* Type:%s */", value, value.Type().String())
+	} else if kindIn(value.Kind(), reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64) {
+		fmt.Fprintf(w, "%+v /* Type:%s */", value, value.Type().String())
+	} else if value.Kind() == reflect.Struct {
+		ntab := tab + tabSpace
+		fmt.Fprintf(w, "{")
+		il := value.NumField()
+		for i, j := 0, 0; i < il && i < MaxFieldLen; i++ {
+			tf := value.Type().Field(i)
+			tag := strings.Split(value.Type().Field(i).Tag.Get("dump"), ",")
+			if !util.InStringSlice("ignore", tag...) {
+				if j > 0 {
+					fmt.Fprintf(w, ",\n%s\"%s\": ", ntab, tf.Name)
+				} else {
+					fmt.Fprintf(w, "\n%s\"%s\": ", ntab, tf.Name)
+				}
+				vf := value.Field(i)
+				fdump(w, rx, rd+1, ntab, vf)
+				j++
+			}
+		}
+		fmt.Fprintf(w, "\n%s}", tab)
+	} else if value.Kind() == reflect.Slice {
+		ntab := tab + tabSpace
+		fmt.Fprintf(w, "[ /* Type:%s Length:%v */\n%s", value.Type().String(), value.Len(), ntab)
+		il := value.Len()
+		for i := 0; i < il && i < MaxSliceLen; i++ {
+			vi := value.Index(i)
+			if i > 0 {
+				fmt.Fprintf(w, ",\n%s/* Index:%v */ ", ntab, i)
+			} else {
+				fmt.Fprint(w, "/* Index:0 */ ")
+			}
+			fdump(w, rx, rd+1, ntab, vi)
+		}
+		if il > MaxSliceLen {
+			fmt.Fprintf(w, "\n%s/* too many items */", ntab)
+		}
+		fmt.Fprintf(w, "\n%s]%s", tab, "")
+		// } else if value.CanInterface() {
+		// 	fmt.Fprintf(w, "%+v \\\\ Type:%s", value.Interface(), value.Type().String())
+	} else if value.Kind() == reflect.Map {
+		ntab := tab + tabSpace
+		fmt.Fprintf(w, "{ /* Type:%s */\n%s", value.Type().String(), ntab)
+		keys := value.MapKeys()
+		for k, kv := range keys {
+			if k > 0 {
+				fmt.Fprintf(w, ",\n%s\"%v\": ", ntab, kv)
+			} else {
+				fmt.Fprintf(w, "\"%v\": ", kv)
+			}
+			fdump(w, rx, rd+1, ntab, value.MapIndex(kv))
+		}
+		fmt.Fprintf(w, "\n%s}%s", tab, "")
+	} else {
+		fmt.Fprintf(w, "undefined /* Type:%s Value:[%v] */", value.Type().String(), value)
+	}
+}
+
+func kindIn(value reflect.Kind, list ...reflect.Kind) bool {
+	for _, v := range list {
+		if value == v {
+			return true
+		}
+	}
+	return false
+}

+ 38 - 0
dump_test.go

@@ -0,0 +1,38 @@
+package util
+
+import (
+	"fmt"
+	"testing"
+)
+
+type Struct1 struct {
+	Name   string
+	secret string `dump:"ignore"`
+	Codes  []string
+	Config map[string]*Address
+	Age    uint
+}
+
+type Address struct {
+	Street string
+	City   string
+}
+
+func (address Address) String() string {
+	return Dump(address)
+}
+
+// TestDump test
+func TestDump(t *testing.T) {
+	t.Logf("dump string(TEST) %s\n", Dump("TEST"))
+	t.Logf("dump int(12) %s\n", Dump(12))
+	config := make(map[string]*Address)
+	config["kampung"] = &Address{"Jalan", "Solo"}
+	config["rumah"] = &Address{"Kampret1", "Jakarta"}
+	config["kantor"] = &Address{"Kampret2", "Jakarta"}
+	t.Logf("dump Struct1{}\n%s\n", Dump(Struct1{"seno", "secret",
+		[]string{"sono", "keling"},
+		config,
+		17}))
+	t.Logf("fmt.Sprintf %s", fmt.Sprintf("HERE\n%v", &Address{"seno", "solo"}))
+}