Skip to content

Commit e799214

Browse files
authored
Merge pull request #32 from phelmkamp/cleanup
Cleanup
2 parents cd46cae + 563c362 commit e799214

File tree

5 files changed

+74
-69
lines changed

5 files changed

+74
-69
lines changed

README.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,12 +9,12 @@ Go metaprogramming using struct tags + generate
99

1010
1. Define struct tags
1111

12-
Format is `meta:"[directive1][;directive2]"`. For example:
12+
Format is `meta:"directive[,option][;directive2]"`. For example:
1313
```go
1414
type Foo struct {
1515
name, Desc string `meta:"getter"`
1616
size int `meta:"ptr;getter;setter"`
17-
labels []string `meta:"setter;getter;filter"`
17+
labels []string `meta:"setter;getter;mapper,int"`
1818
}
1919
```
2020

@@ -56,7 +56,7 @@ Generates a method that returns a copy of the slice, omitting elements that are
5656
Method name is `Filter`, followed by the name of the field unless `omitfield` is specified.
5757
Uses value receiver by default.
5858

59-
`map:$Type` (slice only)
59+
`mapper,$type` (slice only)
6060

6161
Generates a method that returns the result of mapping all elements to the specified type using the given function.
6262
Method name is of the form `MapFieldTo$Type`, or just `MapTo$Type` if `omitfield` is specified.

directive/directive.go

Lines changed: 66 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,60 @@ const (
1515
optReflect = "reflect"
1616
)
1717

18-
// Target represents the target of the directive
18+
var (
19+
runFuncs = map[string]runFunc{
20+
"ptr": ptr,
21+
"getter": getter,
22+
"setter": setter,
23+
"filter": filter,
24+
"mapper": mapper,
25+
"sort": sort,
26+
"stringer": stringer,
27+
"new": runNew,
28+
"equal": equal,
29+
}
30+
)
31+
32+
// Target represents the target of the directive.
1933
type Target struct {
2034
MetaFile *meta.File
2135
RcvName, RcvType string
2236
FldNames []string
2337
FldType string
2438
}
2539

26-
// Ptr converts the receiver to a pointer for all subsequent directives
27-
func Ptr(tgt *Target) {
40+
type runFunc func(*Target, []string)
41+
42+
// RunAll runs all of the given directives.
43+
func RunAll(ds []string, tgt *Target) {
44+
for i := range ds {
45+
Run(ds[i], tgt)
46+
}
47+
}
48+
49+
// Run runs the given directive.
50+
func Run(d string, tgt *Target) {
51+
opts := strings.Split(d, ",")
52+
d = opts[0]
53+
opts = opts[1:]
54+
55+
run, ok := runFuncs[d]
56+
if !ok {
57+
log.Printf("Unknown directive: %s\n", d)
58+
return
59+
}
60+
61+
run(tgt, opts)
62+
}
63+
64+
// ptr converts the receiver to a pointer for all subsequent directives.
65+
func ptr(tgt *Target, opts []string) {
2866
tgt.RcvType = "*" + tgt.RcvType
2967
log.Printf("Using pointer receiver: %s\n", tgt.RcvType)
3068
}
3169

32-
// Getter generates a getter method for each name of the given field
33-
func Getter(tgt *Target) {
70+
// getter generates a getter method for each name of the given field.
71+
func getter(tgt *Target, opts []string) {
3472
for _, fldNm := range tgt.FldNames {
3573
method := upperFirst(fldNm)
3674
if method == fldNm {
@@ -50,8 +88,8 @@ func Getter(tgt *Target) {
5088
}
5189
}
5290

53-
// Setter generates a setter method for each name of the given field
54-
func Setter(tgt *Target) {
91+
// setter generates a setter method for each name of the given field.
92+
func setter(tgt *Target, opts []string) {
5593
elemType := strings.TrimPrefix(tgt.FldType, "[]")
5694

5795
arg := argName(tgt.RcvName, elemType)
@@ -78,8 +116,8 @@ func Setter(tgt *Target) {
78116
}
79117
}
80118

81-
// Filter generates a filter method for each name of the given field
82-
func Filter(tgt *Target, opts []string) {
119+
// filter generates a filter method for each name of the given field.
120+
func filter(tgt *Target, opts []string) {
83121
elemType := strings.TrimPrefix(tgt.FldType, "[]")
84122

85123
var isOmitField bool
@@ -112,15 +150,23 @@ func Filter(tgt *Target, opts []string) {
112150
}
113151
}
114152

115-
// Map generates a mapper method for each name of the given field
116-
func Map(tgt *Target, result string, opts []string) {
117-
elemType := strings.TrimPrefix(tgt.FldType, "[]")
153+
// mapper generates a mapper method for each name of the given field.
154+
func mapper(tgt *Target, opts []string) {
155+
if len(opts) < 1 {
156+
log.Print("skipping 'mapper' - must specify target type as first option\n")
157+
return
158+
}
159+
160+
result := opts[0]
161+
opts = opts[1:]
118162

119163
sel := result
120164
if resSubs := strings.SplitN(result, ".", 2); len(resSubs) > 1 {
121165
sel = resSubs[1]
122166
}
123167

168+
elemType := strings.TrimPrefix(tgt.FldType, "[]")
169+
124170
var isOmitField bool
125171
for i := range opts {
126172
if opts[i] == optOmitField {
@@ -130,11 +176,6 @@ func Map(tgt *Target, result string, opts []string) {
130176
}
131177

132178
for _, fldNm := range tgt.FldNames {
133-
if elemType == tgt.FldType {
134-
log.Printf("'map' not valid for field %s.%s - must be a slice\n", tgt.RcvName, fldNm)
135-
continue
136-
}
137-
138179
var fldPart string
139180
if !isOmitField {
140181
fldPart = upperFirst(fldNm)
@@ -155,8 +196,8 @@ func Map(tgt *Target, result string, opts []string) {
155196
}
156197
}
157198

158-
// Sort generates sort methods for the first name of the given field
159-
func Sort(tgt *Target, opts []string) {
199+
// sort generates sort methods for the first name of the given field.
200+
func sort(tgt *Target, opts []string) {
160201
log.Print("Adding import: \"sort\"\n")
161202
tgt.MetaFile.Imports["sort"] = struct{}{}
162203

@@ -192,8 +233,8 @@ func Sort(tgt *Target, opts []string) {
192233
}
193234
}
194235

195-
// Stringer adds each name of the given field to the String() implementation
196-
func Stringer(tgt *Target) {
236+
// stringer adds each name of the given field to the String() implementation.
237+
func stringer(tgt *Target, opts []string) {
197238
log.Print("Adding import: \"fmt\"\n")
198239
tgt.MetaFile.Imports["fmt"] = struct{}{}
199240

@@ -227,8 +268,8 @@ func Stringer(tgt *Target) {
227268
}
228269
}
229270

230-
// New adds each name of the given field to the New() implementation
231-
func New(tgt *Target) {
271+
// runNew adds each name of the given field to the New() implementation.
272+
func runNew(tgt *Target, opts []string) {
232273
method := "New" + upperFirst(tgt.RcvType)
233274
for _, fldNm := range tgt.FldNames {
234275
log.Printf("Adding to method: %s\n", method)
@@ -256,8 +297,8 @@ func New(tgt *Target) {
256297
}
257298
}
258299

259-
// Equal adds each name of the given field to the Equal() implementation
260-
func Equal(tgt *Target, opts []string) {
300+
// equal adds each name of the given field to the Equal() implementation.
301+
func equal(tgt *Target, opts []string) {
261302
for _, fldNm := range tgt.FldNames {
262303
log.Print("Adding to method: Equal\n")
263304
found := tgt.MetaFile.FilterMethods(

internal/testdata/foobar/foo.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,14 +10,14 @@ type Foo struct {
1010
NoMetaJSON string `json:"omitempty"`
1111
name, Desc string `meta:"new;getter;stringer"`
1212
size int `meta:"stringer;ptr;getter;setter"`
13-
labels []string `meta:"new;setter;getter;filter;map:time.Time"`
13+
labels []string `meta:"new;setter;getter;filter;mapper,time.Time"`
1414
stringer fmt.Stringer `meta:"setter"`
1515
}
1616

1717
type Bar struct {
1818
name string `meta:"stringer;equal"`
19-
foos []Foo `meta:"getter;setter;map:string"`
19+
foos []Foo `meta:"getter;setter;mapper,string"`
2020
pairs map[string]float64 `meta:"getter;setter"`
21-
times []time.Time `meta:"getter;setter;filter;map:int64;equal,reflect"`
21+
times []time.Time `meta:"getter;setter;filter;mapper,int64;equal,reflect"`
2222
baz bool `meta:"setter"`
2323
}

internal/testdata/person/person.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,5 +8,5 @@ type Person struct {
88
}
99

1010
type Persons struct {
11-
Ps []Person `meta:"filter,omitfield;map:int,omitfield;sort,stringer"`
11+
Ps []Person `meta:"filter,omitfield;mapper,int,omitfield;sort,stringer"`
1212
}

main.go

Lines changed: 1 addition & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -149,43 +149,7 @@ func main() {
149149
fldTgt.FldNames[i] = f.Names[i].Name
150150
}
151151

152-
directives := strings.Split(metaTag, ";")
153-
for _, d := range directives {
154-
dSubs := strings.SplitN(d, ":", 2)
155-
if len(dSubs) < 1 {
156-
continue
157-
}
158-
159-
opts := strings.Split(dSubs[len(dSubs)-1], ",")
160-
dSubs[len(dSubs)-1] = opts[0]
161-
opts = opts[1:]
162-
163-
switch dSubs[0] {
164-
case "ptr":
165-
directive.Ptr(&fldTgt)
166-
case "getter":
167-
directive.Getter(&fldTgt)
168-
case "setter":
169-
directive.Setter(&fldTgt)
170-
case "filter":
171-
directive.Filter(&fldTgt, opts)
172-
case "map":
173-
if len(dSubs) < 2 {
174-
continue
175-
}
176-
directive.Map(&fldTgt, dSubs[1], opts)
177-
case "sort":
178-
directive.Sort(&fldTgt, opts)
179-
case "stringer":
180-
directive.Stringer(&fldTgt)
181-
case "new":
182-
directive.New(&fldTgt)
183-
case "equal":
184-
directive.Equal(&fldTgt, opts)
185-
default:
186-
log.Printf("Unknown directive: %s\n", d)
187-
}
188-
}
152+
directive.RunAll(strings.Split(metaTag, ";"), &fldTgt)
189153

190154
if fldPkg != "" {
191155
var importPath string

0 commit comments

Comments
 (0)