Skip to content

Commit

Permalink
improve gutil.Dump
Browse files Browse the repository at this point in the history
  • Loading branch information
gqcn committed Oct 21, 2021
1 parent aacfa1b commit 9777807
Show file tree
Hide file tree
Showing 6 changed files with 321 additions and 63 deletions.
2 changes: 1 addition & 1 deletion encoding/gjson/gjson_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -184,5 +184,5 @@ func (j *Json) Dump() {
func (j *Json) Export() string {
j.mu.RLock()
defer j.mu.RUnlock()
return gutil.Export(*j.p)
return gutil.Export(*j.p, gutil.ExportOption{})
}
11 changes: 6 additions & 5 deletions frame/g/g_func.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,13 +34,14 @@ func Listen() {
}

// Dump dumps a variable to stdout with more manually readable.
func Dump(i ...interface{}) {
gutil.Dump(i...)
func Dump(values ...interface{}) {
gutil.Dump(values...)
}

// Export exports a variable to string with more manually readable.
func Export(i ...interface{}) string {
return gutil.Export(i...)
// DumpBrief acts like Dump, but with no type information.
// Also see Dump.
func DumpBrief(values ...interface{}) {
gutil.DumpBrief(values...)
}

// Throw throws an exception, which can be caught by TryCatch function.
Expand Down
2 changes: 1 addition & 1 deletion os/gview/gview_buildin.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ import (
func (view *View) buildInFuncDump(values ...interface{}) (result string) {
result += "<!--\n"
for _, v := range values {
result += gutil.Export(v) + "\n"
result += gutil.Export(v, gutil.ExportOption{WithoutType: true}) + "\n"
}
result += "-->\n"
return result
Expand Down
4 changes: 4 additions & 0 deletions util/gutil/gutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import (
"reflect"
)

const (
dumpIndent = ` `
)

// Throw throws out an exception, which can be caught be TryCatch or recover.
func Throw(exception interface{}) {
panic(exception)
Expand Down
257 changes: 201 additions & 56 deletions util/gutil/gutil_dump.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ package gutil
import (
"bytes"
"fmt"
"github.com/gogf/gf/v2/internal/json"
"github.com/gogf/gf/v2/util/gconv"
"os"
"github.com/gogf/gf/v2/internal/structs"
"github.com/gogf/gf/v2/text/gstr"
"reflect"
)

// ExportOption specifies the behavior of function Export.
type ExportOption struct {
WithoutType bool // WithoutType specifies exported content has no type information.
}

// iVal is used for type assert api for Val().
type iVal interface {
Val() interface{}
Expand All @@ -30,66 +34,207 @@ type iMapStrAny interface {
MapStrAny() map[string]interface{}
}

// Dump prints variables <i...> to stdout with more manually readable.
func Dump(i ...interface{}) {
s := Export(i...)
if s != "" {
fmt.Println(s)
// Dump prints variables `values` to stdout with more manually readable.
func Dump(values ...interface{}) {
for _, value := range values {
if s := Export(value, ExportOption{
WithoutType: false,
}); s != "" {
fmt.Println(s)
}
}
}

// DumpBrief acts like Dump, but with no type information.
// Also see Dump.
func DumpBrief(values ...interface{}) {
for _, value := range values {
if s := Export(value, ExportOption{
WithoutType: true,
}); s != "" {
fmt.Println(s)
}
}
}

// Export returns variables <i...> as a string with more manually readable.
func Export(i ...interface{}) string {
// Export returns variables `values` as a string with more manually readable.
func Export(value interface{}, option ExportOption) string {
buffer := bytes.NewBuffer(nil)
for _, value := range i {
switch r := value.(type) {
case []byte:
buffer.Write(r)
case string:
buffer.WriteString(r)
default:
var (
reflectValue = reflect.ValueOf(value)
reflectKind = reflectValue.Kind()
)
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
doExport(value, "", buffer, doExportOption{
WithoutType: option.WithoutType,
})
return buffer.String()
}

type doExportOption struct {
WithoutType bool
}

func doExport(value interface{}, indent string, buffer *bytes.Buffer, option doExportOption) {
var (
reflectValue = reflect.ValueOf(value)
reflectKind = reflectValue.Kind()
reflectTypeName = reflectValue.Type().String()
newIndent = indent + dumpIndent
)
if option.WithoutType {
reflectTypeName = ""
}
for reflectKind == reflect.Ptr {
reflectValue = reflectValue.Elem()
reflectKind = reflectValue.Kind()
}
switch reflectKind {
case reflect.Slice, reflect.Array:
if _, ok := value.([]byte); ok {
if option.WithoutType {
buffer.WriteString(fmt.Sprintf("\"%v\"\n", value))
} else {
buffer.WriteString(fmt.Sprintf(
"%s(%d) \"%v\"\n",
reflectTypeName,
len(reflectValue.String()),
value,
))
}
switch reflectKind {
case reflect.Slice, reflect.Array:
value = gconv.Interfaces(value)
case reflect.Map:
value = gconv.Map(value)
case reflect.Struct:
converted := false
if r, ok := value.(iVal); ok {
if result := r.Val(); result != nil {
value = result
converted = true
}
}
if !converted {
if r, ok := value.(iMapStrAny); ok {
if result := r.MapStrAny(); result != nil {
value = result
converted = true
}
}
}
if !converted {
if r, ok := value.(iString); ok {
value = r.String()
}
}
return
}
if reflectValue.Len() == 0 {
if option.WithoutType {
buffer.WriteString("[]")
} else {
buffer.WriteString(fmt.Sprintf("%s(0) []", reflectTypeName))
}
encoder := json.NewEncoder(buffer)
encoder.SetEscapeHTML(false)
encoder.SetIndent("", "\t")
if err := encoder.Encode(value); err != nil {
fmt.Fprintln(os.Stderr, err.Error())
return
}
if option.WithoutType {
buffer.WriteString("[\n")
} else {
buffer.WriteString(fmt.Sprintf("%s(%d) [\n", reflectTypeName, reflectValue.Len()))
}
for i := 0; i < reflectValue.Len(); i++ {
buffer.WriteString(newIndent)
doExport(reflectValue.Index(i).Interface(), newIndent, buffer, option)
buffer.WriteString(",\n")
}
buffer.WriteString(fmt.Sprintf("%s]", indent))

case reflect.Map:
var (
mapKeys = reflectValue.MapKeys()
)
if len(mapKeys) == 0 {
if option.WithoutType {
buffer.WriteString("{}")
} else {
buffer.WriteString(fmt.Sprintf("%s(0) {}", reflectTypeName))
}
return
}

var (
maxSpaceNum = 0
tmpSpaceNum = 0
mapKeyStr = ""
)
for _, key := range mapKeys {
tmpSpaceNum = len(fmt.Sprintf(`%v`, key.Interface()))
if tmpSpaceNum > maxSpaceNum {
maxSpaceNum = tmpSpaceNum
}
}
if option.WithoutType {
buffer.WriteString("{\n")
} else {
buffer.WriteString(fmt.Sprintf("%s(%d) {\n", reflectTypeName, len(mapKeys)))
}
for _, mapKey := range mapKeys {
tmpSpaceNum = len(fmt.Sprintf(`%v`, mapKey.Interface()))
if mapKey.Kind() == reflect.String {
mapKeyStr = fmt.Sprintf(`"%v"`, mapKey.Interface())
} else {
mapKeyStr = fmt.Sprintf(`%v`, mapKey.Interface())
}
if option.WithoutType {
buffer.WriteString(fmt.Sprintf(
"%s%v:%s",
newIndent,
mapKeyStr,
gstr.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
} else {
buffer.WriteString(fmt.Sprintf(
"%s%s(%v):%s",
newIndent,
mapKey.Type().String(),
mapKeyStr,
gstr.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
}
doExport(reflectValue.MapIndex(mapKey).Interface(), newIndent, buffer, option)
buffer.WriteString(",\n")
}
buffer.WriteString(fmt.Sprintf("%s}", indent))

case reflect.Struct:
structFields, _ := structs.Fields(structs.FieldsInput{
Pointer: value,
RecursiveOption: structs.RecursiveOptionEmbeddedNoTag,
})
if len(structFields) == 0 {
if option.WithoutType {
buffer.WriteString("{}")
} else {
buffer.WriteString(fmt.Sprintf("%s(0) {}", reflectTypeName))
}
return
}

var (
maxSpaceNum = 0
tmpSpaceNum = 0
)
for _, field := range structFields {
tmpSpaceNum = len(field.Name())
if tmpSpaceNum > maxSpaceNum {
maxSpaceNum = tmpSpaceNum
}
}
if option.WithoutType {
buffer.WriteString("{\n")
} else {
buffer.WriteString(fmt.Sprintf("%s(%d) {\n", reflectTypeName, len(structFields)))
}
for _, field := range structFields {
tmpSpaceNum = len(fmt.Sprintf(`%v`, field.Name()))
buffer.WriteString(fmt.Sprintf(
"%s%s:%s",
newIndent,
field.Name(),
gstr.Repeat(" ", maxSpaceNum-tmpSpaceNum+1),
))
doExport(field.Value.Interface(), newIndent, buffer, option)
buffer.WriteString(",\n")
}
buffer.WriteString(fmt.Sprintf("%s}", indent))

case reflect.String:
if option.WithoutType {
buffer.WriteString(fmt.Sprintf("\"%v\"", value))
} else {
buffer.WriteString(fmt.Sprintf(
"%s(%d) \"%v\"",
reflectTypeName,
len(reflectValue.String()),
value,
))
}

default:
if option.WithoutType {
buffer.WriteString(fmt.Sprintf("%v", value))
} else {
buffer.WriteString(fmt.Sprintf("%s(%v)", reflectTypeName, value))
}
}
return buffer.String()
}
Loading

0 comments on commit 9777807

Please sign in to comment.