meta

package module
v0.0.0-...-57ed551 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Nov 19, 2022 License: Apache-2.0 Imports: 26 Imported by: 8

README

Meta

本库是为了实现Golang的元编程(Metaprogramming)。

元编程是一种编程技术,使计算机程序能够将其他程序视为其数据。 这意味着一个程序可以被设计为读取、生成、分析或转换其他程序,甚至在运行时修改自身。 在某些情况下,这使程序员可以最大限度地减少表达解决方案的代码行数,从而减少开发时间。

目标

  • 消除样板代码(Boilerplate code)
  • 可以面向切面编程(Aspect-Oriented Programming)

应用场景包括但不限于

  • 通过方法签名生成数据库访问实现(类Spring Data), 参看sqlmap
  • 缓存切面
  • 事务切面
  • 熔断及降级切面
  • 链路跟踪切面
  • 自动注入,参看autowire

原理

很多编程语言都支持元编程,例如Java,主要通过反射加注解。

Golang通过Tag加反射也能进行元编程,但有以下缺点

  1. Tag仅支持结构成员
  2. 反射容易受语言本身限制
  3. 反射容易对性能产生负影响
  4. 反射只能在运行时才能发现问题

本库选择使用代码生成的方式

  1. 使用标准库asttypes包解析代码及注释
  2. 使用标准库text/template包作为模版进行代码生成
  3. 封装常用代码解析函数作为模版的自定义函数,简化模版编写复杂度

功能

  1. 解析Golang源码及注释
  2. 丰富的代码解析类模版函数
  3. 高度可定制,用户可以自定义模版函数及模版,用于生成自己想要的程序

使用

简单示例

本例子演示为注释有//+iface.Ifacestruct生成接口

//SomeStruct
//+iface.Iface
type SomeStruct struct {
}

func (s *SomeStruct) PublicMethod(ctx context.Context, id int64) (string, error) {
	return "nil", nil
}

func (s *SomeStruct) privateMethod(ctx context.Context, time time.Time) (int32, error) {
	return 0, nil
}

//NoneMethodStruct
//+iface.Iface
type NoneMethodStruct struct {
}
// define template
var tplText = `
{{range $struct := structs|filterByMeta "+iface.Iface"}}
    {{$decorator := print $struct.Name "AOPIface"}}
    type {{$decorator}} interface {
    {{range $method := $struct|methods}}
        {{if $method|exported}}
            {{$method|declare}}
        {{end}}
    {{end}}
    }
{{end}}
`

func Genearte() {
	//scan current mod code
	err := ScanCurrentMod().
		// register template
		TemplateText(tplText).
		// the package path must regex match the rule
		RegexOr("testdata").
		// you can add more generator
		And().
		// generate code
		Generate()

	if err != nil {
		fmt.Println(err.Error())
		return
	}
}
// Code generated by meta. DO NOT EDIT.

package testdata

import (
	"context"
)

type NoneMethodStructAOPIface interface {
}

type SomeStructAOPIface interface {
	PublicMethod(ctx context.Context, id int64) (string, error)
}

复杂示例

本例子演示为注释//+sqlmap.Mapperinterface生成数据库访问实现(类Spring Data)

  • 待生成实现的interface,user.go
    • 为方法FindByBirthdayGTE按方法签名生成数据库访问实现
    • 为方法FindByBirthdayGTE2按方法上的+sqlmap.Selectquery参数对应的sql生成数据库访问实现
//UserDao
//+sqlmap.Mapper Table=`user` Dialect="mysql"
type UserDao interface {

	// FindByBirthdayGTE
	FindByBirthdayGTE(ctx context.Context /*sql:param ctx*/, time time.Time) ([]*User, error)

	//FindByBirthdayGTE2
	/*+sqlmap.Select Query="select * from `user` where birthday >= :time"*/
	FindByBirthdayGTE2(ctx context.Context /*sql:param ctx*/, time time.Time) ([]*User, error)
}
package testdata

import (
	"context"
	"time"

	"github.com/gomelon/melon/data"
)

var _ UserDao = &UserDaoSQLImpl{}

type UserDaoSQLImpl struct {
	_tm *data.SQLTXManager
}

func NewUserDaoSQLImpl(_tm *data.SQLTXManager) *UserDaoSQLImpl {
	return &UserDaoSQLImpl{
		_tm: _tm,
	}
}

func (_impl *UserDaoSQLImpl) FindByBirthdayGTE(ctx context.Context, time time.Time) ([]*User, error) {
	_sql := "SELECT id, name, gender, birthday, created_at FROM `user` WHERE (`birthday` >= ?)"
	_rows, _err := _impl._tm.OriginTXOrDB(ctx).
		Query(_sql, time)

	var _items []*User
	if _err != nil {
		return _items, _err
	}

	defer _rows.Close()

	if !_rows.Next() {
		return _items, _rows.Err()
	}

	for _rows.Next() {
		_item := &User{}
		_err = _rows.Scan(&_item.Id, &_item.Name, &_item.Gender, &_item.Birthday, &_item.CreatedAt)
		if _err != nil {
			return _items, _err
		}
		_items = append(_items, _item)
	}
	return _items, nil
}

func (_impl *UserDaoSQLImpl) FindByBirthdayGTE2(ctx context.Context, time time.Time) ([]*User, error) {
	_sql := "select id, name, gender, birthday, created_at from `user` where birthday >= ?"
	_rows, _err := _impl._tm.OriginTXOrDB(ctx).
		Query(_sql, time)

	var _items []*User
	if _err != nil {
		return _items, _err
	}

	defer _rows.Close()

	if !_rows.Next() {
		return _items, _rows.Err()
	}

	for _rows.Next() {
		_item := &User{}
		_err = _rows.Scan(&_item.Id, &_item.Name, &_item.Gender, &_item.Birthday, &_item.CreatedAt)
		if _err != nil {
			return _items, _err
		}
		_items = append(_items, _item)
	}
	return _items, nil
}

主要函数

Documentation

Index

Constants

View Source
const (
	GeneratedBuildTag = "ignore_meta_generated"
	GeneratedComment  = "// Code generated by meta. DO NOT EDIT.\n\n"
)
View Source
const (
	DefaultOutputFilePrefix = "zz_"
	DefaultOutputFileSuffix = "_gen"
)
View Source
const (
	TypeNamePointer   = "Pointer"
	TypeNameStruct    = "Struct"
	TypeNameInterface = "Interface"
	TypeNameSignature = "Signature"
	TypeNameBasic     = "Basic"
	TypeNameSlice     = "Slice"
	TypeNameMap       = "Map"
	TypeNameNamed     = "Named"
	TypeNameTuple     = "Tuple" //see types.Tuple
	TypeNameArray     = "Array"
	TypeNameChan      = "Chan"
)

Variables

This section is empty.

Functions

func HasGoFile

func HasGoFile(root string) (has bool, err error)

func ModuleSrcPath

func ModuleSrcPath(inputPath string) (goModDirPath string, err error)

func PkgNameOrAlias

func PkgNameOrAlias(tracker ImportTracker, pkgPath string) string

func ScanCurrentMod

func ScanCurrentMod() *scanner

func ScanFor

func ScanFor(rootPath string) *scanner

Types

type Decl

type Decl struct {
}

Decl annotate for a strut as a meta declaration +meta.Decl

type DefaultImportTracker

type DefaultImportTracker struct {
	// contains filtered or unexported fields
}

func NewDefaultImportTracker

func NewDefaultImportTracker(localPkgPath string) *DefaultImportTracker

func (*DefaultImportTracker) Import

func (tracker *DefaultImportTracker) Import(pkgPath string) string

func (*DefaultImportTracker) ImportLines

func (tracker *DefaultImportTracker) ImportLines() []string

func (*DefaultImportTracker) LocalNameOf

func (tracker *DefaultImportTracker) LocalNameOf(pkgPath string) string

func (*DefaultImportTracker) PathOf

func (tracker *DefaultImportTracker) PathOf(localName string) (string, bool)

type Group

type Group []*Meta

Group a group is consists of multiple Meta with the same name

type ImportTracker

type ImportTracker interface {
	Import(pkgPath string) string
	LocalNameOf(packagePath string) string
	PathOf(localName string) (string, bool)
	ImportLines() []string
}

type Meta

type Meta struct {
	// contains filtered or unexported fields
}

func New

func New(qualifyName string) *Meta

func (*Meta) MapTo

func (m *Meta) MapTo(obj any) error

func (*Meta) Properties

func (m *Meta) Properties() map[string]any

func (*Meta) Property

func (m *Meta) Property(key string) any

func (*Meta) QualifyName

func (m *Meta) QualifyName() string

func (*Meta) SetProperties

func (m *Meta) SetProperties(properties map[string]any) *Meta

func (*Meta) SetProperty

func (m *Meta) SetProperty(key, value string) *Meta

type Parser

type Parser struct {
	// contains filtered or unexported fields
}

func NewParser

func NewParser(pkgParser *PkgParser) *Parser

func (*Parser) FilterByMeta

func (p *Parser) FilterByMeta(metaName string, objects []types.Object) []types.Object

func (*Parser) FilterByMethodHasMeta

func (p *Parser) FilterByMethodHasMeta(metaName string, objects []types.Object) []types.Object

func (*Parser) HasMeta

func (p *Parser) HasMeta(metaName string, object types.Object) bool

func (*Parser) HasMethodHasMeta

func (p *Parser) HasMethodHasMeta(metaName string, object types.Object) bool

func (*Parser) ObjectMeta

func (p *Parser) ObjectMeta(object types.Object, metaName string) (m *Meta)

func (*Parser) ObjectMetaGroup

func (p *Parser) ObjectMetaGroup(object types.Object, metaName string) (parsedMetaGroup Group)

func (*Parser) ObjectMetaGroups

func (p *Parser) ObjectMetaGroups(object types.Object, metaNames ...string) (
	parsedMetaGroups map[string]Group)

type PathMatcher

type PathMatcher func(absPath, relPath string, patterns ...string) (bool, error)
var RegexOrPathMatcher PathMatcher = func(absPath, relPath string, patterns ...string) (match bool, err error) {
	if len(patterns) == 0 || (len(patterns) == 1 && len(patterns[0]) == 0) {
		match = true
		return
	}
	for _, pattern := range patterns {
		match, err = regexp.MatchString(pattern, relPath)
		if err != nil {
			return
		}
		if match {
			return
		}
	}
	return
}

type PkgGen

type PkgGen interface {
	Bytes() ([]byte, error)
	Write(writer io.Writer) error
	Print() error
	Generate() error
}

type PkgGenFactory

type PkgGenFactory interface {
	Create(absPath, relPath string) (PkgGen, error)
}

type PkgParser

type PkgParser struct {
	// contains filtered or unexported fields
}

func NewPkgParser

func NewPkgParser() *PkgParser

func (*PkgParser) AnonymousAssign

func (pp *PkgParser) AnonymousAssign(t types.Type) (values []types.Type)

AnonymousAssign return anonymous assign some value to t var _ Foo = FooImpl{} Foo is the t,FooImpl is the result

func (*PkgParser) AnonymousAssignTo

func (pp *PkgParser) AnonymousAssignTo(v types.Type) (types []types.Type)

AnonymousAssignTo return anonymous assign some value to t var _ Foo = FooImpl{} Foo is the result,FooImpl is the v

func (*PkgParser) AssignableTo

func (pp *PkgParser) AssignableTo(v, t types.Type) bool

AssignableTo reports whether a value of type V is assignable to a variable of type T. The behavior of AssignableTo is undefined if V or T is an uninstantiated generic type.

func (*PkgParser) AssignableToCtx

func (pp *PkgParser) AssignableToCtx(v types.Type) bool

AssignableToCtx reports whether a value of type V is assignable to context.Context. The behavior of AssignableTo is undefined if V or T is an uninstantiated generic type.

func (*PkgParser) Comments

func (pp *PkgParser) Comments(pos token.Pos) []string

func (*PkgParser) FirstParam

func (pp *PkgParser) FirstParam(methodOrFunc types.Object) types.Object

func (*PkgParser) FirstResult

func (pp *PkgParser) FirstResult(methodOrFunc types.Object) types.Object

func (*PkgParser) Functions

func (pp *PkgParser) Functions(pkgPath string) []types.Object

func (*PkgParser) HasErrorResult

func (pp *PkgParser) HasErrorResult(methodOrFunc types.Object) bool

func (*PkgParser) Indirect

func (pp *PkgParser) Indirect(typ types.Type) types.Type

func (*PkgParser) InterfaceMethods

func (pp *PkgParser) InterfaceMethods(object types.Object) []types.Object

func (*PkgParser) Interfaces

func (pp *PkgParser) Interfaces(pkgPath string) []types.Object

func (*PkgParser) LastResult

func (pp *PkgParser) LastResult(methodOrFunc types.Object) types.Object

func (*PkgParser) Load

func (pp *PkgParser) Load(paths ...string) (err error)

Load path, path may be relative path/absolute path/package path

func (*PkgParser) Methods

func (pp *PkgParser) Methods(object types.Object) []types.Object

func (*PkgParser) Object

func (pp *PkgParser) Object(pkgPath, typeName string) types.Object

func (*PkgParser) ObjectComments

func (pp *PkgParser) ObjectComments(object types.Object) []string

func (*PkgParser) ObjectPlace

func (pp *PkgParser) ObjectPlace(object types.Object) (objectPlace Place)

func (*PkgParser) Package

func (pp *PkgParser) Package(pkgPath string) *packages.Package

func (*PkgParser) Params

func (pp *PkgParser) Params(methodOrFunc types.Object) []types.Object

func (*PkgParser) Path

func (pp *PkgParser) Path(pkgPath string) string

func (*PkgParser) PkgPath

func (pp *PkgParser) PkgPath(path string) string

func (*PkgParser) Results

func (pp *PkgParser) Results(methodOrFunc types.Object) []types.Object

func (*PkgParser) StructMethods

func (pp *PkgParser) StructMethods(object types.Object) []types.Object

func (*PkgParser) Structs

func (pp *PkgParser) Structs(pkgPath string) []types.Object

func (*PkgParser) TypeName

func (pp *PkgParser) TypeName(typ types.Type) string

func (*PkgParser) UnderlyingType

func (pp *PkgParser) UnderlyingType(typ types.Type) types.Type

type Place

type Place uint32
const (
	PlaceUnknown       = 0
	PlaceConst   Place = 1 << iota
	PlaceVar
	PlaceInterface
	PlaceStruct
	PlaceField
	PlaceInterfaceMethod
	PlaceStructMethod
	PlaceFunc
	//TODO seperate param and result
	PlaceFuncVar //func/method param or result, because can't distinguish on named result
)

type TPGFuncMapFactory

type TPGFuncMapFactory func(generator *TmplPkgGen) template.FuncMap

type TPGOption

type TPGOption func(gen *TmplPkgGen)

func WithFuncMap

func WithFuncMap(funcMap template.FuncMap) TPGOption

func WithFuncMapFactory

func WithFuncMapFactory(factory TPGFuncMapFactory) TPGOption

func WithImportTracker

func WithImportTracker(tracker ImportTracker) TPGOption

func WithMetaParser

func WithMetaParser(metaParser *Parser) TPGOption

func WithOutputFilePrefix

func WithOutputFilePrefix(prefix string) TPGOption

func WithOutputFileSuffix

func WithOutputFileSuffix(suffix string) TPGOption

func WithOutputFilename

func WithOutputFilename(filename string) TPGOption

func WithOutputFullFilename

func WithOutputFullFilename(fullFilename string) TPGOption

func WithPkgParser

func WithPkgParser(pkgParser *PkgParser) TPGOption

type TmplPkgGen

type TmplPkgGen struct {
	// contains filtered or unexported fields
}

func NewTmplPkgGen

func NewTmplPkgGen(path string, templateText string, options ...TPGOption) (gen *TmplPkgGen, err error)

func (*TmplPkgGen) Bytes

func (gen *TmplPkgGen) Bytes() ([]byte, error)

func (*TmplPkgGen) Generate

func (gen *TmplPkgGen) Generate() error

func (*TmplPkgGen) ImportTracker

func (gen *TmplPkgGen) ImportTracker() ImportTracker

func (*TmplPkgGen) MetaParser

func (gen *TmplPkgGen) MetaParser() *Parser

func (*TmplPkgGen) PkgFunctions

func (gen *TmplPkgGen) PkgFunctions() *functions

func (*TmplPkgGen) PkgParser

func (gen *TmplPkgGen) PkgParser() *PkgParser

func (*TmplPkgGen) PkgPath

func (gen *TmplPkgGen) PkgPath() string

func (*TmplPkgGen) Print

func (gen *TmplPkgGen) Print() error

func (*TmplPkgGen) Write

func (gen *TmplPkgGen) Write(writer io.Writer) error

type TmplPkgGenFactory

type TmplPkgGenFactory struct {
	// contains filtered or unexported fields
}

func NewTmplPkgGenFactory

func NewTmplPkgGenFactory(templateText string, options ...TPGOption) *TmplPkgGenFactory

func (*TmplPkgGenFactory) Create

func (t *TmplPkgGenFactory) Create(absPath, relPath string) (PkgGen, error)

Directories

Path Synopsis

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL