Merge pull request #91 from danw/replace_strptr

AppendProperties: Replace *strings instead of appending
diff --git a/proptools/extend.go b/proptools/extend.go
index d356419..6ebbff3 100644
--- a/proptools/extend.go
+++ b/proptools/extend.go
@@ -29,8 +29,8 @@
 // An error returned by AppendProperties that applies to a specific property will be an
 // *ExtendPropertyError, and can have the property name and error extracted from it.
 //
-// The append operation is defined as appending strings, pointers to strings, and slices of
-// strings normally, OR-ing bool values, replacing non-nil pointers to booleans, and recursing into
+// The append operation is defined as appending strings and slices of strings normally, OR-ing bool
+// values, replacing non-nil pointers to booleans or strings, and recursing into
 // embedded structs, pointers to structs, and interfaces containing
 // pointers to structs.  Appending the zero value of a property will always be a no-op.
 func AppendProperties(dst interface{}, src interface{}, filter ExtendPropertyFilterFunc) error {
@@ -47,8 +47,8 @@
 // An error returned by PrependProperties that applies to a specific property will be an
 // *ExtendPropertyError, and can have the property name and error extracted from it.
 //
-// The prepend operation is defined as prepending strings, pointers to strings, and slices of
-// strings normally, OR-ing bool values, replacing non-nil pointers to booleans, and recursing into
+// The prepend operation is defined as prepending strings, and slices of strings normally, OR-ing
+// bool values, replacing non-nil pointers to booleans or strings, and recursing into
 // embedded structs, pointers to structs, and interfaces containing
 // pointers to structs.  Prepending the zero value of a property will always be a no-op.
 func PrependProperties(dst interface{}, src interface{}, filter ExtendPropertyFilterFunc) error {
@@ -67,8 +67,8 @@
 // An error returned by AppendMatchingProperties that applies to a specific property will be an
 // *ExtendPropertyError, and can have the property name and error extracted from it.
 //
-// The append operation is defined as appending strings, pointers to strings, and slices of
-// strings normally, OR-ing bool values, replacing non-nil pointers to booleans, and recursing into
+// The append operation is defined as appending strings, and slices of strings normally, OR-ing bool
+// values, replacing non-nil pointers to booleans or strings, and recursing into
 // embedded structs, pointers to structs, and interfaces containing
 // pointers to structs.  Appending the zero value of a property will always be a no-op.
 func AppendMatchingProperties(dst []interface{}, src interface{},
@@ -88,8 +88,8 @@
 // An error returned by PrependProperties that applies to a specific property will be an
 // *ExtendPropertyError, and can have the property name and error extracted from it.
 //
-// The prepend operation is defined as prepending strings, pointers to strings, and slices of
-// strings normally, OR-ing bool values, replacing non-nil pointers to booleans, and recursing into
+// The prepend operation is defined as prepending strings, and slices of strings normally, OR-ing
+// bool values, replacing non-nil pointers to booleans or strings, and recursing into
 // embedded structs, pointers to structs, and interfaces containing
 // pointers to structs.  Prepending the zero value of a property will always be a no-op.
 func PrependMatchingProperties(dst []interface{}, src interface{},
@@ -321,14 +321,13 @@
 						dstFieldValue.Set(reflect.ValueOf(BoolPtr(srcFieldValue.Elem().Bool())))
 					}
 				case reflect.String:
-					dstStr := ""
-					if !dstFieldValue.IsNil() {
-						dstStr = dstFieldValue.Elem().String()
-					}
 					if prepend {
-						dstFieldValue.Set(reflect.ValueOf(StringPtr(srcFieldValue.Elem().String() + dstStr)))
+						if dstFieldValue.IsNil() {
+							dstFieldValue.Set(reflect.ValueOf(StringPtr(srcFieldValue.Elem().String())))
+						}
 					} else {
-						dstFieldValue.Set(reflect.ValueOf(StringPtr(dstStr + srcFieldValue.Elem().String())))
+						// For append, replace the original value.
+						dstFieldValue.Set(reflect.ValueOf(StringPtr(srcFieldValue.Elem().String())))
 					}
 				default:
 					panic(fmt.Errorf("unexpected pointer kind %s", ptrKind))
diff --git a/proptools/extend_test.go b/proptools/extend_test.go
index 64b7040..edf28fd 100644
--- a/proptools/extend_test.go
+++ b/proptools/extend_test.go
@@ -184,7 +184,7 @@
 			S3: StringPtr("string4"),
 		},
 		out: &struct{ S1, S2, S3, S4 *string }{
-			S1: StringPtr("string1string3"),
+			S1: StringPtr("string3"),
 			S2: StringPtr("string2"),
 			S3: StringPtr("string4"),
 			S4: nil,
@@ -201,7 +201,7 @@
 			S3: StringPtr("string4"),
 		},
 		out: &struct{ S1, S2, S3, S4 *string }{
-			S1: StringPtr("string3string1"),
+			S1: StringPtr("string1"),
 			S2: StringPtr("string2"),
 			S3: StringPtr("string4"),
 			S4: nil,