From e2565063ed35c6723f0ce524561abb0444ba5ac7 Mon Sep 17 00:00:00 2001
From: josephyu <josephyu@tencent.com>
Date: Sun, 16 Aug 2020 15:26:57 +0800
Subject: [PATCH] Make lookup support Ptr type

---
 lookup.go      | 30 +++++++++++++++++++++---------
 lookup_test.go |  8 ++++++++
 2 files changed, 29 insertions(+), 9 deletions(-)

diff --git a/lookup.go b/lookup.go
index 763e8e8..860eab8 100644
--- a/lookup.go
+++ b/lookup.go
@@ -43,17 +43,14 @@ func lookup(name string, context ...interface{}) (interface{}, bool) {
 		// struct that matches the name. In the near future I'd like to add
 		// support for matching struct names to tags so we can use lower_case
 		// names in our templates which makes it more mustache like.
+		case reflect.Ptr:
+			reflectValue = reflectValue.Elem()
+			fallthrough
 		case reflect.Struct:
-			field := reflectValue.FieldByName(name)
-			if field.IsValid() {
-				return field.Interface(), truth(field)
+			result, isTrue := lookupStructByName(reflectValue, name)
+			if result != nil {
+				return result, isTrue
 			}
-			method := reflectValue.MethodByName(name)
-			if method.IsValid() && method.Type().NumIn() == 1 {
-				out := method.Call(nil)[0]
-				return out.Interface(), truth(out)
-			}
-
 		}
 		// If by this point no value was matched, we'll move up a step in the
 		// chain and try to match a value there.
@@ -63,6 +60,21 @@ func lookup(name string, context ...interface{}) (interface{}, bool) {
 	return nil, false
 }
 
+// lookupStructByName will return the field or the method result with the given name.
+// Returns nil, false if no such field or method.
+func lookupStructByName(reflectValue reflect.Value, name string) (interface{}, bool) {
+	field := reflectValue.FieldByName(name)
+	if field.IsValid() {
+		return field.Interface(), truth(field)
+	}
+	method := reflectValue.MethodByName(name)
+	if method.IsValid() && method.Type().NumIn() == 1 {
+		out := method.Call(nil)[0]
+		return out.Interface(), truth(out)
+	}
+	return nil, false
+}
+
 // The truth function will tell us if r is a truthy value or not. This is
 // important for sections as they will render their content based on the output
 // of this function.
diff --git a/lookup_test.go b/lookup_test.go
index eb58628..d5f5906 100644
--- a/lookup_test.go
+++ b/lookup_test.go
@@ -24,6 +24,13 @@ func TestSimpleLookup(t *testing.T) {
 				"map": map[string]interface{}{
 					"in": "I'm nested!",
 				},
+				"ptr": &struct {
+					Foo *struct{ Bar string }
+				}{
+					Foo: &struct{ Bar string }{
+						Bar: "bar",
+					},
+				},
 			},
 			assertions: []struct {
 				name  string
@@ -34,6 +41,7 @@ func TestSimpleLookup(t *testing.T) {
 				{"string", "abc", true},
 				{"boolean", true, true},
 				{"map.in", "I'm nested!", true},
+				{"ptr.Foo.Bar", "bar", true},
 			},
 		},
 		{