blob: 1082bbee2a00f8c50d288679c3de91521965c2e2 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package main
import (
"flag"
"fmt"
"html/template"
"log"
"os"
"strings"
)
type Strings []string
func (t *Strings) String() string {
return fmt.Sprint(*t)
}
func (t *Strings) Set(value string) error {
*t = append(*t, value)
return nil
}
type viewData struct {
ClassName string
PackageName string
EnumName string
EnumValues []string
}
func snakeCase(name string) string {
if name == "" {
return ""
}
var s string
for k, v := range []rune(name) {
if v >= 'A' && v <= 'Z' {
if k > 0 {
s += "_"
}
v += 32
}
s += string(v)
}
return s
}
func pascalCase(name string) string {
if name == "" {
return ""
}
var s string
for _, v := range strings.Split(name, "_") {
runes := []rune(v)
for k, vv := range runes {
if k == 0 {
if vv >= 'a' && vv <= 'z' {
vv -= 32
}
} else if vv >= 'A' && vv <= 'Z' {
vv += 32
}
s += string(vv)
}
}
return s
}
const (
usage = `gen-go-enum can generate golang code for hessian2 java enum.
Usage: gen-go-enum -c java_classname [-p golang_package_name] [-e golang_enum_name] -v java_enum_value [-v java_enum_value] [-o target_file]
Options
-c java class name (eg: com.test.enums.TestEnum)
-p golang package name, use 'enum' when not specified (eg: test_enums)
-e golang enum type name, use java class name when not specified (eg: TestEnum)
-v java enum values, can specify multiple (eg: -v TEST1 -v TEST2 -v TEST3)
-o golang code file path, stored in the current directory when not specified
Example
gen-go-enum -c com.test.enums.TestColorEnum -v RED -v BLUE -v YELLOW
gen-go-enum -c com.test.enums.TestColorEnum -p test_enums -e ColorEnum -v RED -v BLUE -v YELLOW -o ./color_enum.go
`
enumTempl = `package {{.PackageName}}
import (
"strconv"
)
import (
hessian "github.com/apache/dubbo-go-hessian2"
)
const (
{{- range $index, $value := .EnumValues }}
{{$.EnumName}}{{ pascalCase $value}}{{ if eq $index 0 }} {{$.EnumName}} = iota{{ end }}
{{- end }}
)
var _{{.EnumName}}Values = map[{{.EnumName}}]string{
{{- range $index, $value := .EnumValues }}
{{$.EnumName}}{{ pascalCase $value}}: "{{$value}}",
{{- end }}
}
var _{{.EnumName}}Entities = map[string]{{.EnumName}}{
{{- range $index, $value := .EnumValues }}
"{{$value}}": {{$.EnumName}}{{ pascalCase $value}},
{{- end }}
}
type {{.EnumName}} hessian.JavaEnum
func (e {{.EnumName}}) JavaClassName() string {
return "{{.ClassName}}"
}
func (e {{.EnumName}}) String() string {
if v, ok := _{{.EnumName}}Values[e]; ok {
return v
}
return strconv.Itoa(int(e))
}
func (e {{.EnumName}}) EnumValue(s string) hessian.JavaEnum {
if v, ok := _{{.EnumName}}Entities[s]; ok {
return hessian.JavaEnum(v)
}
return hessian.InvalidJavaEnum
}
func New{{.EnumName}}(s string) {{.EnumName}} {
if v, ok := _{{.EnumName}}Entities[s]; ok {
return v
}
return {{.EnumName}}(hessian.InvalidJavaEnum)
}
func init() {
for v := range _{{.EnumName}}Values {
hessian.RegisterJavaEnum(v)
}
}`
)
var (
className string
packageName string
enumName string
enumValues Strings
targetFile string
)
func init() {
flag.StringVar(&className, "c", "", "")
flag.StringVar(&packageName, "p", "enum", "")
flag.StringVar(&enumName, "e", "", "")
flag.Var(&enumValues, "v", "")
flag.StringVar(&targetFile, "o", "", "")
flag.Usage = func() {
fmt.Print(usage)
}
}
func main() {
flag.Parse()
if className == "" || len(enumValues) == 0 {
flag.Usage()
return
}
if packageName == "" {
packageName = "enum"
}
if enumName == "" {
classItems := strings.Split(className, ".")
enumName = classItems[len(classItems)-1]
}
if targetFile == "" {
targetFile = snakeCase(enumName) + ".go"
}
tmpl, err := template.New("enum").Funcs(template.FuncMap{"pascalCase": pascalCase}).Parse(enumTempl)
if err != nil {
log.Fatalln("Error: can't parse code template!!!", err)
}
fd, err := os.Create(targetFile)
if err != nil {
log.Fatalln("Error: can't open target file!!!", err)
}
defer func() { _ = fd.Close() }()
err = tmpl.Execute(fd, &viewData{
ClassName: className,
PackageName: packageName,
EnumName: enumName,
EnumValues: enumValues,
})
if err != nil {
log.Fatalln("Error: can't write target file!!!", err)
}
fmt.Printf("Create file '%s'!\n", targetFile)
}