├── .gitignore ├── LICENSE ├── README.md ├── inject.go ├── inject_test.go ├── translations └── README_zh_cn.md └── update_readme.sh /.gitignore: -------------------------------------------------------------------------------- 1 | inject 2 | inject.test 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2013 Jeremy Saenz 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # inject 2 | -- 3 | import "github.com/codegangsta/inject" 4 | 5 | Package inject provides utilities for mapping and injecting dependencies in 6 | various ways. 7 | 8 | Language Translations: 9 | * [简体中文](translations/README_zh_cn.md) 10 | 11 | ## Usage 12 | 13 | #### func InterfaceOf 14 | 15 | ```go 16 | func InterfaceOf(value interface{}) reflect.Type 17 | ``` 18 | InterfaceOf dereferences a pointer to an Interface type. It panics if value is 19 | not an pointer to an interface. 20 | 21 | #### type Applicator 22 | 23 | ```go 24 | type Applicator interface { 25 | // Maps dependencies in the Type map to each field in the struct 26 | // that is tagged with 'inject'. Returns an error if the injection 27 | // fails. 28 | Apply(interface{}) error 29 | } 30 | ``` 31 | 32 | Applicator represents an interface for mapping dependencies to a struct. 33 | 34 | #### type Injector 35 | 36 | ```go 37 | type Injector interface { 38 | Applicator 39 | Invoker 40 | TypeMapper 41 | // SetParent sets the parent of the injector. If the injector cannot find a 42 | // dependency in its Type map it will check its parent before returning an 43 | // error. 44 | SetParent(Injector) 45 | } 46 | ``` 47 | 48 | Injector represents an interface for mapping and injecting dependencies into 49 | structs and function arguments. 50 | 51 | #### func New 52 | 53 | ```go 54 | func New() Injector 55 | ``` 56 | New returns a new Injector. 57 | 58 | #### type Invoker 59 | 60 | ```go 61 | type Invoker interface { 62 | // Invoke attempts to call the interface{} provided as a function, 63 | // providing dependencies for function arguments based on Type. Returns 64 | // a slice of reflect.Value representing the returned values of the function. 65 | // Returns an error if the injection fails. 66 | Invoke(interface{}) ([]reflect.Value, error) 67 | } 68 | ``` 69 | 70 | Invoker represents an interface for calling functions via reflection. 71 | 72 | #### type TypeMapper 73 | 74 | ```go 75 | type TypeMapper interface { 76 | // Maps the interface{} value based on its immediate type from reflect.TypeOf. 77 | Map(interface{}) TypeMapper 78 | // Maps the interface{} value based on the pointer of an Interface provided. 79 | // This is really only useful for mapping a value as an interface, as interfaces 80 | // cannot at this time be referenced directly without a pointer. 81 | MapTo(interface{}, interface{}) TypeMapper 82 | // Provides a possibility to directly insert a mapping based on type and value. 83 | // This makes it possible to directly map type arguments not possible to instantiate 84 | // with reflect like unidirectional channels. 85 | Set(reflect.Type, reflect.Value) TypeMapper 86 | // Returns the Value that is mapped to the current type. Returns a zeroed Value if 87 | // the Type has not been mapped. 88 | Get(reflect.Type) reflect.Value 89 | } 90 | ``` 91 | 92 | TypeMapper represents an interface for mapping interface{} values based on type. 93 | -------------------------------------------------------------------------------- /inject.go: -------------------------------------------------------------------------------- 1 | // Package inject provides utilities for mapping and injecting dependencies in various ways. 2 | package inject 3 | 4 | import ( 5 | "fmt" 6 | "reflect" 7 | ) 8 | 9 | // Injector represents an interface for mapping and injecting dependencies into structs 10 | // and function arguments. 11 | type Injector interface { 12 | Applicator 13 | Invoker 14 | TypeMapper 15 | // SetParent sets the parent of the injector. If the injector cannot find a 16 | // dependency in its Type map it will check its parent before returning an 17 | // error. 18 | SetParent(Injector) 19 | } 20 | 21 | // Applicator represents an interface for mapping dependencies to a struct. 22 | type Applicator interface { 23 | // Maps dependencies in the Type map to each field in the struct 24 | // that is tagged with 'inject'. Returns an error if the injection 25 | // fails. 26 | Apply(interface{}) error 27 | } 28 | 29 | // Invoker represents an interface for calling functions via reflection. 30 | type Invoker interface { 31 | // Invoke attempts to call the interface{} provided as a function, 32 | // providing dependencies for function arguments based on Type. Returns 33 | // a slice of reflect.Value representing the returned values of the function. 34 | // Returns an error if the injection fails. 35 | Invoke(interface{}) ([]reflect.Value, error) 36 | } 37 | 38 | // TypeMapper represents an interface for mapping interface{} values based on type. 39 | type TypeMapper interface { 40 | // Maps the interface{} value based on its immediate type from reflect.TypeOf. 41 | Map(interface{}) TypeMapper 42 | // Maps the interface{} value based on the pointer of an Interface provided. 43 | // This is really only useful for mapping a value as an interface, as interfaces 44 | // cannot at this time be referenced directly without a pointer. 45 | MapTo(interface{}, interface{}) TypeMapper 46 | // Provides a possibility to directly insert a mapping based on type and value. 47 | // This makes it possible to directly map type arguments not possible to instantiate 48 | // with reflect like unidirectional channels. 49 | Set(reflect.Type, reflect.Value) TypeMapper 50 | // Returns the Value that is mapped to the current type. Returns a zeroed Value if 51 | // the Type has not been mapped. 52 | Get(reflect.Type) reflect.Value 53 | } 54 | 55 | type injector struct { 56 | values map[reflect.Type]reflect.Value 57 | parent Injector 58 | } 59 | 60 | // InterfaceOf dereferences a pointer to an Interface type. 61 | // It panics if value is not an pointer to an interface. 62 | func InterfaceOf(value interface{}) reflect.Type { 63 | t := reflect.TypeOf(value) 64 | 65 | for t.Kind() == reflect.Ptr { 66 | t = t.Elem() 67 | } 68 | 69 | if t.Kind() != reflect.Interface { 70 | panic("Called inject.InterfaceOf with a value that is not a pointer to an interface. (*MyInterface)(nil)") 71 | } 72 | 73 | return t 74 | } 75 | 76 | // New returns a new Injector. 77 | func New() Injector { 78 | return &injector{ 79 | values: make(map[reflect.Type]reflect.Value), 80 | } 81 | } 82 | 83 | // Invoke attempts to call the interface{} provided as a function, 84 | // providing dependencies for function arguments based on Type. 85 | // Returns a slice of reflect.Value representing the returned values of the function. 86 | // Returns an error if the injection fails. 87 | // It panics if f is not a function 88 | func (inj *injector) Invoke(f interface{}) ([]reflect.Value, error) { 89 | t := reflect.TypeOf(f) 90 | 91 | var in = make([]reflect.Value, t.NumIn()) //Panic if t is not kind of Func 92 | for i := 0; i < t.NumIn(); i++ { 93 | argType := t.In(i) 94 | val := inj.Get(argType) 95 | if !val.IsValid() { 96 | return nil, fmt.Errorf("Value not found for type %v", argType) 97 | } 98 | 99 | in[i] = val 100 | } 101 | 102 | return reflect.ValueOf(f).Call(in), nil 103 | } 104 | 105 | // Maps dependencies in the Type map to each field in the struct 106 | // that is tagged with 'inject'. 107 | // Returns an error if the injection fails. 108 | func (inj *injector) Apply(val interface{}) error { 109 | v := reflect.ValueOf(val) 110 | 111 | for v.Kind() == reflect.Ptr { 112 | v = v.Elem() 113 | } 114 | 115 | if v.Kind() != reflect.Struct { 116 | return nil // Should not panic here ? 117 | } 118 | 119 | t := v.Type() 120 | 121 | for i := 0; i < v.NumField(); i++ { 122 | f := v.Field(i) 123 | structField := t.Field(i) 124 | if f.CanSet() && (structField.Tag == "inject" || structField.Tag.Get("inject") != "") { 125 | ft := f.Type() 126 | v := inj.Get(ft) 127 | if !v.IsValid() { 128 | return fmt.Errorf("Value not found for type %v", ft) 129 | } 130 | 131 | f.Set(v) 132 | } 133 | 134 | } 135 | 136 | return nil 137 | } 138 | 139 | // Maps the concrete value of val to its dynamic type using reflect.TypeOf, 140 | // It returns the TypeMapper registered in. 141 | func (i *injector) Map(val interface{}) TypeMapper { 142 | i.values[reflect.TypeOf(val)] = reflect.ValueOf(val) 143 | return i 144 | } 145 | 146 | func (i *injector) MapTo(val interface{}, ifacePtr interface{}) TypeMapper { 147 | i.values[InterfaceOf(ifacePtr)] = reflect.ValueOf(val) 148 | return i 149 | } 150 | 151 | // Maps the given reflect.Type to the given reflect.Value and returns 152 | // the Typemapper the mapping has been registered in. 153 | func (i *injector) Set(typ reflect.Type, val reflect.Value) TypeMapper { 154 | i.values[typ] = val 155 | return i 156 | } 157 | 158 | func (i *injector) Get(t reflect.Type) reflect.Value { 159 | val := i.values[t] 160 | 161 | if val.IsValid() { 162 | return val 163 | } 164 | 165 | // no concrete types found, try to find implementors 166 | // if t is an interface 167 | if t.Kind() == reflect.Interface { 168 | for k, v := range i.values { 169 | if k.Implements(t) { 170 | val = v 171 | break 172 | } 173 | } 174 | } 175 | 176 | // Still no type found, try to look it up on the parent 177 | if !val.IsValid() && i.parent != nil { 178 | val = i.parent.Get(t) 179 | } 180 | 181 | return val 182 | 183 | } 184 | 185 | func (i *injector) SetParent(parent Injector) { 186 | i.parent = parent 187 | } 188 | -------------------------------------------------------------------------------- /inject_test.go: -------------------------------------------------------------------------------- 1 | package inject_test 2 | 3 | import ( 4 | "fmt" 5 | "github.com/codegangsta/inject" 6 | "reflect" 7 | "testing" 8 | ) 9 | 10 | type SpecialString interface { 11 | } 12 | 13 | type TestStruct struct { 14 | Dep1 string `inject:"t" json:"-"` 15 | Dep2 SpecialString `inject` 16 | Dep3 string 17 | } 18 | 19 | type Greeter struct { 20 | Name string 21 | } 22 | 23 | func (g *Greeter) String() string { 24 | return "Hello, My name is" + g.Name 25 | } 26 | 27 | /* Test Helpers */ 28 | func expect(t *testing.T, a interface{}, b interface{}) { 29 | if a != b { 30 | t.Errorf("Expected %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 31 | } 32 | } 33 | 34 | func refute(t *testing.T, a interface{}, b interface{}) { 35 | if a == b { 36 | t.Errorf("Did not expect %v (type %v) - Got %v (type %v)", b, reflect.TypeOf(b), a, reflect.TypeOf(a)) 37 | } 38 | } 39 | 40 | func Test_InjectorInvoke(t *testing.T) { 41 | injector := inject.New() 42 | expect(t, injector == nil, false) 43 | 44 | dep := "some dependency" 45 | injector.Map(dep) 46 | dep2 := "another dep" 47 | injector.MapTo(dep2, (*SpecialString)(nil)) 48 | dep3 := make(chan *SpecialString) 49 | dep4 := make(chan *SpecialString) 50 | typRecv := reflect.ChanOf(reflect.RecvDir, reflect.TypeOf(dep3).Elem()) 51 | typSend := reflect.ChanOf(reflect.SendDir, reflect.TypeOf(dep4).Elem()) 52 | injector.Set(typRecv, reflect.ValueOf(dep3)) 53 | injector.Set(typSend, reflect.ValueOf(dep4)) 54 | 55 | _, err := injector.Invoke(func(d1 string, d2 SpecialString, d3 <-chan *SpecialString, d4 chan<- *SpecialString) { 56 | expect(t, d1, dep) 57 | expect(t, d2, dep2) 58 | expect(t, reflect.TypeOf(d3).Elem(), reflect.TypeOf(dep3).Elem()) 59 | expect(t, reflect.TypeOf(d4).Elem(), reflect.TypeOf(dep4).Elem()) 60 | expect(t, reflect.TypeOf(d3).ChanDir(), reflect.RecvDir) 61 | expect(t, reflect.TypeOf(d4).ChanDir(), reflect.SendDir) 62 | }) 63 | 64 | expect(t, err, nil) 65 | } 66 | 67 | func Test_InjectorInvokeReturnValues(t *testing.T) { 68 | injector := inject.New() 69 | expect(t, injector == nil, false) 70 | 71 | dep := "some dependency" 72 | injector.Map(dep) 73 | dep2 := "another dep" 74 | injector.MapTo(dep2, (*SpecialString)(nil)) 75 | 76 | result, err := injector.Invoke(func(d1 string, d2 SpecialString) string { 77 | expect(t, d1, dep) 78 | expect(t, d2, dep2) 79 | return "Hello world" 80 | }) 81 | 82 | expect(t, result[0].String(), "Hello world") 83 | expect(t, err, nil) 84 | } 85 | 86 | func Test_InjectorApply(t *testing.T) { 87 | injector := inject.New() 88 | 89 | injector.Map("a dep").MapTo("another dep", (*SpecialString)(nil)) 90 | 91 | s := TestStruct{} 92 | err := injector.Apply(&s) 93 | expect(t, err, nil) 94 | 95 | expect(t, s.Dep1, "a dep") 96 | expect(t, s.Dep2, "another dep") 97 | expect(t, s.Dep3, "") 98 | } 99 | 100 | func Test_InterfaceOf(t *testing.T) { 101 | iType := inject.InterfaceOf((*SpecialString)(nil)) 102 | expect(t, iType.Kind(), reflect.Interface) 103 | 104 | iType = inject.InterfaceOf((**SpecialString)(nil)) 105 | expect(t, iType.Kind(), reflect.Interface) 106 | 107 | // Expecting nil 108 | defer func() { 109 | rec := recover() 110 | refute(t, rec, nil) 111 | }() 112 | iType = inject.InterfaceOf((*testing.T)(nil)) 113 | } 114 | 115 | func Test_InjectorSet(t *testing.T) { 116 | injector := inject.New() 117 | typ := reflect.TypeOf("string") 118 | typSend := reflect.ChanOf(reflect.SendDir, typ) 119 | typRecv := reflect.ChanOf(reflect.RecvDir, typ) 120 | 121 | // instantiating unidirectional channels is not possible using reflect 122 | // http://golang.org/src/pkg/reflect/value.go?s=60463:60504#L2064 123 | chanRecv := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0) 124 | chanSend := reflect.MakeChan(reflect.ChanOf(reflect.BothDir, typ), 0) 125 | 126 | injector.Set(typSend, chanSend) 127 | injector.Set(typRecv, chanRecv) 128 | 129 | expect(t, injector.Get(typSend).IsValid(), true) 130 | expect(t, injector.Get(typRecv).IsValid(), true) 131 | expect(t, injector.Get(chanSend.Type()).IsValid(), false) 132 | } 133 | 134 | func Test_InjectorGet(t *testing.T) { 135 | injector := inject.New() 136 | 137 | injector.Map("some dependency") 138 | 139 | expect(t, injector.Get(reflect.TypeOf("string")).IsValid(), true) 140 | expect(t, injector.Get(reflect.TypeOf(11)).IsValid(), false) 141 | } 142 | 143 | func Test_InjectorSetParent(t *testing.T) { 144 | injector := inject.New() 145 | injector.MapTo("another dep", (*SpecialString)(nil)) 146 | 147 | injector2 := inject.New() 148 | injector2.SetParent(injector) 149 | 150 | expect(t, injector2.Get(inject.InterfaceOf((*SpecialString)(nil))).IsValid(), true) 151 | } 152 | 153 | func TestInjectImplementors(t *testing.T) { 154 | injector := inject.New() 155 | g := &Greeter{"Jeremy"} 156 | injector.Map(g) 157 | 158 | expect(t, injector.Get(inject.InterfaceOf((*fmt.Stringer)(nil))).IsValid(), true) 159 | } 160 | -------------------------------------------------------------------------------- /translations/README_zh_cn.md: -------------------------------------------------------------------------------- 1 | # inject 2 | -- 3 | import "github.com/codegangsta/inject" 4 | 5 | inject包提供了多种对实体的映射和依赖注入方式。 6 | 7 | ## 用法 8 | 9 | #### func InterfaceOf 10 | 11 | ```go 12 | func InterfaceOf(value interface{}) reflect.Type 13 | ``` 14 | 函数InterfaceOf返回指向接口类型的指针。如果传入的value值不是指向接口的指针,将抛出一个panic异常。 15 | 16 | #### type Applicator 17 | 18 | ```go 19 | type Applicator interface { 20 | // 在Type map中维持对结构体中每个域的引用并用'inject'来标记 21 | // 如果注入失败将会返回一个error. 22 | Apply(interface{}) error 23 | } 24 | ``` 25 | 26 | Applicator接口表示到结构体的依赖映射关系。 27 | 28 | #### type Injector 29 | 30 | ```go 31 | type Injector interface { 32 | Applicator 33 | Invoker 34 | TypeMapper 35 | // SetParent用来设置父injector. 如果在当前injector的Type map中找不到依赖, 36 | // 将会继续从它的父injector中找,直到返回error. 37 | SetParent(Injector) 38 | } 39 | ``` 40 | 41 | Injector接口表示对结构体、函数参数的映射和依赖注入。 42 | 43 | #### func New 44 | 45 | ```go 46 | func New() Injector 47 | ``` 48 | New创建并返回一个Injector. 49 | 50 | #### type Invoker 51 | 52 | ```go 53 | type Invoker interface { 54 | // Invoke尝试将interface{}作为一个函数来调用,并基于Type为函数提供参数。 55 | // 它将返回reflect.Value的切片,其中存放原函数的返回值。 56 | // 如果注入失败则返回error. 57 | Invoke(interface{}) ([]reflect.Value, error) 58 | } 59 | ``` 60 | 61 | Invoker接口表示通过反射进行函数调用。 62 | 63 | #### type TypeMapper 64 | 65 | ```go 66 | type TypeMapper interface { 67 | // 基于调用reflect.TypeOf得到的类型映射interface{}的值。 68 | Map(interface{}) TypeMapper 69 | // 基于提供的接口的指针映射interface{}的值。 70 | // 该函数仅用来将一个值映射为接口,因为接口无法不通过指针而直接引用到。 71 | MapTo(interface{}, interface{}) TypeMapper 72 | // 为直接插入基于类型和值的map提供一种可能性。 73 | // 它使得这一类直接映射成为可能:无法通过反射直接实例化的类型参数,如单向管道。 74 | Set(reflect.Type, reflect.Value) TypeMapper 75 | // 返回映射到当前类型的Value. 如果Type没被映射,将返回对应的零值。 76 | Get(reflect.Type) reflect.Value 77 | } 78 | ``` 79 | 80 | TypeMapper接口用来表示基于类型到接口值的映射。 81 | 82 | 83 | ## 译者 84 | 85 | 张强 (qqbunny@yeah.net) -------------------------------------------------------------------------------- /update_readme.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | go get github.com/robertkrimen/godocdown/godocdown 3 | godocdown > README.md 4 | --------------------------------------------------------------------------------