From edbf7d3c2944fdd195e33fe72d2b2bad7adb2c35 Mon Sep 17 00:00:00 2001 From: soranoba Date: Sat, 19 Sep 2020 13:22:21 +0900 Subject: [PATCH] Fixed a bug that TextUnmarshaler does not work. --- accessor.go | 16 +++++++++++----- accessor_test.go | 16 ++++++++-------- googp_test.go | 38 +++++++++++++++++++++++++++----------- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/accessor.go b/accessor.go index d9992da..19ad6fd 100644 --- a/accessor.go +++ b/accessor.go @@ -41,16 +41,22 @@ type field struct { } func newAccessor(tag *tag, v reflect.Value) accessor { - switch reflect.Indirect(v).Kind() { + iv := reflect.Indirect(v) + switch iv.Kind() { case reflect.Array, reflect.Slice: - return &arrayAccessor{tag: tag, value: reflect.Indirect(v)} + return &arrayAccessor{tag: tag, value: iv} case reflect.Struct: - sv := reflect.Indirect(v) - t := sv.Type() + if iv.CanAddr() { + if iv.Addr().Type().Implements(reflect.TypeOf((*encoding.TextUnmarshaler)(nil)).Elem()) { + return newValueAccessor(v) + } + } + + t := iv.Type() fields := make(map[string]*field) for i := 0; i < t.NumField(); i++ { structField := t.Field(i) - fieldValue := sv.Field(i) + fieldValue := iv.Field(i) if !fieldValue.CanSet() { continue } diff --git a/accessor_test.go b/accessor_test.go index 8ba8d2c..1b4a7d3 100644 --- a/accessor_test.go +++ b/accessor_test.go @@ -8,20 +8,20 @@ import ( func Test_ValueAccessor(t *testing.T) { var s string - ac := newValueAccessor(reflect.ValueOf(s)) // string + ac := newAccessor(nil, reflect.ValueOf(s)) // string assertError(t, ac.Set("og:title", "title")) - ac = newValueAccessor(reflect.ValueOf(&s)) // *string + ac = newAccessor(nil, reflect.ValueOf(&s)) // *string assertNoError(t, ac.Set("og:title", "title")) assertEqual(t, s, "title") assertNoError(t, ac.Set("og:title", "title2")) assertEqual(t, s, "title") // cannot overwrite var time time.Time - ac = newValueAccessor(reflect.ValueOf(time)) // URL + ac = newAccessor(nil, reflect.ValueOf(time)) // Time assertError(t, ac.Set("video:release_date", "2020-05-20T01:01:25Z")) - ac = newValueAccessor(reflect.ValueOf(&time)) // *URL + ac = newAccessor(nil, reflect.ValueOf(&time)) // *Time assertNoError(t, ac.Set("video:release_date", "2020-05-20T01:01:25Z")) assertEqual(t, time.String(), "2020-05-20 01:01:25 +0000 UTC") @@ -42,10 +42,10 @@ func Test_ValueAccessor(t *testing.T) { assertEqual(t, u, uint(123)) var f float64 - ac = newValueAccessor(reflect.ValueOf(f)) // float64 + ac = newAccessor(nil, reflect.ValueOf(f)) // float64 assertError(t, ac.Set("og:number", "23.5")) - ac = newValueAccessor(reflect.ValueOf(&f)) // *float64 + ac = newAccessor(nil, reflect.ValueOf(&f)) // *float64 assertNoError(t, ac.Set("og:number", "23.5")) assertEqual(t, f, float64(23.5)) } @@ -109,7 +109,7 @@ func Test_StructAccessor(t *testing.T) { var v struct { Title string `googp:"og:title"` Description *string `googp:"og:description"` - Url *string `googp:"og:url"` + URL *string `googp:"og:url"` } ac := newAccessor(nil, reflect.ValueOf(v)) @@ -121,7 +121,7 @@ func Test_StructAccessor(t *testing.T) { assertNoError(t, ac.Set("og:description", "description")) assertEqual(t, v.Title, "title") assertEqual(t, *v.Description, "description") - assertEqual(t, v.Url, (*string)(nil)) + assertEqual(t, v.URL, (*string)(nil)) } func Test_StructAccessor_ConflictTag(t *testing.T) { diff --git a/googp_test.go b/googp_test.go index 38ab27d..8ee58e6 100644 --- a/googp_test.go +++ b/googp_test.go @@ -52,21 +52,35 @@ func ExampleFetch() { return } - fmt.Printf("og:title = \"%s\"", ogp.Title) - fmt.Printf("og:type = \"%s\"", ogp.Type) - fmt.Printf("og:url = \"%s\"", ogp.URL) + fmt.Printf("og:title = \"%s\"\n", ogp.Title) + fmt.Printf("og:type = \"%s\"\n", ogp.Type) + fmt.Printf("og:url = \"%s\"\n", ogp.URL) - // Outputs: + // Output: // og:title = "Open Graph protocol" // og:type = "website" // og:url = "https://ogp.me/" } +type URL struct { + url.URL +} + +func (url *URL) UnmarshalText(text []byte) error { + u, err := url.Parse(string(text)) + if err != nil { + return err + } + url.URL = *u + return nil +} + func ExampleFetch_customizeModel() { type MyOGP struct { - Title string `googp:"og:title"` - URL url.URL `googp:"og:url"` - AppID int `googp:"fb:app_id"` + Title string `googp:"og:title"` + URL URL `googp:"og:url"` + ImageURL *URL `googp:"og:image"` + AppID int `googp:"fb:app_id"` } var ogp MyOGP @@ -74,13 +88,15 @@ func ExampleFetch_customizeModel() { return } - fmt.Printf("og:title = \"%s\"", ogp.Title) - fmt.Printf("og:url = \"%s\"", ogp.URL.String()) - fmt.Printf("fb:app_id = \"%d\"", ogp.AppID) + fmt.Printf("og:title = \"%s\"\n", ogp.Title) + fmt.Printf("og:url = \"%s\"\n", ogp.URL.String()) + fmt.Printf("og:image = \"%s\"\n", ogp.ImageURL.String()) + fmt.Printf("fb:app_id = %d\n", ogp.AppID) - // Outputs: + // Output: // og:title = "Open Graph protocol" // og:url = "https://ogp.me/" + // og:image = "https://ogp.me/logo.png" // fb:app_id = 115190258555800 }