GithubHelp home page GithubHelp logo

gophc / go-decorator Goto Github PK

View Code? Open in Web Editor NEW

This project forked from dengsgo/go-decorator

0.0 0.0 0.0 165 KB

让 Go 便捷使用装饰器的工具,装饰器能够切面 (AOP)、代理 (Proxy) 任意的函数和方法,提供观察和控制函数的能力。go-decorator is a tool that allows Go to easily use decorators. The decorator can slice aspect (AOP) and proxy any function and method, providing the ability to observe and control functions.

License: MIT License

Go 100.00%

go-decorator's Introduction

go-decorator

Actions Go Report Card godoc.org Go doc

中文 | English

Beta version, use with caution in production environments. Click ⭐Star to follow the project's progress.

go-decorator, Go 便捷使用装饰器的工具,装饰器能够切面 (AOP)、代理 (Proxy) 任意的函数和方法,提供观察和控制函数的能力。

go-decorator is a tool that allows Go to easily use decorators. The decorator can slice aspect (AOP) and proxy any function and method, providing the ability to observe and control functions.

Feature

  • Add the comment //go:decor F to use the decorator (F is the decorator function) to quickly complete the logic such as "boilerplate code injection, non-intrusive function behavior change, control logic flow";
  • You can freely define functions as decorators and apply them to any top-level function or method;
  • Support the use of multiple (line) //go:decor decorator decorate the functions;
  • Support comment type T types type declaration, decorator will automatically decorate proxy all methods with T or *T as the receiver;
  • The decorator supports optional parameters, which brings more possibilities to development.
  • Support compile-time lint verification to ensure the robustness of Go compiled code.
  • Provide helpful error hints to detect problems at compile time and give the cause and line number of the error (e.g. undefined decorator or unreferenced package, etc.).
  • Enhancing the target function only at compile time does not degrade the performance of the compiled program, nor does it have reflection operations.

Decorator usage can be similar to other languages such as Python, TypeScript. (Ideal for caching, forensics, logging, and other scenarios, as an aid to free up duplicate coding).

go-decorator is a compile-time decorator injection technique. Using it does not affect your project's source files and does not generate additional .go files or other redundant files in your project. This injection method is very different from the go:generate generation method.

Guide

查看: 中文文档 | English Guide

Install

Install via go install.

$ go install github.com/dengsgo/go-decorator/cmd/decorator@latest

Run decorator and it will show you the decorator version.

$ decorator
decorator v0.21.0 beta , https://github.com/dengsgo/go-decorator

Tip: Run the above installation command frequently to install the latest version for bug fixes, enhanced experience, and more new features.

Usage

decorator relies on the native go command to call it, just add the -toolexec decorator parameter to the subcommand of go. For example:

Native Command Use decorator
go build go build -toolexec decorator
go run main.go go run -toolexec decorator main.go
go test -v go test -toolexec decorator -v
go install go install -toolexec decorator
go ... -flags... go ... -toolexec decorator -flags...

Code

Introducing decorator dependencies in your project (must be a go.mod project):

$ go get -u github.com/dengsgo/go-decorator

Write similar code:

package main

import (
	"github.com/dengsgo/go-decorator/decor"
	"log"
)

func main() {
	// Call your function normally.
	// Since this is a function that declares the use of decorator logging,
	// The decorator compilation chain injects calls to the decorator method logging during code compilation.
	// So after compiling and running using the above method, you will get the following output:
	// 
	// 2023/08/13 20:26:30 decorator function logging in []
	// 2023/08/13 20:26:30 this is a function: myFunc
	// 2023/08/13 20:26:30 decorator function logging out []
	// 
	// Instead of just one sentence output from myFunc itself.
	// That is to say, the behavior of this method has been changed through the decorator!
	myFunc() 
}

// Declare that the function will be decorated using the decorator logging by using the go: decor annotation.
//
//go:decor logging
func myFunc() {
	log.Println("this is a function: myFunc")
}

// This is a regular function. 
// But it implements the func (*decor.Context) type, so it is still a decorator method,
// You can use this decorator on other functions.
// In the function, ctx is the decorator context, and the function name, input and output 
// parameters, and execution of the target function can be obtained through ctx.
// If ctx.TargetDo() is not executed in the function, it means that the target function will not execute,
// Even if you call the decorated target function in your code! At this point, the objective function returns zero values.
// Before ctx.TargetDo(), ctx.TargetIn can be modified to change the input parameter values.
// After ctx.TargetDo(), you can modify ctx.TargetOut to change the return value.
// Only the values of the input and output parameters can be changed. Don't try to change their type and quantity, as this will trigger runtime panic!!!
func logging(ctx *decor.Context) {
	log.Println("decorator function logging in", ctx.TargetIn)
	ctx.TargetDo()
	log.Println("decorator function logging out", ctx.TargetOut)
}

Decorator usage with parameters:

package main

import (
	"github.com/dengsgo/go-decorator/decor"
)

func main()  {
	optionalParametersFuncDemo()
}

// It is also a decorator, unlike a normal decorator, which allows the objective function to provide an additional parameter 'level'.
// Decorator provides lint syntax for developers to force verification when compiling code. For example:
// `Required` requires that the target function must pass a value to this field;
// `nonzero` requires that the objective function cannot pass values in time and space.
// If the compilation test fails, the compilation will fail.
// The usage is as follows: (See Guide.md for more usage):
//
//go:decor-lint required: {level}
//go:decor-lint nonzero: {level}
func levelLogging(ctx *decor.Context, level string)  {
	if level == "debug" {
		// to do something
	}
	ctx.TargetDo()
}

// This method uses the decorator levelLogging and passes the "level" parameter value "debug" to the decorator.
// 
//go:decor levelLogging#{level: "debug"}
func optionalParametersFuncDemo()  {
	// function code
}

Add a comment to the' type T types type declaration //go:decor F, and the decorator will automatically use the decorator F to decorate all methods that have T or *T as receiver:

package main

import (
	"github.com/dengsgo/go-decorator/decor"
)

// add comments //go:decor dumpTargetType,
// The structType method sets Name, StrName, and empty are automatically decorated by the decorator dumpTargetType proxy.
// The receiver of a method can be either a value receiver or a pointer receiver, and is automatically decorated.

//go:decor dumpTargetType
type structType struct {
	name string
}

func (s *structType) Name() string {
	return s.name
}

func (s *structType) StrName(name string) {
	s.name = name
}

func (s *structType) empty() {}

Example

example/usages This directory demonstrates how to write code correctly to use the decorator tool.

func main() {
	section("inner.go")
	// Example: Using a function with a package decorator
	useScopeInnerDecor("hello, world", 100)

	section("external.go")
	// Example: Functions using other wrapper decorators 
	useExternalaDecor()
	g.PrintfLn("plus(2, 3) = %+v", plus(2, 3))

	section("datetime.go")
	// Example: Code demonstrating the use of decorators in document Guide.md
	{
		t := 1692450000
		s := datetime(t)
		g.Printf("datetime(%d)=%s\n", t, s)
	}

	section("genericfunc.go")
	// Example: Generic functions using decorators
	g.PrintfLn("Sum(1, 2, 3, 4, 5, 6, 7, 8, 9) = %+v", Sum(1, 2, 3, 4, 5, 6, 7, 8, 9))

	section("method.go")
	// Example: methods using decorators
	{
		m := &methodTestPointerStruct{}
		m.doSomething("main called")
	}
	{
		m := methodTestRawStruct{}
		m.doSomething("main called")
	}

	section("withdecorparams.go")
	// Example: How to pass values when using a decorator with parameters 
	g.PrintfLn("useArgsDecor() = %+v", useArgsDecor())
	// Example: How to use Lint to constrain and validate the parameters of the objective function during compilation in a decorator
	g.Printf("useHitUseRequiredLint() = %+v", useHitUseRequiredLint())
	g.Printf("useHitUseNonzeroLint() = %+v", useHitUseNonzeroLint())
	g.Printf("useHitBothUseLint() = %+v", useHitBothUseLint())
	g.Printf("useHitUseMultilineLintDecor() = %+v", useHitUseMultilineLintDecor())

	section("types.go")
	// Support comment `type T types` type declaration, decorator will automatically decorate proxy all methods with `T` or `*T` as the receiver;  
	{
		// structural
		s := &structType{"main say hello"}
		g.PrintfLn("s.Name() = %+v", s.Name())
		s.StrName("StrName() set")
		g.PrintfLn("s.Name() = %+v", s.Name())
		s.empty()
	}
	{
		// type base
		v := varIntType(100)
		g.PrintfLn("v.value() = %+v", v.value())
		v.zeroSelf()
		g.PrintfLn("v.value() = %+v", v.value())
	}
	{
		// generic type T = int
		genInt := &genericType[int]{}
		g.PrintfLn("genInt.value() = %+v", genInt.value())
		// generic type T = struct
		genStruct := &genericType[struct{}]{}
		g.PrintfLn("genStruct.value() = %+v", genStruct.value())
	}

	section("types_multiple.go")
	// `type T types` 和它的方法同时使用装饰器。
	// 方法上的装饰器优先执行
	{
		m := multipleStructStandType{}
		m.sayHello()
	}
	{
		m := multipleStructWrapType{}
		m.sayNiHao()
	}

}

See more Guide .

Requirement

  • go1.18+
  • go.mod project

Issue

If you find any problems, you can provide feedback here. GitHub Issues

Contribute

The project is still under development and due to frequent changes, external contributions are temporarily not accepted. Welcome to submit a Pull Request after stabilization.

TODO

  • More documents.
  • IDE friendly tool support.
  • better performance.
  • More testing coverage.
  • More clear error reminders.
  • More...

go-decorator's People

Contributors

dengsgo avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.