美文网首页
golang利用模板生成Service Container

golang利用模板生成Service Container

作者: EasyNetCN | 来源:发表于2021-07-23 10:27 被阅读0次

    对于Repository具有固定参数的构造函数,但是对于Service的构造函数参数是不固定的。开始的时候,尝试用反射的方法,感觉非常麻烦,走不通,突发奇想,直接用文件解析的方法,解析Service的New构造函数。

    type Service struct {
        Name string
        Args []ServiceArg
    }
    
    func (s Service) NewFuncString() string {
        sb := new(strings.Builder)
    
        hasEngine := false
        hasLogger := false
        repositoryArgs := make([]ServiceArg, 0)
    
        for _, arg := range s.Args {
            if strings.HasPrefix(arg.TypeName, "*xorm.Engine") && hasEngine == false {
                hasEngine = true
            } else if strings.HasPrefix(arg.TypeName, "*golog.Logger") && hasLogger == false {
                hasLogger = true
            } else if strings.HasPrefix(arg.TypeName, "repository.") {
                repositoryArgs = append(repositoryArgs, arg)
            }
        }
    
        if hasEngine {
            sb.WriteString("engine,\n")
        }
    
        if hasLogger {
            sb.WriteString("logger,\n")
        }
    
        for _, arg := range repositoryArgs {
            sb.WriteString("repositoryContainer.")
            sb.WriteString(arg.TypeName[len("repository."):])
            sb.WriteString(",\n")
        }
    
        return sb.String()
    }
    
    type ServiceArg struct {
        Name     string
        TypeName string
    }
    
    type ServiceContext struct {
        Services []Service
    }
    
    func Test_GenerateServiceContainer(t *testing.T) {
        files, err1 := os.ReadDir("../service")
    
        if err1 != nil {
            fmt.Println("parse file err:", err1)
            return
        }
    
        services := make([]Service, 0)
    
        for _, file := range files {
            filename := file.Name()
    
            if strings.HasSuffix(filename, "_service.go") {
                serviceName := UpperCamelCase(filename[:len(filename)-3])
    
                args, err2 := ServiceArgs(fmt.Sprintf("../service/%s", filename), serviceName)
    
                if err2 != nil {
                    fmt.Println(err2)
    
                    return
                }
    
                services = append(services, Service{Name: serviceName, Args: args})
    
            }
        }
    
        if f, err := os.Stat("../service/service_container.go"); f != nil && err == nil {
            if err := os.Remove("../service/service_container.go"); err != nil {
                fmt.Println("remove file err:", err)
                return
            }
        }
    
        f, err2 := os.OpenFile("../service/service_container.go", os.O_CREATE|os.O_WRONLY, 0666)
    
        defer f.Close()
    
        if err2 != nil {
            fmt.Println("can not create output file,err:", err2)
    
            return
        }
    
        tpl, err3 := template.New("service-container.tpl").ParseFiles("./service-container.tpl")
    
        if err3 != nil {
            fmt.Println("parse file err:", err3)
            return
        }
    
        if err := tpl.Execute(f, &ServiceContext{Services: services}); err != nil {
            fmt.Println("There was an error:", err.Error())
        }
    }
    
    func UpperCamelCase(txt string) string {
        sb := new(strings.Builder)
    
        strs := strings.Split(txt, "_")
    
        for _, str := range strs {
            sb.WriteString(strings.ToUpper(string(str[0])))
            sb.WriteString(str[1:])
        }
    
        return sb.String()
    }
    
    func ServiceArgs(filename, serviceName string) ([]ServiceArg, error) {
        content, err1 := ReadGoFile(filename)
    
        if err1 != nil {
            return nil, err1
        }
    
        args := make([]ServiceArg, 0)
    
        startTxt := fmt.Sprintf("New%s(", serviceName)
    
        firstIndex := strings.Index(content, startTxt) + len(startTxt)
        lastIndex := firstIndex + strings.Index(content[firstIndex:], ")")
    
        reg := regexp.MustCompile(`\s+`)
    
        strs := strings.Split(reg.ReplaceAllString(content[firstIndex:lastIndex], " "), ",")
    
        for _, str := range strs {
            txt := strings.TrimSpace(str)
    
            if len(txt) > 0 {
                args = append(args, Arg(txt))
            }
        }
    
        return args, nil
    }
    
    func Arg(str string) ServiceArg {
        strs := strings.Split(str, " ")
    
        return ServiceArg{Name: strings.TrimSpace(strs[0]), TypeName: strings.TrimSpace(strs[1])}
    }
    
    func ReadGoFile(fileName string) (string, error) {
        f, err := os.OpenFile(fileName, os.O_RDONLY, 0600)
    
        defer f.Close()
    
        if err != nil {
            return "", err
        } else {
            if bytes, err := ioutil.ReadAll(f); err != nil {
                return "", err
            } else {
                return string(bytes), nil
            }
        }
    }
    

    模板

    package service
    
    import (
        "github.com/kataras/golog"
        "xorm.io/xorm"
    )
    
    type ServiceContainer struct{
        {{range $service := .Services -}}
        {{.Name}} {{.Name}} 
        {{end -}}
    }
    
    func NewServiceContainer(engine *xorm.Engine, logger *golog.Logger, repositoryContainer repository.RepositoryContainer) *ServiceContainer{
        return &ServiceContainer{
            {{range $service := .Services -}}
            {{.Name}}: New{{.Name}}({{.NewFuncString}}),
            {{end -}}
        }
    }
    

    相关文章

      网友评论

          本文标题:golang利用模板生成Service Container

          本文链接:https://www.haomeiwen.com/subject/ygvumltx.html