From edbf7d3c2944fdd195e33fe72d2b2bad7adb2c35 Mon Sep 17 00:00:00 2001
From: soranoba <soranoba@gmail.com>
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
 }