Skip to content

Commit

Permalink
Improve Get
Browse files Browse the repository at this point in the history
  • Loading branch information
sunfmin committed Apr 20, 2019
1 parent 121efe8 commit d7d7515
Show file tree
Hide file tree
Showing 7 changed files with 148 additions and 50 deletions.
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -76,8 +76,9 @@ By given these structs
}

type Company struct {
Name string
Phone *Phone
Name string
Phone *Phone
Phone2 **Phone
}

type Department struct {
Expand Down
9 changes: 6 additions & 3 deletions example_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package reflectutils
package reflectutils_test

import (
"encoding/json"
"fmt"

. "github.com/sunfmin/reflectutils"
)

// By given these structs
Expand All @@ -24,8 +26,9 @@ func ExampleSet_0init() {
}

type Company struct {
Name string
Phone *Phone
Name string
Phone *Phone
Phone2 **Phone
}

type Department struct {
Expand Down
40 changes: 16 additions & 24 deletions get.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
package reflectutils

import (
"errors"
"fmt"
"reflect"
"strings"
Expand All @@ -19,36 +18,22 @@ func MustGet(i interface{}, name string) (value interface{}) {

// Get value of a struct by path using reflect.
func Get(i interface{}, name string) (value interface{}, err error) {

v := reflect.ValueOf(i)

if v.Kind() != reflect.Ptr {
err = errors.New("get object must be a pointer")
return
}

for v.Elem().Kind() == reflect.Ptr {
v = v.Elem()
}

if v.IsNil() {
return
}

sv := v.Elem()
// printv(i, name)

if name == "" {
value = sv.Interface()
value = i
return
}

v := reflect.ValueOf(i)

var token *dotToken
token, err = nextDot(name)
if err != nil {
return
}

// printv(sv.Interface(), name, value)
sv := v

if sv.Kind() == reflect.Map {
// map must have string type
Expand All @@ -72,7 +57,7 @@ func Get(i interface{}, name string) (value interface{}, err error) {
mapElem.Set(existElem)
}

value, err = Get(mapElem.Addr().Interface(), token.Left)
value, err = Get(mapElem.Interface(), token.Left)
if err != nil {
return
}
Expand All @@ -96,14 +81,22 @@ func Get(i interface{}, name string) (value interface{}, err error) {
return
}

value, err = Get(arrayElem.Addr().Interface(), token.Left)
value, err = Get(arrayElem.Interface(), token.Left)
if err != nil {
return
}

return
}

if sv.Kind() != reflect.Struct {
for sv.Elem().Kind() == reflect.Ptr {
sv = sv.Elem()
}

sv = sv.Elem()
}

if sv.Kind() == reflect.Struct {
fv := sv.FieldByNameFunc(func(fname string) bool {
return strings.EqualFold(fname, token.Field)
Expand All @@ -113,8 +106,7 @@ func Get(i interface{}, name string) (value interface{}, err error) {
err = NoSuchFieldError
return
}

value, err = Get(fv.Addr().Interface(), token.Left)
value, err = Get(fv.Interface(), token.Left)
return
}

Expand Down
4 changes: 3 additions & 1 deletion map_slice_test.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package reflectutils
package reflectutils_test

import (
"testing"

. "github.com/sunfmin/reflectutils"
)

type mapTest struct {
Expand Down
14 changes: 0 additions & 14 deletions populate_test.go

This file was deleted.

5 changes: 2 additions & 3 deletions set.go
Original file line number Diff line number Diff line change
Expand Up @@ -224,17 +224,16 @@ func nextDot(name string) (t *dotToken, err error) {
return
}

func printv(v interface{}, name interface{}, value string) {
func printv(v interface{}, name interface{}) {
log.Println("=====")
rv := reflect.ValueOf(v)
log.Printf(
"\n\tname: %+v, \n\tv: %+v, \n\trv: %+v, \n\trv.Kind(): %+v, \n\trv.Type(): %+v, \n\trv.IsNil(): %+v, \n\trv.IsValid(): %+v",
"\n\tname: %+v, \n\tv: %+v, \n\trv: %+v, \n\trv.Kind(): %+v, \n\trv.Type(): %+v, \n\trv.IsValid(): %+v",
name,
v,
rv,
rv.Kind(),
rv.Type(),
"",
rv.IsValid(),
)
log.Println("=====")
Expand Down
121 changes: 118 additions & 3 deletions struct_test.go
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
package reflectutils
package reflectutils_test

import (
"fmt"
"reflect"
"testing"

. "github.com/sunfmin/reflectutils"
)

type Person struct {
Expand All @@ -22,8 +25,9 @@ type Language struct {
}

type Company struct {
Name string
Phone *Phone
Name string
Phone *Phone
Phone2 **Phone `json:"-"`
}

type Department struct {
Expand Down Expand Up @@ -198,3 +202,114 @@ func TestSetOtherPointers(t *testing.T) {
t.Errorf("set failed %+v", v)
}
}

var phone158 = &Phone{
Number: "158",
}

var getcases = []struct {
Name string
Value interface{}
ExpectedGetType string
}{
{
Name: "",
Value: &Person{
Company: &Company{
Name: "The Plant",
},
},
ExpectedGetType: "*reflectutils_test.Person",
},
{
Name: "Company",
Value: &Person{
Company: &Company{
Name: "The Plant",
},
},
ExpectedGetType: "*reflectutils_test.Company",
},
{
Name: "Company.Phone2",
Value: &Person{
Company: &Company{
Phone2: &phone158,
},
},
ExpectedGetType: "**reflectutils_test.Phone",
},
{
Name: "Company.Phone2.Number",
Value: &Person{
Company: &Company{
Phone2: &phone158,
},
},
ExpectedGetType: "string",
},
{
Name: "Phones.Home",
Value: &Person{
Phones: map[string]string{
"Home": "158",
},
},
ExpectedGetType: "string",
},
{
Name: "Languages.en_US.Name",
Value: &Person{
Languages: map[string]Language{
"en_US": Language{
Name: "English",
},
},
},
ExpectedGetType: "string",
},
{
Name: "Projects[1].Name",
Value: &Person{
Projects: []*Project{
{
Name: "Top1",
},
{
Name: "Top2",
},
},
},
ExpectedGetType: "string",
},
}

func TestGet(t *testing.T) {

for _, c := range getcases {
t.Run(c.Name, func(t2 *testing.T) {
v, err := Get(c.Value, c.Name)
if err != nil {
panic(err)
}

typeName := reflect.ValueOf(v).Type().String()
if typeName != c.ExpectedGetType {
panic(fmt.Sprintf("expected is %v, but was %v", c.ExpectedGetType, typeName))
}
})
}

var p = &Person{
Company: &Company{
Name: "The Plant 1",
},
}

c1 := MustGet(p, "Company").(*Company)

c1.Name = "The Plant 2"
if p.Company.Name != c1.Name {
panic(fmt.Sprintf("expected is %v, but was %v", c1.Name, p.Company.Name))
}
}

0 comments on commit d7d7515

Please sign in to comment.