reflectplus

package module
v0.0.0-...-81a9ded Latest Latest
Warning

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

Go to latest
Published: May 13, 2020 License: Apache-2.0 Imports: 14 Imported by: 0

README

reflectplus

The missing reflection bits for go. This library parses your go source code and generates reflection information at compile time, which can be inspected later at runtime. This can be also used for code generation.

Using this library, you can work around the following issues:

related work:

roadmap

  • interfaces
  • structs
  • package level functions
  • annotations
  • keep comments
  • struct constructors
  • annotation validation at parsing time
  • package level variables
  • package level constants
  • type aliases
  • other type definitions
  • interface proxy (stub code generation)
  • private functions, methods, types (will never be supported)

annotation support

In contrast to macros, annotations are just passive data key/value pairs in JSON notation for any type or function. The following notations are allowed:

// A MyRepo is for ...
// @Repo
// @Repo()
// @Repo({}) // comments allowed, outer {} can be omitted 
// @Repo({"value":5})
// @Repo(5) // implicitly wrapped into {"value": 5}
// @Repo("text") // implicitly wrapped into {"value": "text"}
// @Repo("value":"te:xt") // this is fine 
// @Repo("values":["can","be","multiple"])
// @Repo("anyKey":"anyValue","num":5,"bool":true,"nested":{"care":{"of":["your", "head"]}})
type MyRepo interface{
    //...
}

interface proxy support

The reflection and proxy support is just as you would have expected it:

package main

import (
    "my/module/pckage"
    "fmt"
    "github.com/worldiety/reflectplus"
    _ "my/module"
)

func main(){
    iface := reflectplus.FindInterface("my/module/pckage","MyInterface")
    fmt.Println(iface)

    proxy, err := reflectplus.NewProxy("my/module/pckage", "MyInterface", func(method string, args ...interface{}) []interface{} {
        fmt.Printf("hello %s\n", method)
        return nil
    })
    if err != nil {
        panic(err)
    }
    proxy.(pckage.MyInterface).MyMethod()
}


usage

# create a file like my/module/cmd/gen/gen.go
//go:generate go run gen.go
package main

import (
	"github.com/worldiety/reflectplus"
)

func main() {
	reflectplus.Must(reflectplus.Generate("../.."))
}

# import dependency
go get github.com/worldiety/reflectplus

# go generate
go generate ./...

# the generated file is my/module/reflect.gen.go, you need to import it, to run its init method
# e.g. in my/module/cmd/app/main.go
package main

import _ "github.com/worldiety/mercurius"

func main(){
//...
}
standalone
GO111MODULE=off && go get -u github.com/worldiety/reflectplus/cmd/reflectplus
cd my/module
reflectplus

FAQ

Does it work in go path?

This is a legacy configuration and not tested, so probably not.

Does it work with multiple modules?

Well it depends, the generated reflection metadata is always included, if the maintainer has included the reflectplus dependency. You also have to ensure to load the package (currently only the module import path) containing the init method which registers the additional reflection information and the interface proxy factories.

Documentation

Overview

reflectplus generates and embedds the missing pieces in the go reflection system.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddPackage

func AddPackage(pkg Package)

func AddProxyFactory

func AddProxyFactory(importPath string, name string, fac ProxyFactory)

func AddType

func AddType(importPath string, name string, p reflect.Type)

func FindByType

func FindByType(t reflect.Type) interface{}

FindByType tries to find the Struct or interface from the reflect type, otherwise returns nil.

func FindType

func FindType(importPath string, name string) reflect.Type

FindType returns the type or nil

func Generate

func Generate(dir string) error

func Must

func Must(err error)

func NewProxy

func NewProxy(importPath string, name string, handler InvocationHandler) (interface{}, error)

func PositionalError

func PositionalError(p Positional, causedBy error) error

Types

type Annotation

type Annotation struct {
	Doc    string                 `json:"doc,omitempty"`
	Text   string                 `json:"text,omitempty"`
	Name   string                 `json:"name,omitempty"`
	Values map[string]interface{} `json:"values,omitempty"`
	Pos    Pos                    `json:"pos,omitempty"`
}

An Annotation is actually an @-prefixed-named json object one-liner

func (Annotation) AsString

func (a Annotation) AsString(key string) string

func (Annotation) MustAsBool

func (a Annotation) MustAsBool(key string) bool

func (Annotation) MustAsFloat

func (a Annotation) MustAsFloat(key string) float64

func (Annotation) MustAsString

func (a Annotation) MustAsString(key string) string

func (Annotation) Position

func (a Annotation) Position() Pos

func (Annotation) Value

func (a Annotation) Value() string

Value returns the value for the "value"-key or the empty string

type Annotations

type Annotations []Annotation

func (Annotations) Has

func (s Annotations) Has(name string) bool

type Field

type Field struct {
	Doc         string       `json:"doc,omitempty"`
	Annotations []Annotation `json:"annotations,omitempty"`
	Name        string
	Type        TypeDecl          `json:"type,omitempty"`
	Tags        map[string]string `json:"tags,omitempty"`
	Pos         Pos               `json:"pos,omitempty"`
}

func (Field) Position

func (f Field) Position() Pos

type Interface

type Interface struct {
	Doc         string       `json:"doc,omitempty"`
	Annotations []Annotation `json:"annotations,omitempty"`
	ImportPath  string       `json:"importPath,omitempty"`
	Name        string       `json:"name,omitempty"`
	Methods     []Method     `json:"methods,omitempty"`
	Pos         Pos          `json:"pos,omitempty"`
}

func FindInterface

func FindInterface(importPath string, name string) *Interface

func Interfaces

func Interfaces() []Interface

func (*Interface) String

func (p *Interface) String() string

type InvocationHandler

type InvocationHandler func(method string, args ...interface{}) []interface{}

type Method

type Method struct {
	Doc         string       `json:"doc,omitempty"`
	Annotations []Annotation `json:"annotations,omitempty"`
	Receiver    *Param       `json:"receiver,omitempty"` // optional receiver, if this is actually a struct method not a function
	Name        string       `json:"name,omitempty"`
	Params      []Param      `json:"params,omitempty"`
	Returns     []Param      `json:"returns,omitempty"`
	Pos         Pos          `json:"pos,omitempty"`
}

func (Method) FindAnnotations

func (m Method) FindAnnotations(name string) []Annotation

func (Method) MustAnnotationByName

func (m Method) MustAnnotationByName(n string) Annotation

AnnotationByName asserts the existence of the named annotation and panics otherwise

func (Method) ParamAndIndexByName

func (m Method) ParamAndIndexByName(n string) (*Param, int)

func (Method) ParamByName

func (m Method) ParamByName(n string) *Param

func (Method) Position

func (m Method) Position() Pos

type Package

type Package struct {
	Doc        string       `json:"doc,omitempty"`
	ImportPath string       `json:"importPath,omitempty"`
	Name       string       `json:"name,omitempty"`
	Packages   []*Package   `json:"packages,omitempty"`
	Interfaces []*Interface `json:"interfaces,omitempty"`
	Structs    []*Struct    `json:"structs,omitempty"`
	Funcs      []Method     `json:"funcs,omitempty"`
}

func FindPackage

func FindPackage(importPath string) *Package

func ImportMetaData

func ImportMetaData(jsn []byte) (Package, error)

func Packages

func Packages() []Package

func ParseMetaModel

func ParseMetaModel(pkg *parser.Package) (*Package, error)

func (*Package) AllInterfaces

func (p *Package) AllInterfaces() []Interface

func (*Package) AllStructs

func (p *Package) AllStructs() []Struct

func (*Package) String

func (p *Package) String() string

func (*Package) VisitPackages

func (p *Package) VisitPackages(f func(pkg Package) bool)

type Param

type Param struct {
	Doc  string   `json:"doc,omitempty"`
	Name string   `json:"name,omitempty"`
	Type TypeDecl `json:"type,omitempty"`
}

type Pos

type Pos struct {
	Filename string `json:"filename,omitempty"`
	Line     int    `json:"line,omitempty"`
}

type Positional

type Positional interface {
	Position() Pos
}

type ProxyFactory

type ProxyFactory func(px InvocationHandler) interface{}

type Struct

type Struct struct {
	Doc         string       `json:"doc,omitempty"`
	Annotations []Annotation `json:"annotations,omitempty"`
	ImportPath  string       `json:"importPath,omitempty"`
	Name        string       `json:"name,omitempty"`
	Fields      []Field      `json:"fields,omitempty"`
	Methods     []Method     `json:"methods,omitempty"`   // Methods with a receiver
	Factories   []Method     `json:"factories,omitempty"` // factory methods, returning the struct
	Pos         Pos          `json:"pos,omitempty"`
}

func FindStruct

func FindStruct(importPath string, name string) *Struct

func (Struct) FindAnnotations

func (s Struct) FindAnnotations(name string) []Annotation

func (Struct) Position

func (s Struct) Position() Pos

type TypeDecl

type TypeDecl struct {
	ImportPath string     `json:"importPath,omitempty"`
	Identifier string     `json:"identifier,omitempty"` // slices and arrays are [], maps are map, look at the type Params for details. func is a hard one and is describes in Func
	Stars      int        `json:"stars,omitempty"`
	Var        bool       `json:"var,omitempty"`
	Params     []TypeDecl `json:"params,omitempty"` // generics: currently only slices [], arrays [x] and maps map[a]b are supported
	Length     int        `json:"length,omitempty"` // parsed array length or -1 for a slice, 0 if not applicable
	Func       *Method    `json:"func,omitempty"`   // only non-nil if identifier is "func"
}

A TypeDecl (TypeDeclaration) refers to a type definition somewhere else. A declaration may contain other type parameter for generics (currently only slices, maps and channels), which itself may be generic. Also in a parameter definition variable (ellipsis) is allowed. What makes it even more complex are length attributes for arrays and an variable amount of pointer indirection (stars).

Directories

Path Synopsis
cmd
parser contains the glue code for different parsers (e.g.
parser contains the glue code for different parsers (e.g.

Jump to

Keyboard shortcuts

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