Просмотр исходного кода

Merge pull request #181 from ivnivnch/master

fmt.Stringer interface support in WriteSlice & WriteStruct
Geoffrey J. Teale 10 лет назад
Родитель
Сommit
4076bd52f2
2 измененных файлов с 83 добавлено и 37 удалено
  1. 47 33
      write.go
  2. 36 4
      write_test.go

+ 47 - 33
write.go

@@ -1,6 +1,9 @@
 package xlsx
 
-import "reflect"
+import (
+	"fmt"
+	"reflect"
+)
 
 // Writes an array to row r. Accepts a pointer to array type 'e',
 // and writes the number of columns to write, 'cols'. If 'cols' is < 0,
@@ -24,25 +27,31 @@ func (r *Row) WriteSlice(e interface{}, cols int) int {
 
 	var setCell func(reflect.Value)
 	setCell = func(val reflect.Value) {
-		switch val.Kind() { // underlying type of slice
-		case reflect.String:
+		switch t := val.Interface().(type) {
+		case fmt.Stringer: // check Stringer first
 			cell := r.AddCell()
-			cell.SetString(val.Interface().(string))
-		case reflect.Int, reflect.Int8,
-			reflect.Int16, reflect.Int32:
-			cell := r.AddCell()
-			cell.SetInt(val.Interface().(int))
-		case reflect.Int64:
-			cell := r.AddCell()
-			cell.SetInt64(val.Interface().(int64))
-		case reflect.Bool:
-			cell := r.AddCell()
-			cell.SetBool(val.Interface().(bool))
-		case reflect.Float64, reflect.Float32:
-			cell := r.AddCell()
-			cell.SetFloat(val.Interface().(float64))
-		case reflect.Interface:
-			setCell(reflect.ValueOf(val.Interface()))
+			cell.SetString(t.String())
+		default:
+			switch val.Kind() { // underlying type of slice
+			case reflect.String:
+				cell := r.AddCell()
+				cell.SetString(t.(string))
+			case reflect.Int, reflect.Int8,
+				reflect.Int16, reflect.Int32:
+				cell := r.AddCell()
+				cell.SetInt(t.(int))
+			case reflect.Int64:
+				cell := r.AddCell()
+				cell.SetInt64(t.(int64))
+			case reflect.Bool:
+				cell := r.AddCell()
+				cell.SetBool(t.(bool))
+			case reflect.Float64, reflect.Float32:
+				cell := r.AddCell()
+				cell.SetFloat(t.(float64))
+			case reflect.Interface:
+				setCell(reflect.ValueOf(t))
+			}
 		}
 	}
 
@@ -74,23 +83,28 @@ func (r *Row) WriteStruct(e interface{}, cols int) int {
 
 	var k int
 	for i := 0; i < n; i, k = i+1, k+1 {
-		f := v.Field(i).Kind()
+		f := v.Field(i)
 		cell := r.AddCell()
 
-		switch f {
-		case reflect.Int, reflect.Int8,
-			reflect.Int16, reflect.Int32:
-			cell.SetInt(v.Field(i).Interface().(int))
-		case reflect.Int64:
-			cell.SetInt64(v.Field(i).Interface().(int64))
-		case reflect.String:
-			cell.SetString(v.Field(i).Interface().(string))
-		case reflect.Float64, reflect.Float32:
-			cell.SetFloat(v.Field(i).Interface().(float64))
-		case reflect.Bool:
-			cell.SetBool(v.Field(i).Interface().(bool))
+		switch t := f.Interface().(type) {
+		case fmt.Stringer: // check Stringer first
+			cell.SetString(t.String())
 		default:
-			k-- // nothing set so reset to previous
+			switch f.Kind() {
+			case reflect.Int, reflect.Int8,
+				reflect.Int16, reflect.Int32:
+				cell.SetInt(t.(int))
+			case reflect.Int64:
+				cell.SetInt64(t.(int64))
+			case reflect.String:
+				cell.SetString(t.(string))
+			case reflect.Float64, reflect.Float32:
+				cell.SetFloat(t.(float64))
+			case reflect.Bool:
+				cell.SetBool(t.(bool))
+			default:
+				k-- // nothing set so reset to previous
+			}
 		}
 	}
 

+ 36 - 4
write_test.go

@@ -8,6 +8,14 @@ type WriteSuite struct{}
 
 var _ = Suite(&WriteSuite{})
 
+type testStringerImpl struct {
+	Value string
+}
+
+func (this testStringerImpl) String() string {
+	return this.Value
+}
+
 // Test if we can write a struct to a row
 func (r *RowSuite) TestWriteStruct(c *C) {
 	var f *File
@@ -15,16 +23,20 @@ func (r *RowSuite) TestWriteStruct(c *C) {
 	sheet, _ := f.AddSheet("Test1")
 	row := sheet.AddRow()
 	type e struct {
-		FirstName string
-		Age       int
-		GPA       float64
-		LikesPHP  bool
+		FirstName   string
+		Age         int
+		GPA         float64
+		LikesPHP    bool
+		Stringer    testStringerImpl
+		StringerPtr *testStringerImpl
 	}
 	testStruct := e{
 		"Eric",
 		20,
 		3.94,
 		false,
+		testStringerImpl{"Stringer"},
+		&testStringerImpl{"Pointer to Stringer"},
 	}
 	row.WriteStruct(&testStruct, -1)
 	c.Assert(row, NotNil)
@@ -33,11 +45,15 @@ func (r *RowSuite) TestWriteStruct(c *C) {
 	c1, e1 := row.Cells[1].Int()
 	c2, e2 := row.Cells[2].Float()
 	c3 := row.Cells[3].Bool()
+	c4 := row.Cells[4].String()
+	c5 := row.Cells[5].String()
 
 	c.Assert(c0, Equals, "Eric")
 	c.Assert(c1, Equals, 20)
 	c.Assert(c2, Equals, 3.94)
 	c.Assert(c3, Equals, false)
+	c.Assert(c4, Equals, "Stringer")
+	c.Assert(c5, Equals, "Pointer to Stringer")
 
 	c.Assert(e1, Equals, nil)
 	c.Assert(e2, Equals, nil)
@@ -54,6 +70,8 @@ func (r *RowSuite) TestWriteSlice(c *C) {
 	type floatA []float64
 	type boolA []bool
 	type interfaceA []interface{}
+	type stringerA []testStringerImpl
+	type stringerPtrA []*testStringerImpl
 
 	s0 := strA{"Eric"}
 	row0 := sheet.AddRow()
@@ -99,4 +117,18 @@ func (r *RowSuite) TestWriteSlice(c *C) {
 	c.Assert(c42, Equals, 3.94)
 	c43 := row4.Cells[3].Bool()
 	c.Assert(c43, Equals, true)
+
+	s5 := stringerA{testStringerImpl{"Stringer"}}
+	row5 := sheet.AddRow()
+	row5.WriteSlice(&s5, -1)
+	c.Assert(row5, NotNil)
+	c5 := row5.Cells[0].String()
+	c.Assert(c5, Equals, "Stringer")
+
+	s6 := stringerPtrA{&testStringerImpl{"Pointer to Stringer"}}
+	row6 := sheet.AddRow()
+	row6.WriteSlice(&s6, -1)
+	c.Assert(row6, NotNil)
+	c6 := row6.Cells[0].String()
+	c.Assert(c6, Equals, "Pointer to Stringer")
 }