mirror of
https://github.com/gohugoio/hugo.git
synced 2024-11-21 20:46:30 -05:00
debug: Add method debug.List
The method returns a slice of field names and method names of the struct/pointer or keys of the map. This method scans the provided value shallow, non-recursively. The method is aimed to make debugging variables easier. Fixes 9148 # Conflicts: # tpl/debug/debug.go
This commit is contained in:
parent
2b97a2a8bf
commit
36df350f52
2 changed files with 109 additions and 0 deletions
|
@ -15,6 +15,10 @@
|
||||||
package debug
|
package debug
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"reflect"
|
||||||
|
"sort"
|
||||||
|
|
||||||
|
"github.com/sanity-io/litter"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"sort"
|
"sort"
|
||||||
"sync"
|
"sync"
|
||||||
|
@ -181,3 +185,47 @@ func (ns *Namespace) TestDeprecationErr(item, alternative string) string {
|
||||||
hugo.Deprecate(item, alternative, v.String())
|
hugo.Deprecate(item, alternative, v.String())
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// List returns a slice of field names and method names of the struct/pointer or keys of the map
|
||||||
|
// This method scans the provided value shallow, non-recursively.
|
||||||
|
func (ns *Namespace) List(val any) []string {
|
||||||
|
|
||||||
|
fields := make([]string, 0)
|
||||||
|
value := reflect.ValueOf(val)
|
||||||
|
|
||||||
|
if value.Kind() == reflect.Map {
|
||||||
|
for _, key := range value.MapKeys() {
|
||||||
|
fields = append(fields, key.String())
|
||||||
|
sort.Strings(fields)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dereference the pointer if needed
|
||||||
|
if value.Kind() == reflect.Pointer {
|
||||||
|
value = value.Elem()
|
||||||
|
}
|
||||||
|
|
||||||
|
if value.Kind() == reflect.Struct {
|
||||||
|
// Iterate over the fields
|
||||||
|
for i := 0; i < value.NumField(); i++ {
|
||||||
|
field := value.Type().Field(i)
|
||||||
|
|
||||||
|
// Only add exported fields
|
||||||
|
if field.PkgPath == "" {
|
||||||
|
fields = append(fields, field.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Calling NumMethod() on the pointer type returns the number of methods
|
||||||
|
// defined for the pointer type as well as the non pointer type.
|
||||||
|
// Calling NumMethod() on the non pointer type returns on the other hand only the number of non pointer methods.
|
||||||
|
pointerType := reflect.PointerTo(value.Type())
|
||||||
|
|
||||||
|
for i := 0; i < pointerType.NumMethod(); i++ {
|
||||||
|
method := pointerType.Method(i)
|
||||||
|
fields = append(fields, method.Name)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return fields
|
||||||
|
}
|
||||||
|
|
61
tpl/debug/debug_test.go
Normal file
61
tpl/debug/debug_test.go
Normal file
|
@ -0,0 +1,61 @@
|
||||||
|
// Copyright 2023 The Hugo Authors. All rights reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
package debug
|
||||||
|
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"reflect"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
type User struct {
|
||||||
|
Name string
|
||||||
|
Address any
|
||||||
|
foo string
|
||||||
|
}
|
||||||
|
|
||||||
|
func (u *User) M1() string { return "" }
|
||||||
|
func (u *User) M2(v string) string { return "" }
|
||||||
|
func (u *User) m3(v string) string { return "" }
|
||||||
|
|
||||||
|
// Non Pointer type methods
|
||||||
|
func (u User) M4(v string) string { return "" }
|
||||||
|
func (u User) m5(v string) string { return "" }
|
||||||
|
|
||||||
|
func TestList(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
namespace := new(Namespace)
|
||||||
|
|
||||||
|
for i, test := range []struct {
|
||||||
|
val any
|
||||||
|
expect []string
|
||||||
|
}{
|
||||||
|
// Map
|
||||||
|
{map[string]any{"key1": 1, "key2": 2, "key3": 3}, []string{"key1", "key2", "key3"}},
|
||||||
|
// Map non string keys
|
||||||
|
{map[int]any{1: 1, 2: 2, 3: 3}, []string{"<int Value>", "<int Value>", "<int Value>"}},
|
||||||
|
// Struct
|
||||||
|
{User{}, []string{"Name", "Address", "M1", "M2", "M4"}},
|
||||||
|
// Pointer
|
||||||
|
{&User{}, []string{"Name", "Address", "M1", "M2", "M4"}},
|
||||||
|
} {
|
||||||
|
t.Run(fmt.Sprintf("test%d", i), func(t *testing.T) {
|
||||||
|
result := namespace.List(test.val)
|
||||||
|
|
||||||
|
if !reflect.DeepEqual(result, test.expect) {
|
||||||
|
t.Fatalf("List called with value: %#v got\n%#v but expected\n%#v", test.val, result, test.expect)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue