This commit is contained in:
병준 박 2019-11-12 23:58:17 +09:00
commit e44b732fea
6 changed files with 466 additions and 0 deletions

14
const.go Normal file
View File

@ -0,0 +1,14 @@
package annotation
const (
// AnnotationTag is value
AnnotationTag = "annotation"
// AnnotationMetaTag is value
AnnotationMetaTag = "@annotation"
// AnnotationChar is value
AnnotationChar = "@"
// AnnotationStartChar is value
AnnotationStartChar = "("
// AnnotationEndChar is value
AnnotationEndChar = ")"
)

5
go.mod Normal file
View File

@ -0,0 +1,5 @@
module git.loafle.net/loafer/annotation-go
go 1.13
require git.loafle.net/loafer/util-go v0.0.0-20191112142134-9a567d18b779

2
go.sum Normal file
View File

@ -0,0 +1,2 @@
git.loafle.net/loafer/util-go v0.0.0-20191112142134-9a567d18b779 h1:TcBAz07pghDjiwGLgWrPVbovK4i8gnROGqFIwzxzarA=
git.loafle.net/loafer/util-go v0.0.0-20191112142134-9a567d18b779/go.mod h1:HGVw9FNJIc/UFDIzxmoIj5K2+D9Eadal5jjHOq0NFOU=

172
registry.go Normal file
View File

@ -0,0 +1,172 @@
package annotation
import (
"encoding/json"
"fmt"
"reflect"
"strings"
luReflect "git.loafle.net/loafer/util-go/reflect"
)
func init() {
registry = newRegistry()
}
// Definition is struct
type Definition struct {
t reflect.Type
rt reflect.Type
}
// Regist is interface
type Regist interface {
// Register is method
Register(t reflect.Type)
// Parse is method
Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error)
}
// Registry is struct
type Registry struct {
definitions map[string]*Definition
}
var registry Regist
func newRegistry() Regist {
r := &Registry{}
r.definitions = make(map[string]*Definition, 0)
return r
}
// Register is method
func Register(t reflect.Type) {
registry.Register(t)
}
// Register is method
func (r *Registry) Register(t reflect.Type) {
rt, _, _ := luReflect.GetTypeInfo(t)
f := r.getTypeAnnotationField(t)
if nil == f {
panic(fmt.Sprintf("Annotation: This type[%s] is not Annotation. use TypeAnnotation", rt.Name()))
}
name := r.parseAnnotationMeta(f.Tag)
if _, ok := r.definitions[name]; ok {
panic(fmt.Sprintf("Annotation: name[%s] of annotation exist already", name))
}
def := &Definition{
t: t,
rt: rt,
}
r.definitions[name] = def
}
// Parse is method
func Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error) {
return registry.Parse(tag)
}
// Parse is method
func (r *Registry) Parse(tag reflect.StructTag) (map[reflect.Type]Annotation, error) {
s := strings.Trim(tag.Get(AnnotationTag), " ")
if "" == s {
return nil, nil
}
annotations, err := r.splitAnnotation(s)
if nil != err {
return nil, err
}
if nil == annotations || 0 == len(annotations) {
return nil, nil
}
rKVs := make(map[reflect.Type]Annotation, 0)
for name, attributes := range annotations {
t, annotation, err := r.buildAnnotation(name, attributes)
if nil != err {
return nil, err
}
rKVs[t] = annotation
}
return rKVs, nil
}
func (r *Registry) getTypeAnnotationField(t reflect.Type) *reflect.StructField {
rt, _, _ := luReflect.GetTypeInfo(t)
if reflect.Struct != rt.Kind() {
return nil
}
for i := 0; i < rt.NumField(); i++ {
f := rt.Field(i)
if f.Anonymous {
if f.Type == TypeAnnotationType {
return &f
}
}
}
return nil
}
func (r *Registry) parseAnnotationMeta(tag reflect.StructTag) string {
return strings.Trim(tag.Get(AnnotationMetaTag), " ")
}
func (r *Registry) splitAnnotation(s string) (map[string]string, error) {
ss := make(map[string]string, 0)
ts := s
for {
as := strings.Index(ts, AnnotationChar)
if -1 == as {
break
}
aas := strings.Index(ts, AnnotationStartChar)
aae := strings.Index(ts, AnnotationEndChar)
aName := ts[as:aas]
aAttributes := ts[aas+1 : aae]
if 0 < len(aAttributes) {
ss[aName] = aAttributes
} else {
ss[aName] = ""
}
if len(ts) <= (aae + 1) {
break
}
ts = ts[aae+1:]
}
return ss, nil
}
func (r *Registry) buildAnnotation(name string, attributes string) (reflect.Type, Annotation, error) {
def, ok := r.definitions[name]
if !ok {
return nil, nil, fmt.Errorf("There is no annotation[%s]", name)
}
v := reflect.New(def.rt)
i := v.Interface().(Annotation)
if "" != attributes {
_json := fmt.Sprintf("{%s}", attributes)
if err := json.Unmarshal([]byte(_json), i); nil != err {
return nil, nil, err
}
}
return def.t, i, nil
}

247
registry_test.go Normal file
View File

@ -0,0 +1,247 @@
package annotation
import (
"reflect"
"testing"
)
func Test_newRegistry(t *testing.T) {
tests := []struct {
name string
want Regist
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := newRegistry(); !reflect.DeepEqual(got, tt.want) {
t.Errorf("newRegistry() = %v, want %v", got, tt.want)
}
})
}
}
func TestRegister(t *testing.T) {
type args struct {
t reflect.Type
}
tests := []struct {
name string
args args
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Register(tt.args.t)
})
}
}
func TestRegistry_Register(t *testing.T) {
type fields struct {
definitions map[string]*Definition
}
type args struct {
t reflect.Type
}
tests := []struct {
name string
fields fields
args args
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Registry{
definitions: tt.fields.definitions,
}
r.Register(tt.args.t)
})
}
}
func TestParse(t *testing.T) {
type args struct {
tag reflect.StructTag
}
tests := []struct {
name string
args args
want map[reflect.Type]Annotation
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
got, err := Parse(tt.args.tag)
if (err != nil) != tt.wantErr {
t.Errorf("Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Parse() = %v, want %v", got, tt.want)
}
})
}
}
func TestRegistry_Parse(t *testing.T) {
type fields struct {
definitions map[string]*Definition
}
type args struct {
tag reflect.StructTag
}
tests := []struct {
name string
fields fields
args args
want map[reflect.Type]Annotation
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Registry{
definitions: tt.fields.definitions,
}
got, err := r.Parse(tt.args.tag)
if (err != nil) != tt.wantErr {
t.Errorf("Registry.Parse() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Registry.Parse() = %v, want %v", got, tt.want)
}
})
}
}
func TestRegistry_getTypeAnnotationField(t *testing.T) {
type fields struct {
definitions map[string]*Definition
}
type args struct {
t reflect.Type
}
tests := []struct {
name string
fields fields
args args
want *reflect.StructField
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Registry{
definitions: tt.fields.definitions,
}
if got := r.getTypeAnnotationField(tt.args.t); !reflect.DeepEqual(got, tt.want) {
t.Errorf("Registry.getTypeAnnotationField() = %v, want %v", got, tt.want)
}
})
}
}
func TestRegistry_parseAnnotationMeta(t *testing.T) {
type fields struct {
definitions map[string]*Definition
}
type args struct {
tag reflect.StructTag
}
tests := []struct {
name string
fields fields
args args
want string
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Registry{
definitions: tt.fields.definitions,
}
if got := r.parseAnnotationMeta(tt.args.tag); got != tt.want {
t.Errorf("Registry.parseAnnotationMeta() = %v, want %v", got, tt.want)
}
})
}
}
func TestRegistry_splitAnnotation(t *testing.T) {
type fields struct {
definitions map[string]*Definition
}
type args struct {
s string
}
tests := []struct {
name string
fields fields
args args
want map[string]string
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Registry{
definitions: tt.fields.definitions,
}
got, err := r.splitAnnotation(tt.args.s)
if (err != nil) != tt.wantErr {
t.Errorf("Registry.splitAnnotation() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Registry.splitAnnotation() = %v, want %v", got, tt.want)
}
})
}
}
func TestRegistry_buildAnnotation(t *testing.T) {
type fields struct {
definitions map[string]*Definition
}
type args struct {
name string
attributes string
}
tests := []struct {
name string
fields fields
args args
want reflect.Type
want1 Annotation
wantErr bool
}{
// TODO: Add test cases.
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
r := &Registry{
definitions: tt.fields.definitions,
}
got, got1, err := r.buildAnnotation(tt.args.name, tt.args.attributes)
if (err != nil) != tt.wantErr {
t.Errorf("Registry.buildAnnotation() error = %v, wantErr %v", err, tt.wantErr)
return
}
if !reflect.DeepEqual(got, tt.want) {
t.Errorf("Registry.buildAnnotation() got = %v, want %v", got, tt.want)
}
if !reflect.DeepEqual(got1, tt.want1) {
t.Errorf("Registry.buildAnnotation() got1 = %v, want %v", got1, tt.want1)
}
})
}
}

26
types.go Normal file
View File

@ -0,0 +1,26 @@
package annotation
import "reflect"
// Annotation is interface
type Annotation interface {
}
// AnnotationType is type of Annotation
var AnnotationType = reflect.TypeOf((*Annotation)(nil))
// TypeAnnotation is interface
type TypeAnnotation interface {
Annotation
}
// TypeAnnotationType is type of TypeAnnotation
var TypeAnnotationType = reflect.TypeOf((*TypeAnnotation)(nil))
// MethodAnnotation is interface
type MethodAnnotation interface {
Annotation
}
// MethodAnnotationType is type of MethodAnnotation
var MethodAnnotationType = reflect.TypeOf((*MethodAnnotation)(nil))