diff --git a/README.md b/README.md index a290d3d..c393521 100644 --- a/README.md +++ b/README.md @@ -53,26 +53,37 @@ and you will get file user_tag.go: //go:generate gtag -types User -tags bson . package tutorial -import "reflect" +import ( + "reflect" + "strings" +) var ( // ... ) +// UserTags indicate tags of type User type UserTags struct { - Id string - Name string - Email string + Id string // `bson:"_id"` + Name string // `bson:"name"` + Email string // `bson:"email"` } -func (User) Tags(tag string) UserTags { +// Tags return specified tags of User +func (User) Tags(tag string, convert ...func(string) string) UserTags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 && convert[0] != nil { + conv = convert[0] + } + _ = conv return UserTags{ - Id: tagOfUserId.Get(tag), - Name: tagOfUserName.Get(tag), - Email: tagOfUserEmail.Get(tag), + Id: conv(tagOfUserId.Get(tag)), + Name: conv(tagOfUserName.Get(tag)), + Email: conv(tagOfUserEmail.Get(tag)), } } +// TagsBson is alias of Tags("bson") func (v User) TagsBson() UserTags { return v.Tags("bson") } diff --git a/go.mod b/go.mod index 5f5a8d6..a809687 100644 --- a/go.mod +++ b/go.mod @@ -4,6 +4,6 @@ go 1.14 require ( github.com/gochore/uniq v1.0.0 - github.com/pmezard/go-difflib v1.0.0 + github.com/google/go-cmp v0.4.0 golang.org/x/tools v0.0.0-20200505023115-26f46d2f7ef8 ) diff --git a/go.sum b/go.sum index 39ff1a2..75d59ee 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,7 @@ github.com/gochore/uniq v1.0.0 h1:qBA8Jm9GhSojZ8vsCI2h5FJGonmItjY9NLBPUaciOYk= github.com/gochore/uniq v1.0.0/go.mod h1:zxZBO4/6PcgNuYMrlJCUKOEEpxSejbD6R53GUpSHelk= -github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= -github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/google/go-cmp v0.4.0 h1:xsAVV57WRhGj6kEIi8ReJzQlHHqcBYCElAvkovg3B/4= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= diff --git a/internal/gtag/gtag.go b/internal/gtag/gtag.go index 74a69fa..26eef51 100644 --- a/internal/gtag/gtag.go +++ b/internal/gtag/gtag.go @@ -76,7 +76,7 @@ func generateFile(ctx context.Context, cmd, file string, types []string, tags [] } pkg := f.Name.Name - fieldM := map[string][]string{} + fieldM := map[string][]*ast.Field{} for _, typ := range types { fields, ok := parseStructField(f, typ) if ok { @@ -95,9 +95,23 @@ func generateFile(ctx context.Context, cmd, file string, types []string, tags [] for _, typ := range types { if fields, ok := fieldM[typ]; ok { + var tmpFields []templateDataTypeField + for _, field := range fields { + tag := "" + if field.Tag != nil { + tag = field.Tag.Value + } + for _, name := range field.Names { + tmpFields = append(tmpFields, templateDataTypeField{ + Name: name.Name, + Tag: tag, + }) + } + } + data.Types = append(data.Types, templateDataType{ Name: typ, - Fields: fields, + Fields: tmpFields, }) } } @@ -140,7 +154,7 @@ func loadFile(name string) (*ast.File, error) { return parser.ParseFile(token.NewFileSet(), name, f, 0) } -func parseStructField(f *ast.File, name string) ([]string, bool) { +func parseStructField(f *ast.File, name string) ([]*ast.Field, bool) { var fields []*ast.Field found := false @@ -166,12 +180,5 @@ func parseStructField(f *ast.File, name string) ([]string, bool) { return nil, found } - var ret []string - for _, field := range fields { - for _, v := range field.Names { - ret = append(ret, v.Name) - } - } - - return ret, found + return fields, found } diff --git a/internal/gtag/template.go b/internal/gtag/template.go index 5c198a6..3ddfcac 100644 --- a/internal/gtag/template.go +++ b/internal/gtag/template.go @@ -14,7 +14,12 @@ type templateData struct { type templateDataType struct { Name string - Fields []string + Fields []templateDataTypeField +} + +type templateDataTypeField struct { + Name string + Tag string } type templateDataTag struct { @@ -29,7 +34,10 @@ const templateLayout = ` //go:generate {{.Command}} package {{.Package}} -import "reflect" +import ( + "reflect" + "strings" +) {{$tags := .Tags}} {{- range .Types}} @@ -40,24 +48,32 @@ var ( {{$type := .Name}} {{- range .Fields}} - _ = valueOf{{$type}}.{{.}} - fieldOf{{$type}}{{.}}, _ = typeOf{{$type}}.FieldByName("{{.}}") - tagOf{{$type}}{{.}} = fieldOf{{$type}}{{.}}.Tag + _ = valueOf{{$type}}.{{.Name}} + fieldOf{{$type}}{{.Name}}, _ = typeOf{{$type}}.FieldByName("{{.Name}}") + tagOf{{$type}}{{.Name}} = fieldOf{{$type}}{{.Name}}.Tag {{end}} ) // {{$type}}Tags indicate tags of type {{$type}} type {{$type}}Tags struct { {{- range .Fields}} - {{.}} string + {{.Name}} string // {{.Tag}} {{- end}} } // Tags return specified tags of {{$type}} -func ({{$type}}) Tags(tag string) {{$type}}Tags { +func ({{$type}}) Tags(tag string, convert ...func(string) string) {{$type}}Tags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 { + conv = convert[0] + } + if conv == nil { + conv = func(in string) string { return in } + } + _ = conv return {{$type}}Tags{ {{- range .Fields}} - {{.}}: tagOf{{$type}}{{.}}.Get(tag), + {{.Name}}: conv(tagOf{{$type}}{{.Name}}.Get(tag)), {{- end}} } } diff --git a/internal/gtag/template_test.go b/internal/gtag/template_test.go index ff7d75e..d04f07a 100644 --- a/internal/gtag/template_test.go +++ b/internal/gtag/template_test.go @@ -3,7 +3,7 @@ package gtag import ( "testing" - "github.com/pmezard/go-difflib/difflib" + "github.com/google/go-cmp/cmp" ) func Test_execute(t *testing.T) { @@ -22,8 +22,17 @@ func Test_execute(t *testing.T) { Package: "test", Types: []templateDataType{ { - Name: "test", - Fields: []string{"A", "b"}, + Name: "test", + Fields: []templateDataTypeField{ + { + Name: "A", + Tag: `json:"a"`, + }, + { + Name: "b", + Tag: ``, + }, + }, }, }, Tags: []templateDataTag{ @@ -45,7 +54,10 @@ func Test_execute(t *testing.T) { //go:generate package test -import "reflect" +import ( + "reflect" + "strings" +) @@ -66,15 +78,23 @@ var ( // testTags indicate tags of type test type testTags struct { - A string - b string + A string // json:"a" + b string // } // Tags return specified tags of test -func (test) Tags(tag string) testTags { +func (test) Tags(tag string, convert ...func(string) string) testTags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 { + conv = convert[0] + } + if conv == nil { + conv = func(in string) string { return in } + } + _ = conv return testTags{ - A: tagOftestA.Get(tag), - b: tagOftestb.Get(tag), + A: conv(tagOftestA.Get(tag)), + b: conv(tagOftestb.Get(tag)), } } @@ -99,14 +119,7 @@ func (v test) TagsBson() testTags { t.Run(tt.name, func(t *testing.T) { if got := string(execute(tt.args.data)); got != tt.want { t.Errorf("execute() = %v, want %v", got, tt.want) - diff := difflib.UnifiedDiff{ - A: difflib.SplitLines(got), - B: difflib.SplitLines(tt.want), - FromFile: "got", - ToFile: "want", - } - text, _ := difflib.GetUnifiedDiffString(diff) - t.Log(text) + t.Error(cmp.Diff(got, tt.want)) } }) } diff --git a/test/internal/regular/empty_tag.go b/test/internal/regular/empty_tag.go index 5119960..65d6440 100644 --- a/test/internal/regular/empty_tag.go +++ b/test/internal/regular/empty_tag.go @@ -4,7 +4,10 @@ //go:generate gtag -types Empty,User,UserName -tags bson,json . package regular -import "reflect" +import ( + "reflect" + "strings" +) var ( valueOfEmpty = Empty{} @@ -16,7 +19,15 @@ type EmptyTags struct { } // Tags return specified tags of Empty -func (Empty) Tags(tag string) EmptyTags { +func (Empty) Tags(tag string, convert ...func(string) string) EmptyTags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 { + conv = convert[0] + } + if conv == nil { + conv = func(in string) string { return in } + } + _ = conv return EmptyTags{} } diff --git a/test/internal/regular/empty_tag_test.go b/test/internal/regular/empty_tag_test.go index a3aad28..44c51e4 100644 --- a/test/internal/regular/empty_tag_test.go +++ b/test/internal/regular/empty_tag_test.go @@ -2,12 +2,14 @@ package regular import ( "reflect" + "strings" "testing" ) func TestEmpty_Tags(t *testing.T) { type args struct { - tag string + tag string + convert []func(string) string } tests := []struct { name string @@ -21,11 +23,27 @@ func TestEmpty_Tags(t *testing.T) { }, want: EmptyTags{}, }, + { + name: "convert ToUpper", + args: args{ + tag: "json", + convert: []func(string) string{strings.ToUpper}, + }, + want: EmptyTags{}, + }, + { + name: "convert nil", + args: args{ + tag: "json", + convert: []func(string) string{nil}, + }, + want: EmptyTags{}, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { em := Empty{} - if got := em.Tags(tt.args.tag); !reflect.DeepEqual(got, tt.want) { + if got := em.Tags(tt.args.tag, tt.args.convert...); !reflect.DeepEqual(got, tt.want) { t.Errorf("Tags() = %v, want %v", got, tt.want) } }) diff --git a/test/internal/regular/user.go b/test/internal/regular/user.go index 3af0409..34c1956 100644 --- a/test/internal/regular/user.go +++ b/test/internal/regular/user.go @@ -2,7 +2,7 @@ package regular type User struct { Id int `json:"id"` - Name UserName `json:"name"` + Name UserName `json:"name,omitempty"` Email string `json:"email"` age int } diff --git a/test/internal/regular/user_tag.go b/test/internal/regular/user_tag.go index 5ee78ce..a0d6953 100644 --- a/test/internal/regular/user_tag.go +++ b/test/internal/regular/user_tag.go @@ -4,7 +4,10 @@ //go:generate gtag -types Empty,User,UserName -tags bson,json . package regular -import "reflect" +import ( + "reflect" + "strings" +) var ( valueOfUser = User{} @@ -29,19 +32,27 @@ var ( // UserTags indicate tags of type User type UserTags struct { - Id string - Name string - Email string - age string + Id string // `json:"id"` + Name string // `json:"name,omitempty"` + Email string // `json:"email"` + age string // } // Tags return specified tags of User -func (User) Tags(tag string) UserTags { +func (User) Tags(tag string, convert ...func(string) string) UserTags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 { + conv = convert[0] + } + if conv == nil { + conv = func(in string) string { return in } + } + _ = conv return UserTags{ - Id: tagOfUserId.Get(tag), - Name: tagOfUserName.Get(tag), - Email: tagOfUserEmail.Get(tag), - age: tagOfUserage.Get(tag), + Id: conv(tagOfUserId.Get(tag)), + Name: conv(tagOfUserName.Get(tag)), + Email: conv(tagOfUserEmail.Get(tag)), + age: conv(tagOfUserage.Get(tag)), } } @@ -70,15 +81,23 @@ var ( // UserNameTags indicate tags of type UserName type UserNameTags struct { - First string - Last string + First string // `json:"first"` + Last string // `json:"last"` } // Tags return specified tags of UserName -func (UserName) Tags(tag string) UserNameTags { +func (UserName) Tags(tag string, convert ...func(string) string) UserNameTags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 { + conv = convert[0] + } + if conv == nil { + conv = func(in string) string { return in } + } + _ = conv return UserNameTags{ - First: tagOfUserNameFirst.Get(tag), - Last: tagOfUserNameLast.Get(tag), + First: conv(tagOfUserNameFirst.Get(tag)), + Last: conv(tagOfUserNameLast.Get(tag)), } } diff --git a/test/internal/regular/user_tag_test.go b/test/internal/regular/user_tag_test.go index 425d69f..efe2ef7 100644 --- a/test/internal/regular/user_tag_test.go +++ b/test/internal/regular/user_tag_test.go @@ -2,6 +2,7 @@ package regular import ( "reflect" + "strings" "testing" ) @@ -13,7 +14,8 @@ func TestUser_Tags(t *testing.T) { age int } type args struct { - tag string + tag string + convert []func(string) string } tests := []struct { name string @@ -42,6 +44,20 @@ func TestUser_Tags(t *testing.T) { age: "", }, }, + { + name: "convert nil", + fields: fields{}, + args: args{ + tag: "json", + convert: []func(string) string{nil}, + }, + want: UserTags{ + Id: "id", + Name: "name,omitempty", + Email: "email", + age: "", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -51,7 +67,7 @@ func TestUser_Tags(t *testing.T) { Email: tt.fields.Email, age: tt.fields.age, } - if got := us.Tags(tt.args.tag); !reflect.DeepEqual(got, tt.want) { + if got := us.Tags(tt.args.tag, tt.args.convert...); !reflect.DeepEqual(got, tt.want) { t.Errorf("Tags() = %v, want %v", got, tt.want) } }) @@ -64,7 +80,8 @@ func TestUserName_Tags(t *testing.T) { Last string } type args struct { - tag string + tag string + convert []func(string) string } tests := []struct { name string @@ -86,6 +103,36 @@ func TestUserName_Tags(t *testing.T) { Last: "last", }, }, + { + name: "convert ToUpper", + fields: fields{ + First: "", + Last: "", + }, + args: args{ + tag: "json", + convert: []func(string) string{strings.ToUpper}, + }, + want: UserNameTags{ + First: "FIRST", + Last: "LAST", + }, + }, + { + name: "convert nil", + fields: fields{ + First: "", + Last: "", + }, + args: args{ + tag: "json", + convert: []func(string) string{nil}, + }, + want: UserNameTags{ + First: "first", + Last: "last", + }, + }, } for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { @@ -93,7 +140,7 @@ func TestUserName_Tags(t *testing.T) { First: tt.fields.First, Last: tt.fields.Last, } - if got := us.Tags(tt.args.tag); !reflect.DeepEqual(got, tt.want) { + if got := us.Tags(tt.args.tag, tt.args.convert...); !reflect.DeepEqual(got, tt.want) { t.Errorf("Tags() = %v, want %v", got, tt.want) } }) diff --git a/test/internal/tutorial/user_tag.go b/test/internal/tutorial/user_tag.go index 1603879..cbd8035 100644 --- a/test/internal/tutorial/user_tag.go +++ b/test/internal/tutorial/user_tag.go @@ -4,7 +4,10 @@ //go:generate gtag -types User -tags bson . package tutorial -import "reflect" +import ( + "reflect" + "strings" +) var ( valueOfUser = User{} @@ -23,20 +26,28 @@ var ( tagOfUserEmail = fieldOfUserEmail.Tag ) +// UserTags indicate tags of type User type UserTags struct { - Id string - Name string - Email string + Id string // `bson:"_id"` + Name string // `bson:"name"` + Email string // `bson:"email"` } -func (User) Tags(tag string) UserTags { +// Tags return specified tags of User +func (User) Tags(tag string, convert ...func(string) string) UserTags { + conv := func(in string) string { return strings.TrimSpace(strings.Split(in, ",")[0]) } + if len(convert) > 0 && convert[0] != nil { + conv = convert[0] + } + _ = conv return UserTags{ - Id: tagOfUserId.Get(tag), - Name: tagOfUserName.Get(tag), - Email: tagOfUserEmail.Get(tag), + Id: conv(tagOfUserId.Get(tag)), + Name: conv(tagOfUserName.Get(tag)), + Email: conv(tagOfUserEmail.Get(tag)), } } +// TagsBson is alias of Tags("bson") func (v User) TagsBson() UserTags { return v.Tags("bson") }