From 6d96051dadb29d11442d7a14eae150003a6b0f9f Mon Sep 17 00:00:00 2001 From: Radek Simko Date: Wed, 3 Aug 2016 23:35:43 +0100 Subject: [PATCH] Add support for omitempty tag option --- struct.go | 35 ++++++++++++++++++++++++++++++++++- struct_test.go | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+), 1 deletion(-) diff --git a/struct.go b/struct.go index f4620af..a1efa17 100644 --- a/struct.go +++ b/struct.go @@ -19,6 +19,7 @@ import ( "errors" "fmt" "reflect" + "strings" "time" "unicode" ) @@ -323,6 +324,26 @@ func reflectWithProperType(t reflect.Type, key *Key, field reflect.Value, delim return nil } +func isEmptyValue(v reflect.Value) bool { + switch v.Kind() { + case reflect.Array, reflect.Map, reflect.Slice, reflect.String: + return v.Len() == 0 + case reflect.Bool: + return !v.Bool() + case reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64: + return v.Int() == 0 + case reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr: + return v.Uint() == 0 + case reflect.Float32, reflect.Float64: + return v.Float() == 0 + case reflectTime: + return v.Interface().(time.Time).IsZero() + case reflect.Interface, reflect.Ptr: + return v.IsNil() + } + return false +} + func (s *Section) reflectFrom(val reflect.Value) error { if val.Kind() == reflect.Ptr { val = val.Elem() @@ -338,7 +359,19 @@ func (s *Section) reflectFrom(val reflect.Value) error { continue } - fieldName := s.parseFieldName(tpField.Name, tag) + opts := strings.Split(tag, ",") + if len(opts) > 2 { + return fmt.Errorf("Expected max. 2 comma-separated values in a tag, %d given", len(opts)) + } + + if len(opts) == 2 { + v := opts[1] + if v == "omitempty" && isEmptyValue(field) { + continue + } + } + + fieldName := s.parseFieldName(tpField.Name, opts[0]) if len(fieldName) == 0 || !field.CanSet() { continue } diff --git a/struct_test.go b/struct_test.go index b3f5d46..39763c1 100644 --- a/struct_test.go +++ b/struct_test.go @@ -269,6 +269,38 @@ None = Convey("Reflect from non-point struct", func() { So(ReflectFrom(cfg, Author{}), ShouldNotBeNil) }) + + Convey("Reflect from struct with omitempty", func() { + cfg := Empty() + type SpecialStruct struct { + FirstName string `ini:"first_name"` + LastName string `ini:"last_name"` + JustOmitMe string `ini:"omitempty"` + LastLogin time.Time `ini:"last_login,omitempty"` + LastLogin2 time.Time `ini:",omitempty"` + NotEmpty int `ini:"omitempty"` + } + + So(ReflectFrom(cfg, &SpecialStruct{FirstName: "John", LastName: "Doe", NotEmpty: 9}), ShouldBeNil) + + var buf bytes.Buffer + _, err = cfg.WriteTo(&buf) + So(buf.String(), ShouldEqual, `first_name = John +last_name = Doe +omitempty = 9 + +`) + }) + + Convey("Reflect from struct with too many opts in a tag", func() { + cfg := Empty() + type SpecialStruct struct { + TooManyOpts string `ini:"first_name,second,third"` + LastName string `ini:"last_name"` + } + + So(ReflectFrom(cfg, &SpecialStruct{TooManyOpts: "John", LastName: "Doe"}), ShouldNotBeNil) + }) }) }