少し探した感じでは見つけられなかったので,GolangでEnumコードを生成するコードジェネレーターを自分で書いた時の記録になります.
何を作ったか
---
複数種の(単純な)Enumを大量生成するにあたって必要な情報が書かれたjsonファイルを入力とし,goのEnumコードを出力生成するコードジェネレーターを作成しました.
入力(jsonファイル```enums.json```)
```json
[
{
"type": "CITY",
"package": "types",
"data": [
{
"id": "TYO",
"name": "Tokyo"
},
{
"id": "NYC",
"name": "New York"
},
{
"id": "LDN",
"name": "London"
}
]
},
{
"type": "COUNTRY",
"package": "enums",
"data": [
{
"id": "JPN",
"name": "Japan"
},
{
"id": "US",
"name": "United States"
},
{
"id": "UK",
"name": "United Kingdom"
}
]
}
]
生成されたEnum(types/city.go
)
// Code generated by go generate; DO NOT EDIT.
package types
type CITY int
const (
TYO CITY = iota
NYC CITY = iota
LDN CITY = iota
)
func (e CITY) String() string {
switch e {
case TYO:
return "Tokyo"
case NYC:
return "New York"
case LDN:
return "London"
default:
return "Unknown CITY"
}
}
生成されたEnum(enums/country.go
)
// Code generated by go generate; DO NOT EDIT.
package enums
type COUNTRY int
const (
JPN COUNTRY = iota
US COUNTRY = iota
UK COUNTRY = iota
)
func (e COUNTRY) String() string {
switch e {
case JPN:
return "Japan"
case US:
return "United States"
case UK:
return "United Kingdom"
default:
return "Unknown COUNTRY"
}
}
TL;DR
package main
//go:generate go run main.go
import (
_ "embed"
"encoding/json"
"fmt"
"os"
"strings"
"text/template"
)
const (
ENUM_FILE_NAME = "enum.json"
)
type Enum struct {
Id string `json:"id"`
Name string `json:"name"`
}
type Enums struct {
Type string `json:"type"`
Package string `json:"package"`
Data []Enum `json:"data"`
}
func main() {
var enums []Enums
enumBytes, _ := os.ReadFile(ENUM_FILE_NAME)
if err := json.Unmarshal(enumBytes, &enums); err != nil {
panic(err)
}
fmt.Println(enums)
for _, e := range enums {
os.Mkdir(e.Package, 0755)
f, err := os.Create("./" + e.Package + "/" + strings.ToLower(e.Type) + ".go")
if err != nil {
panic(err)
}
defer f.Close()
err = enumTemplate.Execute(f, e)
if err != nil {
panic(err)
}
}
}
var enumTemplate = template.Must(template.New("").Parse(`// Code generated by go generate; DO NOT EDIT.
package
type int
const (
= iota
)
func (e ) String() string {
switch e {
case :
return
default:
return "Unknown "
}
}
`))
使い方
$ go generate
[{CITY types [{TYO Tokyo} {NYC New York} {LDN London}]} {COUNTRY enums [{JPN Japan} {US United States} {UK United Kingdom}]}]
実行後,それぞれのpackage配下にファイルが生成されます.
個人的なハマりポイントとしては,テンプレートにおいて 内では
を呼び出すとエラーになるので,一回 `````` で変数置換する必要があるという点でした.
なお,Go 1.16 から採用されたgo:embed
ディレクティブを使うと,1バイナリになったコードジェネレーターが作れるので,実行時にjsonファイルがなくてもコード生成できるようになります.
まとめ
今回のこの単純な具体例を通して,text/template
でコード自動生成へ興味を持っていただけたなら幸いです.
また,間違いがありましたら指摘くださると助かります.
利用したコードは下記に格納してあります https://github.com/tk42/go-enum-gen