Skip to content

Commit

Permalink
rebase with master
Browse files Browse the repository at this point in the history
  • Loading branch information
anuptalwalkar committed May 5, 2017
1 parent 19a35a6 commit 01c50a8
Show file tree
Hide file tree
Showing 6 changed files with 84 additions and 88 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Expand Up @@ -3,8 +3,9 @@

## v0.4 (unreleased)
- Add support form `map`, `slice` and `array` to dig

- Remove `Must*` funcs to greatly reduce API surface area.
- Remove `*All` funcs to reduce API surface area. Available methods on
container are `Provide`, `Resolve` and `Invoke`

## v0.3 (2 May 2017)

Expand Down
2 changes: 1 addition & 1 deletion README.md
Expand Up @@ -76,7 +76,7 @@ var (
typeslice = []int{1, 2, 3}
typearray = [2]string{"one", "two"}
)
err := c.ProvideAll(typemap, typeslice, typearray)
err := c.Provide(typemap, typeslice, typearray)

var resolveslice []int
err := c.Resolve(&resolveslice)
Expand Down
105 changes: 46 additions & 59 deletions container.go
Expand Up @@ -84,85 +84,72 @@ func (c *Container) Invoke(t interface{}) error {
return nil
}

// Provide an object in the Container
// Provide registers all the provided args in the Container
//
// The provided argument must be a function that accepts its dependencies as
// arguments and returns one or more results, which must be a pointer type, map, slice or an array.
// The function may optionally return an error as the last argument.
func (c *Container) Provide(t interface{}) error {
ctype := reflect.TypeOf(t)
switch ctype.Kind() {
case reflect.Func:
switch ctype.NumOut() {
case 0:
return errReturnCount
case 1:
objType := ctype.Out(0)
if objType.Kind() != reflect.Ptr && objType.Kind() != reflect.Interface {
return errReturnKind
func (c *Container) Provide(types ...interface{}) error {
for _, t := range types {
ctype := reflect.TypeOf(t)
switch ctype.Kind() {
case reflect.Func:
switch ctype.NumOut() {
case 0:
return errReturnCount
case 1:
objType := ctype.Out(0)
if objType.Kind() != reflect.Ptr && objType.Kind() != reflect.Interface {
return errReturnKind
}
}
if err := c.Graph.InsertConstructor(t); err != nil {
return err
}
case reflect.Slice, reflect.Array, reflect.Map, reflect.Ptr:
v := reflect.ValueOf(t)
if ctype.Elem().Kind() == reflect.Interface {
ctype = ctype.Elem()
v = v.Elem()
}
if err := c.Graph.InsertObject(v); err != nil {
return err
}
default:
return errParamType
}
return c.Graph.InsertConstructor(t)
case reflect.Slice, reflect.Array, reflect.Map, reflect.Ptr, reflect.Interface:
v := reflect.ValueOf(t)
if ctype.Elem().Kind() == reflect.Interface {
ctype = ctype.Elem()
v = v.Elem()
}
return c.Graph.InsertObject(v)
default:
return errParamType
}
return nil
}

// Resolve all of the dependencies of the provided class
//
// Provided object must be a pointer, map, slice or an array
// Any dependencies of the object will receive constructor calls, or be initialized (once)
// Constructor with return value *object will be called
func (c *Container) Resolve(obj interface{}) (err error) {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic during Resolve %v", r)
}
}()

objType := reflect.TypeOf(obj)
if objType.Kind() != reflect.Ptr {
return fmt.Errorf("can not resolve non-pointer object of type %v", objType)
}

objElemType := reflect.TypeOf(obj).Elem()
objVal := reflect.ValueOf(obj)

v, err := c.Graph.Read(objElemType)
if err != nil {
return err
}
func (c *Container) Resolve(objs ...interface{}) (err error) {
for _, obj := range objs {
defer func() {
if r := recover(); r != nil {
err = fmt.Errorf("panic during Resolve %v", r)
}
}()

// set the pointer value of the provided object to the instance pointer
objVal.Elem().Set(v)
objType := reflect.TypeOf(obj)
if objType.Kind() != reflect.Ptr {
return fmt.Errorf("can not resolve non-pointer object of type %v", objType)
}

return nil
}
objElemType := reflect.TypeOf(obj).Elem()
objVal := reflect.ValueOf(obj)

// ResolveAll the dependencies of each provided object
// Returns the first error encountered
func (c *Container) ResolveAll(objs ...interface{}) error {
for _, o := range objs {
if err := c.Resolve(o); err != nil {
v, err := c.Graph.Read(objElemType)
if err != nil {
return err
}
}
return nil
}

// ProvideAll registers all the provided args in the Container
func (c *Container) ProvideAll(types ...interface{}) error {
for _, t := range types {
if err := c.Provide(t); err != nil {
return err
}
// set the pointer value of the provided object to the instance pointer
objVal.Elem().Set(v)
}
return nil
}
22 changes: 11 additions & 11 deletions container_test.go
Expand Up @@ -164,7 +164,7 @@ func TestComplexType(t *testing.T) {
},
{
"test ctor",
func(c *Container) error { return c.ProvideAll(testslice, testmap, testarray, ctorWithMapsAndSlices) },
func(c *Container) error { return c.Provide(testslice, testmap, testarray, ctorWithMapsAndSlices) },
func(t *testing.T, c *Container) error {
err := c.Resolve(&resolveTestResult)
assert.Equal(t, resolveTestResult.testarray[0], "one")
Expand All @@ -176,7 +176,7 @@ func TestComplexType(t *testing.T) {
},
{
"test invoke",
func(c *Container) error { return c.ProvideAll(testslice, testmap, testarray) },
func(c *Container) error { return c.Provide(testslice, testmap, testarray) },
func(t *testing.T, c *Container) error {
if err := c.Invoke(ctorWithMapsAndSlices); err != nil {
return err
Expand Down Expand Up @@ -315,7 +315,7 @@ func TestConstructorErrors(t *testing.T) {
for _, tt := range tests {
t.Run(tt.desc, func(t *testing.T) {
c := New()
require.NoError(t, c.ProvideAll(tt.registers...))
require.NoError(t, c.Provide(tt.registers...))
var p1 *FlakyParent
err := c.Resolve(&p1)
if tt.wantErr != "" {
Expand All @@ -331,7 +331,7 @@ func TestInvokeSuccess(t *testing.T) {
t.Parallel()
c := New()

err := c.ProvideAll(
err := c.Provide(
NewParent1,
NewChild1,
NewGrandchild1,
Expand All @@ -351,7 +351,7 @@ func TestInvokeAndRegisterSuccess(t *testing.T) {
t.Parallel()
c := New()
child := &Child1{}
err := c.ProvideAll(
err := c.Provide(
&Parent1{
c1: child,
},
Expand All @@ -372,7 +372,7 @@ func TestInvokeAndRegisterFailure(t *testing.T) {
t.Parallel()
c := New()
child := &Child1{}
err := c.ProvideAll(
err := c.Provide(
&Parent1{
c1: child,
},
Expand Down Expand Up @@ -403,7 +403,7 @@ func TestInvokeFailureUnresolvedDependencies(t *testing.T) {
t.Parallel()
c := New()

err := c.ProvideAll(
err := c.Provide(
NewParent1,
)
assert.NoError(t, err)
Expand All @@ -415,11 +415,11 @@ func TestInvokeFailureUnresolvedDependencies(t *testing.T) {
require.Contains(t, err.Error(), "dependency of type *dig.Parent12 is not registered")
}

func TestProvideAll(t *testing.T) {
func TestProvide(t *testing.T) {
t.Parallel()
c := New()

err := c.ProvideAll(
err := c.Provide(
NewParent1,
NewChild1,
NewGrandchild1,
Expand Down Expand Up @@ -498,7 +498,7 @@ func TestResolveAll(t *testing.T) {
t.Parallel()
c := New()

err := c.ProvideAll(
err := c.Provide(
NewGrandchild1,
NewChild1,
NewParent1,
Expand All @@ -509,7 +509,7 @@ func TestResolveAll(t *testing.T) {
var p3 *Parent1
var p4 *Parent1

err = c.ResolveAll(&p1, &p2, &p3, &p4)
err = c.Resolve(&p1, &p2, &p3, &p4)
require.NoError(t, err, "Did not expect error on resolve all")
require.Equal(t, p1.name, "Parent1")
require.True(t, p1 == p2 && p2 == p3 && p3 == p4, "All pointers must be equal")
Expand Down
38 changes: 23 additions & 15 deletions doc.go
Expand Up @@ -36,6 +36,8 @@
//
// • Provide a pointer to an existing object
//
// • Provide a slice, map, array
//
// • Provide a "constructor function" that returns one pointer (or interface)
//
// Provide a Constructor
Expand Down Expand Up @@ -76,6 +78,27 @@
// // dig container is now able to provide *Type1 as a dependency
// // to other constructors that require it.
//
// Provide an Maps, slices or arrays
//
// Dig also support maps, slices and arrays as objects to
// resolve, or provided as a dependency to the constructor.
//
//
// c := dig.New()
// var (
// typemap = map[string]int{}
// typeslice = []int{1, 2, 3}
// typearray = [2]string{"one", "two"}
// )
// err := c.Provide(typemap, typeslice, typearray)
//
// var resolveslice []int
// err := c.Resolve(&resolveslice)
//
// c.Invoke(func(map map[string]int, slice []int, array [2]string) {
// // do something
// })
//
// Resolve
//
// Resolve retrieves objects from the container by building the object graph.
Expand Down Expand Up @@ -115,20 +138,5 @@
// // dig container is now able to provide *Type1 as a dependency
// // to other constructors that require it.
//
// Error Handling and Alternatives
//
// Provide and Resolve (and their ProvideAll and ResolveAll counterparts)
// return errors, and usages of
// dig should fully utilize the error checking, since
// container creation is done through reflection meaning a lot of the errors surface
// at runtime.
//
//
// There are, however, Must* alternatives of all the methods available. They
// are drawn from some of the patterns in the Go standard library and are there
// to simplify usage in critical scenarios: where not being able to resolve an
// object is not an option and panic is preferred.
//
//
//
package dig
2 changes: 1 addition & 1 deletion examples/three/three.go
Expand Up @@ -55,7 +55,7 @@ func main() {
//
// At this point no functions are called and no objects are created.
// dig is merely constructing a directional graph of dependencies.
err := c.ProvideAll(newOne, newTwo, newThree)
err := c.Provide(newOne, newTwo, newThree)
if err != nil {
panic(err)
}
Expand Down

0 comments on commit 01c50a8

Please sign in to comment.