use stringer if string tag option is used
This commit is contained in:
parent
dd04ebad3d
commit
89d5c9d448
28
structs.go
28
structs.go
@ -1,7 +1,11 @@
|
||||
// Package structs contains various utilities functions to work with structs.
|
||||
package structs
|
||||
|
||||
import "reflect"
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"reflect"
|
||||
)
|
||||
|
||||
var (
|
||||
// DefaultTagName is the default tag name for struct fields which provides
|
||||
@ -42,6 +46,12 @@ func New(s interface{}) *Struct {
|
||||
// // Field is ignored by this package.
|
||||
// Field bool `structs:"-"`
|
||||
//
|
||||
// A tag value with the content of "string" uses the stringer to get the value. Example:
|
||||
//
|
||||
// // The value will be output of Animal's String() func.
|
||||
// // Map will panic if Animal does not implement String().
|
||||
// Field *Animal `structs:"field,string"`
|
||||
//
|
||||
// A tag value with the option of "omitnested" stops iterating further if the type
|
||||
// is a struct. Example:
|
||||
//
|
||||
@ -104,6 +114,14 @@ func (s *Struct) Map() map[string]interface{} {
|
||||
finalVal = val.Interface()
|
||||
}
|
||||
|
||||
if tagOpts.Has("string") {
|
||||
s, ok := val.Interface().(fmt.Stringer)
|
||||
if ok {
|
||||
out[name] = s.String()
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
out[name] = finalVal
|
||||
}
|
||||
|
||||
@ -153,6 +171,14 @@ func (s *Struct) Values() []interface{} {
|
||||
}
|
||||
}
|
||||
|
||||
if tagOpts.Has("string") {
|
||||
s, ok := val.Interface().(fmt.Stringer)
|
||||
if ok {
|
||||
t = append(t, s.String())
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||
// look out for embedded structs, and convert them to a
|
||||
// []interface{} to be added to the final values slice
|
||||
|
||||
@ -910,3 +910,89 @@ func TestNestedNilPointer(t *testing.T) {
|
||||
_ = Map(personWithDog) // Panics
|
||||
_ = Map(personWithDogWithCollar) // Doesn't panic
|
||||
}
|
||||
|
||||
type Person struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
func (p *Person) String() string {
|
||||
return fmt.Sprintf("%s(%d)", p.Name, p.Age)
|
||||
}
|
||||
|
||||
func TestTagWithStringOption(t *testing.T) {
|
||||
|
||||
type Address struct {
|
||||
Country string `json:"country"`
|
||||
Person *Person `json:"person,string"`
|
||||
}
|
||||
|
||||
person := &Person{
|
||||
Name: "John",
|
||||
Age: 23,
|
||||
}
|
||||
|
||||
address := &Address{
|
||||
Country: "EU",
|
||||
Person: person,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
fmt.Printf("err %+v\n", err)
|
||||
t.Error("Internal nil pointer should not panic")
|
||||
}
|
||||
}()
|
||||
|
||||
s := New(address)
|
||||
|
||||
s.TagName = "json"
|
||||
m := s.Map()
|
||||
|
||||
if m["person"] != person.String() {
|
||||
t.Errorf("Value for field person should be %s, got: %s", person.String(), m["person"])
|
||||
}
|
||||
|
||||
vs := s.Values()
|
||||
if vs[1] != person.String() {
|
||||
t.Errorf("Value for 2nd field (person) should be %t, got: %t", person.String(), vs[1])
|
||||
}
|
||||
}
|
||||
|
||||
type Animal struct {
|
||||
Name string
|
||||
Age int
|
||||
}
|
||||
|
||||
type Dog struct {
|
||||
Animal *Animal `json:"animal,string"`
|
||||
}
|
||||
|
||||
func TestNonStringerTagWithStringOption(t *testing.T) {
|
||||
a := &Animal{
|
||||
Name: "Fluff",
|
||||
Age: 4,
|
||||
}
|
||||
|
||||
d := &Dog{
|
||||
Animal: a,
|
||||
}
|
||||
|
||||
defer func() {
|
||||
err := recover()
|
||||
if err != nil {
|
||||
fmt.Printf("err %+v\n", err)
|
||||
t.Error("Internal nil pointer should not panic")
|
||||
}
|
||||
}()
|
||||
|
||||
s := New(d)
|
||||
|
||||
s.TagName = "json"
|
||||
m := s.Map()
|
||||
|
||||
if _, exists := m["animal"]; exists {
|
||||
t.Errorf("Value for field Animal should not exist")
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user