Skip to content

Commit e81b720

Browse files
Add --template flag to provide filenames of additional templates (#53)
* Add --template flag to provide filenames of additional templates * Update readme * Add globbing support to templates * Share globbing code between --file and --template
1 parent f5cbb58 commit e81b720

File tree

9 files changed

+199
-57
lines changed

9 files changed

+199
-57
lines changed

README.md

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -26,20 +26,21 @@ USAGE:
2626
go-enum [global options] [arguments...]
2727

2828
GLOBAL OPTIONS:
29-
--file value, -f value The file(s) to generate enums. Use more than one flag for more files.
30-
--noprefix Prevents the constants generated from having the Enum as a prefix. (default: false)
31-
--lower Adds lowercase variants of the enum strings for lookup. (default: false)
32-
--nocase Adds case insensitive parsing to the enumeration (forces lower flag). (default: false)
33-
--marshal Adds text (and inherently json) marshalling functions. (default: false)
34-
--sql Adds SQL database scan and value functions. (default: false)
35-
--flag Adds golang flag functions. (default: false)
36-
--prefix value Replaces the prefix with a user one.
37-
--names Generates a 'Names() []string' function, and adds the possible enum values in the error response during parsing (default: false)
38-
--nocamel Removes the snake_case to CamelCase name changing (default: false)
39-
--ptr Adds a pointer method to get a pointer from const values (default: false)
40-
--sqlnullint Adds a Null{{ENUM}} type for marshalling a nullable int value to sql (default: false)
41-
--sqlnullstr Adds a Null{{ENUM}} type for marshalling a nullable string value to sql. If sqlnullint is specified too, it will be Null{{ENUM}}Str (default: false)
42-
--help, -h show help (default: false)
29+
--file value, -f value The file(s) to generate enums. Use more than one flag for more files.
30+
--noprefix Prevents the constants generated from having the Enum as a prefix. (default: false)
31+
--lower Adds lowercase variants of the enum strings for lookup. (default: false)
32+
--nocase Adds case insensitive parsing to the enumeration (forces lower flag). (default: false)
33+
--marshal Adds text (and inherently json) marshalling functions. (default: false)
34+
--sql Adds SQL database scan and value functions. (default: false)
35+
--flag Adds golang flag functions. (default: false)
36+
--prefix value Replaces the prefix with a user one.
37+
--names Generates a 'Names() []string' function, and adds the possible enum values in the error response during parsing (default: false)
38+
--nocamel Removes the snake_case to CamelCase name changing (default: false)
39+
--ptr Adds a pointer method to get a pointer from const values (default: false)
40+
--sqlnullint Adds a Null{{ENUM}} type for marshalling a nullable int value to sql (default: false)
41+
--sqlnullstr Adds a Null{{ENUM}} type for marshalling a nullable string value to sql. If sqlnullint is specified too, it will be Null{{ENUM}}Str (default: false)
42+
--template value, -t value Additional template file(s) to generate enums. Use more than one flag for more files. Templates will be executed in alphabetical order.
43+
--help, -h show help (default: false)
4344
```
4445
4546
### Syntax

example/user_globbed.tmpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func Parse{{.enum.Name}}GlobbedExample() bool {
2+
return true
3+
}

example/user_globbed2.tmpl

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
func Parse{{.enum.Name}}GlobbedExample2() bool {
2+
return true
3+
}

example/user_template.go

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
//go:generate ../bin/go-enum -f=$GOFILE -t user_template.tmpl -t *user_glob*.tmpl
2+
3+
package example
4+
5+
// OceanColor is an enumeration of ocean colors that are allowed.
6+
/*
7+
ENUM(
8+
Cerulean
9+
Blue
10+
Green
11+
)
12+
*/
13+
type OceanColor int

example/user_template.tmpl

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
// Additional template
2+
func Parse{{.enum.Name}}Example() bool {
3+
return true
4+
}

example/user_template_enum.go

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

example/user_template_test.go

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package example
2+
3+
import (
4+
"testing"
5+
6+
"github.com/stretchr/testify/assert"
7+
)
8+
9+
func TestUserTemplateColor(t *testing.T) {
10+
assert.Equal(t, OceanColor(0), OceanColorCerulean)
11+
assert.Equal(t, true, ParseOceanColorExample())
12+
assert.Equal(t, true, ParseOceanColorGlobbedExample())
13+
assert.Equal(t, true, ParseOceanColorGlobbedExample2())
14+
}

generator/generator.go

Lines changed: 40 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -28,21 +28,22 @@ const (
2828

2929
// Generator is responsible for generating validation files for the given in a go source file.
3030
type Generator struct {
31-
t *template.Template
32-
knownTemplates map[string]*template.Template
33-
fileSet *token.FileSet
34-
noPrefix bool
35-
lowercaseLookup bool
36-
caseInsensitive bool
37-
marshal bool
38-
sql bool
39-
flag bool
40-
names bool
41-
leaveSnakeCase bool
42-
prefix string
43-
sqlNullInt bool
44-
sqlNullStr bool
45-
ptr bool
31+
t *template.Template
32+
knownTemplates map[string]*template.Template
33+
userTemplateNames []string
34+
fileSet *token.FileSet
35+
noPrefix bool
36+
lowercaseLookup bool
37+
caseInsensitive bool
38+
marshal bool
39+
sql bool
40+
flag bool
41+
names bool
42+
leaveSnakeCase bool
43+
prefix string
44+
sqlNullInt bool
45+
sqlNullStr bool
46+
ptr bool
4647
}
4748

4849
// Enum holds data for a discovered enum in the parsed source
@@ -66,10 +67,11 @@ type EnumValue struct {
6667
// templates loaded.
6768
func NewGenerator() *Generator {
6869
g := &Generator{
69-
knownTemplates: make(map[string]*template.Template),
70-
t: template.New("generator"),
71-
fileSet: token.NewFileSet(),
72-
noPrefix: false,
70+
knownTemplates: make(map[string]*template.Template),
71+
userTemplateNames: make([]string, 0),
72+
t: template.New("generator"),
73+
fileSet: token.NewFileSet(),
74+
noPrefix: false,
7375
}
7476

7577
funcs := sprig.TxtFuncMap()
@@ -163,6 +165,18 @@ func (g *Generator) WithSQLNullStr() *Generator {
163165
return g
164166
}
165167

168+
// WithTemplates is used to provide the filenames of additional templates.
169+
func (g *Generator) WithTemplates(filenames ...string) *Generator {
170+
for _, ut := range template.Must(g.t.ParseFiles(filenames...)).Templates() {
171+
if _, ok := g.knownTemplates[ut.Name()]; !ok {
172+
g.userTemplateNames = append(g.userTemplateNames, ut.Name())
173+
}
174+
}
175+
g.updateTemplates()
176+
sort.Strings(g.userTemplateNames)
177+
return g
178+
}
179+
166180
// GenerateFromFile is responsible for orchestrating the Code generation. It results in a byte array
167181
// that can be written to any file desired. It has already had goimports run on the code before being returned.
168182
func (g *Generator) GenerateFromFile(inputFile string) ([]byte, error) {
@@ -223,6 +237,13 @@ func (g *Generator) Generate(f *ast.File) ([]byte, error) {
223237
if err != nil {
224238
return vBuff.Bytes(), errors.WithMessage(err, fmt.Sprintf("Failed writing enum data for enum: %q", name))
225239
}
240+
241+
for _, userTemplateName := range g.userTemplateNames {
242+
err = g.t.ExecuteTemplate(vBuff, userTemplateName, data)
243+
if err != nil {
244+
return vBuff.Bytes(), errors.WithMessage(err, fmt.Sprintf("Failed writing enum data for enum: %q, template: %v", name, userTemplateName))
245+
}
246+
}
226247
}
227248

228249
formatted, err := imports.Process(pkg, vBuff.Bytes(), nil)

main.go

Lines changed: 48 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -14,19 +14,20 @@ import (
1414
)
1515

1616
type rootT struct {
17-
FileNames cli.StringSlice
18-
NoPrefix bool
19-
Lowercase bool
20-
NoCase bool
21-
Marshal bool
22-
SQL bool
23-
Flag bool
24-
Prefix string
25-
Names bool
26-
LeaveSnakeCase bool
27-
SQLNullStr bool
28-
SQLNullInt bool
29-
Ptr bool
17+
FileNames cli.StringSlice
18+
NoPrefix bool
19+
Lowercase bool
20+
NoCase bool
21+
Marshal bool
22+
SQL bool
23+
Flag bool
24+
Prefix string
25+
Names bool
26+
LeaveSnakeCase bool
27+
SQLNullStr bool
28+
SQLNullInt bool
29+
Ptr bool
30+
TemplateFileNames cli.StringSlice
3031
}
3132

3233
func main() {
@@ -109,6 +110,12 @@ func main() {
109110
Usage: "Adds a Null{{ENUM}} type for marshalling a nullable string value to sql. If sqlnullint is specified too, it will be Null{{ENUM}}Str",
110111
Destination: &argv.SQLNullStr,
111112
},
113+
&cli.StringSliceFlag{
114+
Name: "template",
115+
Aliases: []string{"t"},
116+
Usage: "Additional template file(s) to generate enums. Use more than one flag for more files. Templates will be executed in alphabetical order.",
117+
Destination: &argv.TemplateFileNames,
118+
},
112119
},
113120
Action: func(ctx *cli.Context) error {
114121
for _, fileOption := range argv.FileNames.Value() {
@@ -151,20 +158,21 @@ func main() {
151158
if argv.SQLNullStr {
152159
g.WithSQLNullStr()
153160
}
161+
if templates := []string(argv.TemplateFileNames.Value()); len(templates) > 0 {
162+
for _, t := range templates {
163+
if fn, err := globFilenames(t); err != nil {
164+
return err
165+
} else {
166+
g.WithTemplates(fn...)
167+
}
168+
}
169+
}
154170

155171
var filenames []string
156-
157-
// In order to maintain existing capabilities, only glob when a * is in the path.
158-
// Leave execution on par with old method in case there are bad patterns in use that somehow
159-
// work without the Glob method.
160-
if strings.Contains(fileOption, "*") {
161-
matches, err := filepath.Glob(fileOption)
162-
if err != nil {
163-
return fmt.Errorf("failed parsing glob filepath\nInputFile=%s\nError=%s", color.Cyan(fileOption), color.RedBg(err))
164-
}
165-
filenames = append(filenames, matches...)
172+
if fn, err := globFilenames(fileOption); err != nil {
173+
return err
166174
} else {
167-
filenames = append(filenames, fileOption)
175+
filenames = fn
168176
}
169177

170178
for _, fileName := range filenames {
@@ -203,3 +211,19 @@ func main() {
203211
log.Fatal(err)
204212
}
205213
}
214+
215+
// globFilenames gets a list of filenames matching the provided filename.
216+
// In order to maintain existing capabilities, only glob when a * is in the path.
217+
// Leave execution on par with old method in case there are bad patterns in use that somehow
218+
// work without the Glob method.
219+
func globFilenames(filename string) ([]string, error) {
220+
if strings.Contains(filename, "*") {
221+
matches, err := filepath.Glob(filename)
222+
if err != nil {
223+
return []string{}, fmt.Errorf("failed parsing glob filepath\nInputFile=%s\nError=%s", color.Cyan(filename), color.RedBg(err))
224+
}
225+
return matches, nil
226+
} else {
227+
return []string{filename}, nil
228+
}
229+
}

0 commit comments

Comments
 (0)