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 contains various utilities functions to work with structs.
|
||||||
package structs
|
package structs
|
||||||
|
|
||||||
import "reflect"
|
import (
|
||||||
|
"fmt"
|
||||||
|
|
||||||
|
"reflect"
|
||||||
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// DefaultTagName is the default tag name for struct fields which provides
|
// 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 is ignored by this package.
|
||||||
// Field bool `structs:"-"`
|
// 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
|
// A tag value with the option of "omitnested" stops iterating further if the type
|
||||||
// is a struct. Example:
|
// is a struct. Example:
|
||||||
//
|
//
|
||||||
@ -104,6 +114,14 @@ func (s *Struct) Map() map[string]interface{} {
|
|||||||
finalVal = val.Interface()
|
finalVal = val.Interface()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if tagOpts.Has("string") {
|
||||||
|
s, ok := val.Interface().(fmt.Stringer)
|
||||||
|
if ok {
|
||||||
|
out[name] = s.String()
|
||||||
|
}
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
out[name] = finalVal
|
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") {
|
if IsStruct(val.Interface()) && !tagOpts.Has("omitnested") {
|
||||||
// look out for embedded structs, and convert them to a
|
// look out for embedded structs, and convert them to a
|
||||||
// []interface{} to be added to the final values slice
|
// []interface{} to be added to the final values slice
|
||||||
|
|||||||
@ -910,3 +910,89 @@ func TestNestedNilPointer(t *testing.T) {
|
|||||||
_ = Map(personWithDog) // Panics
|
_ = Map(personWithDog) // Panics
|
||||||
_ = Map(personWithDogWithCollar) // Doesn't panic
|
_ = 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