From e44b732fea76df0bf0bbc6e8ac8f0036e640e763 Mon Sep 17 00:00:00 2001 From: Richard Park Date: Tue, 12 Nov 2019 23:58:17 +0900 Subject: [PATCH] ing --- const.go | 14 +++ go.mod | 5 + go.sum | 2 + registry.go | 172 +++++++++++++++++++++++++++++++++ registry_test.go | 247 +++++++++++++++++++++++++++++++++++++++++++++++ types.go | 26 +++++ 6 files changed, 466 insertions(+) create mode 100644 const.go create mode 100644 go.mod create mode 100644 go.sum create mode 100644 registry.go create mode 100644 registry_test.go create mode 100644 types.go diff --git a/const.go b/const.go new file mode 100644 index 0000000..f9a1eca --- /dev/null +++ b/const.go @@ -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 = ")" +) diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..1239386 --- /dev/null +++ b/go.mod @@ -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 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..ee3cf07 --- /dev/null +++ b/go.sum @@ -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= diff --git a/registry.go b/registry.go new file mode 100644 index 0000000..c88458e --- /dev/null +++ b/registry.go @@ -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 +} diff --git a/registry_test.go b/registry_test.go new file mode 100644 index 0000000..26824c8 --- /dev/null +++ b/registry_test.go @@ -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) + } + }) + } +} diff --git a/types.go b/types.go new file mode 100644 index 0000000..c2dad7d --- /dev/null +++ b/types.go @@ -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))