#+startup: overview
#+title: gogen
* gogen
golang generate tool collection and merge.
| command | source | description |
|----------+------------+--------------------------------------------------------------------|
| stringer | [[https://pkg.go.dev/golang.org/x/tools/cmd/stringer][stringer]] | generate fmt.Stringer interface for const integer. |
| import | | import const type and value from another package. |
| option | [[https://github.com/timestee/optiongen][optiongen]] | generate generate go Struct option for test, mock or more flexible |
| imake | [[https://github.com/vburenin/ifacemaker][ifacemaker]] | generate interface from go struct define. mock stub supported |
** stringer
#+begin_src text
Usage:
gogen stringer [flags] -t T [directory | files ]
Flags:
-h, --help help for stringer
--linecomment use line comment text as printed text when present
-o, --output string output file name; default srcdir/<type>_string.go
--tags strings comma-separated list of build tags to apply
-p, --trimprefix prefix trim the prefix from the generated constant names
-t, --type strings list of type names; must be set
#+end_src
sample source code
[[./samples/testdata/test.go][samples/testdata/test.go]]
#+begin_src go
// TestType test type comment 1
// second line comment
type TestType int // comment 2
const (
// T1 comment 11
T1 TestType = iota // line suffix comment 1
// T2 comment 22
T2
T3 // T3 line suffix comment 1
)
#+end_src
generete:
[[./samples/testdata/testtype_string.go][samples/testdata/testtype_string.go]]
#+begin_src go
// Code generated by "gogen stringer"; DO NOT EDIT.
// Exec: "gogen stringer -t TestType"
// Version: 0.0.1
package testdata
import "strconv"
func _() {
// An "invalid array index" compiler error signifies that the constant values have changed.
// Re-run the stringer command to generate them again.
var x [1]struct{}
_ = x[T1-0]
_ = x[T2-1]
_ = x[T3-2]
}
const _TestType_name = "T1T2T3"
var _TestType_index = [...]uint8{0, 2, 4, 6}
func (i TestType) String() string {
if i < 0 || i >= TestType(len(_TestType_index)-1) {
return "TestType(" + strconv.FormatInt(int64(i), 10) + ")"
}
return _TestType_name[_TestType_index[i]:_TestType_index[i+1]]
}
#+end_src
** import
#+begin_src text
Usage:
gogen import [flag] -t T [flags]
Flags:
-f, --func strings list of functions names
-h, --help help for import
--new import type new functions
-o, --output string output file name; default <package>_import.go
--tags strings comma-separated list of build tags to apply
--to string which package be imported, extract the package from this folder (default ".")
-p, --trimprefix prefix trim the prefix from the generated constant names
-t, --type strings list of type names; must be set
-v, --value strings list of value names
--version version for import
#+end_src
sample source code
[[./samples/testdata/test.go][samples/testdata/test.go]]
#+begin_src go
// TestType test type comment 1
// second line comment
type TestType int // comment 2
const (
// T1 comment 11
T1 TestType = iota // line suffix comment 1
// T2 comment 22
T2
T3 // T3 line suffix comment 1
)
#+end_src
generate code
[[./samples/gen_td.go][samples/gen_td.go]]
#+begin_src go
// Code generated by "gogen import"; DO NOT EDIT.
// Exec: "gogen import ./testdata -t TestType"
// Version: 0.0.1
package main
import testdata "github.com/aggronmagi/gogen/testdata"
// TestType test type comment 1
// second line comment
type TestType = testdata.TestType // comment 2
const (
// T1 comment 11
T1 = testdata.T1 // line suffix comment 1
// T2 comment 22
T2 = testdata.T2
T3 = testdata.T3 // T3 line suffix comment 1
)
#+end_src
** option
#+begin_src text
Usage:
gogen option [flags]
Flags:
-e, --all-export Export all field option settings. If set to false, lowercase fields will not be exported. (default true)
-a, --gen-slice-append decide whether generate append method for slice option.
-h, --help help for option
-n, --options-name string generate options name,default collection from function name.
-f, --with-option-name Decide whether the name of the generated setting function has an option name, which is used to have multiple options for repetitio
#+end_src
sample source code
#+begin_src go
// Google Public DNS provides two distinct DoH APIs at these endpoints
// Using the GET method can reduce latency, as it is cached more effectively.
// RFC 8484 GET requests must have a ?dns= query parameter with a Base64Url encoded DNS message. The GET method is the only method supported for the JSON API.
//go:generate gogen option
func ConfigOptionDeclareWithDefault() interface{} {
return map[string]interface{}{
// test comment 1
// test comment 2
"TestNil": nil, // test comment 3
"TestBool": false, // test comment 4
// 这里是函数注释1
// 这里是函数注释2
"TestInt": 32, // default 32
"TestInt64": int64(32), // int64 line
"TestSliceInt": []int{1, 2, 3}, // slice int
"TestSliceInt64": []int64{1, 2, 3}, // slice int64 line
"TestSliceString": []string{"test1", "test2"}, // slice string
"TestSliceBool": []bool{false, true}, // slice bool line comment
"TestSliceIntNil": []int(nil), // TestSliceIntNil line comment
"TestSliceByte": []byte(nil), // TestSliceByte line comment
// SliceInt Doc
"TestSliceIntEmpty": []int{}, // Slice int line comment
"TestMapIntInt": map[int]int{1: 1, 2: 2, 3: 3}, // TestMapIntInt line comment
"TestMapIntString": map[int]string{1: "test"}, // TestMapIntString line comment
"TestMapStringInt": map[string]int{"test": 1}, // TestMapStringInt line comment
// MapStringString Doc
"TestMapStringString": map[string]string{"test": "test"}, // MapStringString Line Comment
"TestString": "Meow",
// Food Doc
"Food": (*string)(nil), // Food Line Comment
// Walk Doc
"Walk": func() {
log.Println("Walking")
}, // Walk Line Comment
// TestNilFunc
"TestNilFunc": (func())(nil), // 中文1
// TestReserved1_
"TestReserved1_": []byte(nil), // 在调优或者运行阶段,我们可能需要动态查看连接池中的一些指标,
// 来判断设置的值是否合理,或者检测连接池是否有异常情况出现
"TestReserved2Inner": 1, // TestReserved2Inner after
}
}
#+end_src
generate code
[[./samples/gen_configoptions.go][samples/gen_configoptions.go]]
#+begin_src go
// Code generated by "gogen option"; DO NOT EDIT.
// Exec: "gogen option"
// Version: 0.0.1
package sample
import (
log "log"
)
var _ = ConfigOptionDeclareWithDefault()
// Google Public DNS provides two distinct DoH APIs at these endpoints
// Using the GET method can reduce latency, as it is cached more effectively.
// RFC 8484 GET requests must have a ?dns= query parameter with a Base64Url encoded DNS message. The GET method is the only method supported for the JSON API.
type ConfigOptions struct {
// test comment 1
// test comment 2
TestNil interface{} // test comment 3
TestBool bool // test comment 4
// 这里是函数注释1
// 这里是函数注释2
TestInt int // default 32
TestInt64 int64 // int64 line
TestSliceInt []int // slice int
TestSliceInt64 []int64 // slice int64 line
TestSliceString []string // slice string
TestSliceBool []bool // slice bool line comment
TestSliceIntNil []int // TestSliceIntNil line comment
TestSliceByte []byte // TestSliceByte line comment
// SliceInt Doc
TestSliceIntEmpty []int
TestMapIntInt map[int]int // TestMapIntInt line comment
TestMapIntString map[int]string // TestMapIntString line comment
TestMapStringInt map[string]int // TestMapStringInt line comment
// MapStringString Doc
TestMapStringString map[string]string // MapStringString Line Comment
TestString string
// Food Doc
Food (*string) // Food Line Comment
// Walk Doc
Walk func() // Walk Line Comment
// TestNilFunc
TestNilFunc (func()) // 中文1
// TestReserved1_
TestReserved1 []byte // 在调优或者运行阶段,我们可能需要动态查看连接池中的一些指标,
// 来判断设置的值是否合理,或者检测连接池是否有异常情况出现
TestReserved2 int // TestReserved2Inner after
}
// test comment 1
// test comment 2
func WithTestNil(v interface{}) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestNil
cc.TestNil = v
return WithTestNil(previous)
}
}
func WithTestBool(v bool) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestBool
cc.TestBool = v
return WithTestBool(previous)
}
}
// 这里是函数注释1
// 这里是函数注释2
func WithTestInt(v int) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestInt
cc.TestInt = v
return WithTestInt(previous)
}
}
/// .. Omit part of the code
// SliceInt Doc
func WithTestSliceIntEmpty(v ...int) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestSliceIntEmpty
cc.TestSliceIntEmpty = v
return WithTestSliceIntEmpty(previous...)
}
}
func WithTestMapIntInt(v map[int]int) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestMapIntInt
cc.TestMapIntInt = v
return WithTestMapIntInt(previous)
}
}
/// .. Omit part of the code
// TestReserved1_
func withTestReserved1(v []byte) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestReserved1
cc.TestReserved1 = v
return withTestReserved1(previous)
}
}
// 来判断设置的值是否合理,或者检测连接池是否有异常情况出现
func withTestReserved2(v int) ConfigOption {
return func(cc *ConfigOptions) ConfigOption {
previous := cc.TestReserved2
cc.TestReserved2 = v
return withTestReserved2(previous)
}
}
// SetOption modify options
func (cc *ConfigOptions) SetOption(opt ConfigOption) {
_ = opt(cc)
}
// ApplyOption modify options
func (cc *ConfigOptions) ApplyOption(opts ...ConfigOption) {
for _, opt := range opts {
_ = opt(cc)
}
}
// GetSetOption modify and get last option
func (cc *ConfigOptions) GetSetOption(opt ConfigOption) ConfigOption {
return opt(cc)
}
// ConfigOption option define
type ConfigOption func(cc *ConfigOptions) ConfigOption
// NewConfigOptions create options instance.
func NewConfigOptions(opts ...ConfigOption) *ConfigOptions {
cc := newDefaultConfigOptions()
for _, opt := range opts {
_ = opt(cc)
}
if watchDogConfigOptions != nil {
watchDogConfigOptions(cc)
}
return cc
}
// InstallConfigOptionsWatchDog install watch dog
func InstallConfigOptionsWatchDog(dog func(cc *ConfigOptions)) {
watchDogConfigOptions = dog
}
var watchDogConfigOptions func(cc *ConfigOptions)
// newDefaultConfigOptions new option with default value
func newDefaultConfigOptions() *ConfigOptions {
cc := &ConfigOptions{
TestNil: nil,
TestBool: false,
TestInt: 32,
TestInt64: 32,
TestSliceInt: []int{1, 2, 3},
TestSliceInt64: []int64{1, 2, 3},
TestSliceString: []string{"test1", "test2"},
TestSliceBool: []bool{false, true},
TestSliceIntNil: nil,
TestSliceByte: nil,
TestSliceIntEmpty: nil,
TestMapIntInt: map[int]int{1: 1, 2: 2, 3: 3},
TestMapIntString: map[int]string{1: "test"},
TestMapStringInt: map[string]int{"test": 1},
TestMapStringString: map[string]string{"test": "test"},
TestString: "Meow",
Food: nil,
Walk: func() {
log.Println("Walking")
},
TestNilFunc: nil,
TestReserved1: nil,
TestReserved2: 1,
}
return cc
}
#+end_src
** imake
#+begin_example
Flags:
-h, --help help for imake
--ignore-empty-struct ignore empty struct(not has funcions)
--ignore-unexport-method is ignore unexport method (default true)
--ignore-unexport-struct is ignore unexport struct (default true)
-m, --match type match struct name;current option is mutually exclusive with type
--mock generate struct mock functions
-o, --output string output file name; default stdout
-s, --suffix string add interface name suffix (default "IFace")
--tags strings comma-separated list of build tags to apply
--to string generated package name (default ".")
-t, --type match list of type names; current option is mutually exclusive with match
-v, --version version for imake
#+end_example
#+begin_src shell
gogen imake "github.com/go-redis/redis/v8" --to redismock -m ".*Cmd$" -o samples/redismock/redis.go --mock
#+end_src
[[./samples/redismock/][redismock]] generate code sample
** TODO-LIST
[[https://github.com/ncw/gotemplate][github.com/ncw/gotemplate]]
** others
[[https://github.com/xyz347/pbidl/][pbidl - protobuf parse by goyacc]]