digpro

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Nov 20, 2021 License: MIT Imports: 10 Imported by: 0

README

⚒ digpro

MIT GoDoc GitHub release Build Status Coverage Status Go Report Card

English | 简体中文

Introduction

digpro is a enhanced uber-go/dig, inherit all feature of uber-go/dig and add the following features:

  • Progressive use digpro
  • Value Provider
  • Property dependency injection
  • Extract object from the container
  • Override a registered Provider
  • Add global container
  • Export some function
    • QuickPanic function
    • Visualize function
    • Unwrap function

Installation

go get github.com/rectcircle/digpro

Document

https://pkg.go.dev/github.com/rectcircle/digpro

Guide

dig Introduction

uber-go/dig is a lightweight dependency injection library that supported by uber for go language. The library driven by reflection and has the following features:

  • Dependency injection based on constructor
  • Object and interface binding
  • Named objects and group objects
  • Parameter object, result object and optional dependencies

More see: go docs

Why need digpro

dig provides a very lightweight runtime dependency injection, and the code is high-quality and stable. But it lacks the following more useful features:

  • Property dependency injection, by simply providing a structure type, the dependency injection library can construct a structure object and inject the dependency into that object and into the container. This feature can save dependency injection users a lot of time and avoid writing a lot of sample constructors.
  • Value Provider, which can take a constructed object provided by the user and put it directly into a container.
  • Extract Object, which extracts the constructed object from the container for use.
Progressive use
Lower level API

Containers constructed with c := dig.New() can be used directly. use it like

c := dig.New()
c.Provide(digpro.Supply(...))
c.Provide(digpro.Struct(...))
digpro.Extract(c, ...)

This approach introduces all the capabilities provided by digpro at zero cost to projects already using dig. However, due to a limitation of the principle, this method reports errors without the correct code file and line number information, and only displays the following information

... missing dependencies for function "reflect".makeFuncStub (/usr/local/Cellar/go/1.17.1/libexec/src/reflect/asm_amd64.s:30) ...

Therefore, if starting from scratch with digpro it is recommended to use the High level API or the global container.

High level API

Construct a wrapper object for dig.Container (digpro.ContainerWrapper) with c := digpro.New(). use it like

c := digpro.New()
c.Supply(...)
c.Struct(...)
c.Extract(...)

This approach is much more elegant and simple than the low-level API.

Global container

By importing the digglobal package, you can use the global digpro.ContainerWrapper object, which can be used if you are looking for the ultimate efficiency

import "github.com/rectcircle/digpro/digglobal"

// dao/module.go
func init() {
  digglobal.Struct(new(XxxDAO))
  digglobal.Struct(new(XxxDAO))
  digglobal.Struct(new(XxxDAO))
}

// service/module.go
func init() {
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
}

// controller/module.go
func init() {
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
  digglobal.Struct(new(XxxService))
}

// main.go
func main() {
  digglobal.Supply(Config{})
  digglobal.Supply(DB{})
  digglobal.Provide(NewServer)
  server, err := digglobal.Extract(new(Server))
  digpro.QuickPanic(err)
  server.Run()
}

Note: For global containers, functions of type Provider (Provide, Struct, Supply) will no longer return an error, directly Panic

Value Provider

It can take a constructed object provided by the user and put it directly into a container.

func Supply(value interface{}) interface{}
func (c *ContainerWrapper) Supply(value interface{}, opts ...dig.ProvideOption) error
  • The value parameter supports any non-error type
  • If value is untyped nil, then the object in the container with type = interface{} and value = nil

Example

// High Level API
c.Supply("a")
// Lower Level API
c.Provide(digpro.Supply("a"))

Equals to

c.Provide(func() string {return "a"})
Property dependency injection

By simply providing a structure type, the dependency injection library can construct a structure object and inject the dependency into that object and into the container.

func Struct(structOrStructPtr interface{}) interface{}
func (c *ContainerWrapper) Struct(structOrStructPtr interface{}, opts ...dig.ProvideOption) error
  • structOrStructPtr must be of struct type, or struct pointer type

Example

type Foo struct {
	A       string
	B       int
	C       int `name:"c"`
	private bool
	ignore  int `digpro:"ignore"`
}
// High Level API
c.Struct(Foo{
  ignore: 3,
})
// Lower Level API
c.Provide(digpro.Struct(Foo{
  ignore: 3,
}))

Equals to

c.Provide(func(in struct {
  A       string
  B       int
  C       int `name:"c"`
  Private bool
}) Foo {
  return Foo{
    A:       in.A,
    B:       in.B,
    C:       in.C,
    private: in.Private,
    ignore:  3,
  }
}),
Extract object

Extracts the object constructed inside the container for use.

func MakeExtractFunc(ptr interface{}, opts ...ExtractOption) interface{}
func Extract(c *dig.Container, typ interface{}, opts ...ExtractOption) (interface{}, error)
func (c *ContainerWrapper) Extract(typ interface{}, opts ...ExtractOption) (interface{}, error)

For two Extract functions, if want to extract a non-interface, reflect.TypeOf(result) == reflect.TypeOf(typ)

func(int) -> int    // func(int(0)) -> int
func(*int) -> *int  // func(new(int)) -> *int

For two Extract functions, if want to extract a interface, reflect.TypeOf(result) == reflect.TypeOf(typ).Elem()

type A interface { ... }
func(A) -> error   // func(A(nil)) -> error
func(*A) -> A      // func(new(A)) -> A
func(**A) -> *A    // func(new(*A)) -> *A

Example

// High Level API
i, err := c.Extract(int(0)) 
// Lower Level API (1)
i, err := digpro.Extract(c, int(0))
// Lower Level API (2)
var i int
err := digpro.Invoke(digpro.MakeExtractFunc(&i))

Equals to

var i interface{}
err := c.Invoke(func(_i int){
  i = _i
})
Override

⚠ Only support High Level API

When using dependency injection, the Provider is registered according to the configuration of the production environment, and the service is started in the main function. When starting a service in another environment (e.g. testing), it is generally only necessary to replace a small number of the production environment's Providers with proprietary ones (e.g. db mock).

To more elegantly support scenarios such as the above, add the Override capability.

Example

c := digpro.New()
_ = c.Supply(1) // please handle error in production
_ = c.Supply(1, digpro.Override())
// _ = c.Supply("a", digpro.Override())  // has error
i, _ := c.Extract(0)
fmt.Println(i.(int) == 1)
// Output: true

To expose the problem in advance, using digpro.Override() will return the error no provider to override was found if the same Provider does not exist in the container

Circular reference

⚠ Only support High Level API Struct method

In some cases, there may be circular references between several structs. This is manifested in the Go language in the following two cases and in a mixture of these two cases.

  • Pointer type: two structures contain pointers to each other
  • Interface type: two structures implement two interfaces, and these two structures contain references to each other's implemented interfaces

To address the two circular reference scenarios, digpro offers to add an option digpro.ResolveCyclic() to the *digpro.WrapContainer.Struct method. When a circular reference occurs, the Simply add the digpro.ResolveCyclic() option to the Struct method call of any structure that reference cycle, and the circular reference will be automatically resolved.

Example

package digpro_test

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

type D1 struct {
	D2    *D2
	Value int
}

func (d1 *D1) String() string {
	return fmt.Sprintf("D1: {D2: {D1: ..., Value: '%s'}, Value: %d}", d1.D2.Value, d1.Value)
}

type D2 struct {
	D1    *D1
	Value string
}

func (d2 *D2) String() string {
	return fmt.Sprintf("D2: {D1: {D2: ..., Value: %d}, Value: '%s'}", d2.D1.Value, d2.Value)
}

func resolvePointerTypeCyclicDependency() {
	c := digpro.New()
	_ = c.Supply(1) // please handle error in production
	_ = c.Supply("a")
	_ = c.Struct(new(D1), digpro.ResolveCyclic()) // enable resolve cyclic dependency
	_ = c.Struct(new(D2))
	d1, _ := c.Extract(new(D1))
	d2, _ := c.Extract(new(D2))
	fmt.Println(d1.(*D1).String())
	fmt.Println(d2.(*D2).String())
}

type I1 interface{ String1() string }
type I2 interface{ String2() string }

type DI1 struct {
	I2    I2
	Value int
}

func (d1 *DI1) String1() string {
	return fmt.Sprintf("DI1: {I2: {I1: ..., Value: '%s'}, Value: %d}", d1.I2.(*DI2).Value, d1.Value)
}

type DI2 struct {
	I1    I1
	Value string
}

func (d2 *DI2) String2() string {
	return fmt.Sprintf("DI2: {I1: {I2: ..., Value: %d}, Value: '%s'}", d2.I1.(*DI1).Value, d2.Value)
}

func resolveInterfaceTypeCyclicDependency() {
	c := digpro.New()
	_ = c.Supply(1) // please handle error in production
	_ = c.Supply("a")
	_ = c.Struct(new(DI1), dig.As(new(I1)))
	_ = c.Struct(new(DI2), dig.As(new(I2)), digpro.ResolveCyclic()) // enable resolve cyclic dependency
	i1, _ := c.Extract(new(I1))
	i2, _ := c.Extract(new(I2))
	fmt.Println(i1.(I1).String1())
	fmt.Println(i2.(I2).String2())
}

func ExampleResolveCyclic() {
	resolvePointerTypeCyclicDependency()
	resolveInterfaceTypeCyclicDependency()
	// Output:
	// D1: {D2: {D1: ..., Value: 'a'}, Value: 1}
	// D2: {D1: {D2: ..., Value: 1}, Value: 'a'}
	// DI1: {I2: {I1: ..., Value: 'a'}, Value: 1}
	// DI2: {I1: {I2: ..., Value: 1}, Value: 'a'}
}
Others
QuickPanic
func QuickPanic(errs ...error)

If any of the errs is not nil, it will panic directly

Example

c := digpro.New()
digpro.QuickPanic(
	c.Supply(1),
	c.Supply(1),
)
// panic: [1]: cannot provide function "xxx".Xxx (xxx.go:n): cannot provide int from [0]: already provided by "xxx".Xxx (xxx.go:m)
Visualize
func (c *ContainerWrapper) Visualize(w io.Writer, opts ...dig.VisualizeOption) error

Write dot graph to io.Writer.

Unwrap
func (c *ContainerWrapper) Unwrap() *dig.Container

From *digpro.ContainerWrapper obtain *dig.Container

Documentation

Overview

Example (HighLevelAPI)
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	// High Level API has better error output

	type Foo struct {
		A       string
		B       int
		C       int  `name:"c"`
		private bool //lint:ignore U1000 for test
		ignore  int  `digpro:"ignore"`
	}
	// new a *dig.Container wrapper - *digpro.ContainerWrapper
	c := digpro.New()
	// provide some constructor
	digpro.QuickPanic(
		// register object
		c.Supply("a"),
		c.Supply(1),
		c.Supply(2, dig.Name("c")),
		c.Supply(true),
		c.Supply("aaa", digpro.Override()), // Override "a" by "aaa"
		// register a struct
		c.Struct(Foo{
			ignore: 3,
		}),
	)
	// extract object from container
	foo, err := c.Extract(Foo{})
	if err != nil {
		digpro.QuickPanic(err)
	}
	fmt.Printf("%#v", foo)
}
Output:

digpro_test.Foo{A:"aaa", B:1, C:2, private:true, ignore:3}
Example (LowerLevelAPI)
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	// Lower Level API can be used quickly, but the error is not friendly enough, such as:
	//   ... missing dependencies for function "reflect".makeFuncStub (/usr/local/Cellar/go/1.17.1/libexec/src/reflect/asm_amd64.s:30) ...

	type Foo struct {
		A       string
		B       int
		C       int  `name:"c"`
		private bool //lint:ignore U1000 for test
		ignore  int  `digpro:"ignore"`
	}
	// new a *dig.Container
	c := dig.New()
	// provide some constructor
	digpro.QuickPanic(
		// register object
		c.Provide(digpro.Supply("a")),
		c.Provide(digpro.Supply(1)),
		c.Provide(digpro.Supply(true)),
		c.Provide(digpro.Supply(2), dig.Name("c")),
		// register a struct
		c.Provide(digpro.Struct(Foo{
			ignore: 3,
		})),
	)
	// extract object from container
	foo, err := digpro.Extract(c, Foo{})
	if err != nil {
		digpro.QuickPanic(err)
	}
	fmt.Printf("%#v", foo)
}
Output:

digpro_test.Foo{A:"a", B:1, C:2, private:true, ignore:3}

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

func Extract

func Extract(c *dig.Container, typ interface{}, opts ...ExtractOption) (interface{}, error)

Extract a value from dig.Container by type of value.

if want to extract a non-interface, reflect.TypeOf(result) == reflect.TypeOf(typ). look like

func(int) -> int    // func(int(0)) -> int
func(*int) -> *int  // func(new(int)) -> *int

if want to extract a interface, reflect.TypeOf(result) == reflect.TypeOf(typ).Elem(). look like

type A interface { ... }
func(A) -> error   // func(A(nil)) -> error
func(*A) -> A      // func(new(A)) -> A
func(**A) -> *A    // func(new(*A)) -> *A

for example

c := dig.New()
_ = c.Provide(func() int {return 1})  // please handle error in production
i, _ := digpro.Extract(c, int(0))
fmt.Println(i.(int) == 1)
// Output: true
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	c := dig.New()
	_ = c.Provide(func() int { return 1 }) // please handle error in production
	i, _ := digpro.Extract(c, int(0))
	fmt.Println(i.(int) == 1)
}
Output:

true

func MakeExtractFunc added in v1.1.0

func MakeExtractFunc(ptr interface{}, opts ...ExtractOption) interface{}

MakeExtractFunc make Invoke function to extract a value and assign to *ptr from dig.Container, for example

c := dig.New()
_ = c.Provide(func() int { return 1 }) // please handle error in production
i := new(int)
_ = c.Invoke(digpro.MakeExtractFunc(i))
fmt.Println(*i == 1)
// Output: true
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	c := dig.New()
	_ = c.Provide(func() int { return 1 }) // please handle error in production
	i := new(int)
	_ = c.Invoke(digpro.MakeExtractFunc(i))
	fmt.Println(*i == 1)
}
Output:

true

func Override added in v1.1.0

func Override() dig.ProvideOption

Override a registered provider and only support digpro high level api (support *digpro.ContainerWrapper and digglobal). if Container not exist provider, the option will return error: no provider to override was found. for example

c := digpro.New()
_ = c.Supply(1) // please handle error in production
_ = c.Supply(1, digpro.Override())
// _ = c.Supply("a", digpro.Override())  // has error
i, _ := c.Extract(0)
fmt.Println(i.(int) == 1)
// Output: true
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
)

func main() {
	c := digpro.New()
	_ = c.Supply(1) // please handle error in production
	_ = c.Supply(1, digpro.Override())
	// _ = c.Supply("a", digpro.Override())  // has error
	i, _ := c.Extract(0)
	fmt.Println(i.(int) == 1)
}
Output:

true

func QuickPanic

func QuickPanic(errs ...error)

QuickPanic if anyone of errs is not nil, will panic. for example

c := digpro.New()
digpro.QuickPanic(
	c.Supply(1),
	c.Supply(1),
)
// panic: [1]: cannot provide function "xxx".Xxx (xxx.go:n): cannot provide int from [0]: already provided by "xxx".Xxx (xxx.go:m)

func ResolveCyclic added in v1.2.0

func ResolveCyclic() dig.ProvideOption

ResolveCyclic to resolve *digpro.ContainerWrapper.Struct cyclic dependency. The option only support *digpro.ContainerWrapper.Struct and *digglobal.Struct functions.

for example

type D1 struct {
	D2    *D2
	Value int
}

func (d1 *D1) String() string {
	return fmt.Sprintf("D1: {D2: {D1: ..., Value: '%s'}, Value: %d}", d1.D2.Value, d1.Value)
}

type D2 struct {
	D1    *D1
	Value string
}

func (d2 *D2) String() string {
	return fmt.Sprintf("D2: {D1: {D2: ..., Value: %d}, Value: '%s'}", d2.D1.Value, d2.Value)
}

c := digpro.New()
_ = c.Supply(1) // please handle error in production
_ = c.Supply("a")
_ = c.Struct(new(D1), digpro.ResolveCyclic()) // enable resolve cyclic dependency
_ = c.Struct(new(D2))
d1, _ := c.Extract(new(D1))
d2, _ := c.Extract(new(D2))
fmt.Println(d1.(*D1).String())
fmt.Println(d2.(*D2).String())
// Output:
// D1: {D2: {D1: ..., Value: 'a'}, Value: 1}
// D2: {D1: {D2: ..., Value: 1}, Value: 'a'}
// Output: true
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

type D1 struct {
	D2    *D2
	Value int
}

func (d1 *D1) String() string {
	return fmt.Sprintf("D1: {D2: {D1: ..., Value: '%s'}, Value: %d}", d1.D2.Value, d1.Value)
}

type D2 struct {
	D1    *D1
	Value string
}

func (d2 *D2) String() string {
	return fmt.Sprintf("D2: {D1: {D2: ..., Value: %d}, Value: '%s'}", d2.D1.Value, d2.Value)
}

func resolvePointerTypeCyclicDependency() {
	c := digpro.New()
	_ = c.Supply(1) // please handle error in production
	_ = c.Supply("a")
	_ = c.Struct(new(D1), digpro.ResolveCyclic()) // enable resolve cyclic dependency
	_ = c.Struct(new(D2))
	d1, _ := c.Extract(new(D1))
	d2, _ := c.Extract(new(D2))
	fmt.Println(d1.(*D1).String())
	fmt.Println(d2.(*D2).String())
}

type I1 interface{ String1() string }
type I2 interface{ String2() string }

type DI1 struct {
	I2    I2
	Value int
}

func (d1 *DI1) String1() string {
	return fmt.Sprintf("DI1: {I2: {I1: ..., Value: '%s'}, Value: %d}", d1.I2.(*DI2).Value, d1.Value)
}

type DI2 struct {
	I1    I1
	Value string
}

func (d2 *DI2) String2() string {
	return fmt.Sprintf("DI2: {I1: {I2: ..., Value: %d}, Value: '%s'}", d2.I1.(*DI1).Value, d2.Value)
}

func resolveInterfaceTypeCyclicDependency() {
	c := digpro.New()
	_ = c.Supply(1) // please handle error in production
	_ = c.Supply("a")
	_ = c.Struct(new(DI1), dig.As(new(I1)))
	_ = c.Struct(new(DI2), dig.As(new(I2)), digpro.ResolveCyclic()) // enable resolve cyclic dependency
	i1, _ := c.Extract(new(I1))
	i2, _ := c.Extract(new(I2))
	fmt.Println(i1.(I1).String1())
	fmt.Println(i2.(I2).String2())
}

func main() {
	resolvePointerTypeCyclicDependency()
	resolveInterfaceTypeCyclicDependency()
}
Output:

D1: {D2: {D1: ..., Value: 'a'}, Value: 1}
D2: {D1: {D2: ..., Value: 1}, Value: 'a'}
DI1: {I2: {I1: ..., Value: 'a'}, Value: 1}
DI2: {I1: {I2: ..., Value: 1}, Value: 'a'}

func Struct

func Struct(structOrStructPtr interface{}) interface{}

Struct make a struct constructor.

support all dig tags and `digpro:"ignore"`

struct {
	A string   `name:"a"`
	B []string `group:"b"`
	C bool     `optional:"true"`
	D string   `digpro:"ignore"`  // ignore this field
}

for example

type Foo struct {
	A       string
	B       int
	C       int `name:"c"`
	private bool
	ignore  int `digpro:"ignore"`
}
// new a *dig.Container
c := dig.New()
// provide some constructor
digpro.QuickPanic(
	// register object
	c.Provide(digpro.Supply("a")),
	c.Provide(digpro.Supply(1)),
	c.Provide(digpro.Supply(true)),
	c.Provide(digpro.Supply(2), dig.Name("c")),
	// register a struct
	c.Provide(digpro.Struct(Foo{
		ignore: 3,
	})),
	// equals to
	// c.Provide(func(in struct {
	// 	A       string
	// 	B       int
	// 	C       int `name:"c"`
	// 	Private bool
	// }) Foo {
	// 	return Foo{
	// 		A:       in.A,
	// 		B:       in.B,
	// 		C:       in.C,
	// 		private: in.Private,
	// 		ignore:  3,
	// 	}
	// }),
)
// extract object from container
foo, err := digpro.Extract(c, Foo{})
if err != nil {
	digpro.QuickPanic(err)
}
fmt.Printf("%#v", foo)
// Output: digpro_test.Foo{A:"a", B:1, C:2, private:true, ignore:3}
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	type Foo struct {
		A       string
		B       int
		C       int  `name:"c"`
		private bool //lint:ignore U1000 for test
		ignore  int  `digpro:"ignore"`
	}
	// new a *dig.Container
	c := dig.New()
	// provide some constructor
	digpro.QuickPanic(
		// register object
		c.Provide(digpro.Supply("a")),
		c.Provide(digpro.Supply(1)),
		c.Provide(digpro.Supply(true)),
		c.Provide(digpro.Supply(2), dig.Name("c")),
		// register a struct
		c.Provide(digpro.Struct(Foo{
			ignore: 3,
		})),
		// equals to
		// c.Provide(func(in struct {
		// 	A       string
		// 	B       int
		// 	C       int `name:"c"`
		// 	Private bool
		// }) Foo {
		// 	return Foo{
		// 		A:       in.A,
		// 		B:       in.B,
		// 		C:       in.C,
		// 		private: in.Private,
		// 		ignore:  3,
		// 	}
		// }),
	)
	// extract object from container
	foo, err := digpro.Extract(c, Foo{})
	if err != nil {
		digpro.QuickPanic(err)
	}
	fmt.Printf("%#v", foo)
}
Output:

digpro_test.Foo{A:"a", B:1, C:2, private:true, ignore:3}

func Supply

func Supply(value interface{}) interface{}

Supply a value into container. for example

c := dig.New()
digpro.QuickPanic(
	// register object
	c.Provide(digpro.Supply("a")),
	// equals to
	// c.Provide(func() string {return "a"}),
)
foo, err := digpro.Extract(c, string(""))
if err != nil {
	digpro.QuickPanic(err)
}
fmt.Println(foo)
// Output: a
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	c := dig.New()
	digpro.QuickPanic(
		// register object
		c.Provide(digpro.Supply("a")),
		// equals to
		// c.Provide(func() string {return "a"}),
	)
	foo, err := digpro.Extract(c, string(""))
	if err != nil {
		digpro.QuickPanic(err)
	}
	fmt.Println(foo)
}
Output:

a

Types

type ContainerWrapper

type ContainerWrapper struct {
	dig.Container
	// contains filtered or unexported fields
}

ContainerWrapper is a dig.Container wrapper, for add some method

func New

func New(opts ...dig.Option) *ContainerWrapper

New constructs a dig.Container wrapper and export some metholds.

For example.

c = digpro.New
// dig.Container methold
c.Provide(...)
c.Invoke(...)
// digpro exported methold
c.Value(...)
c.Struct(...)

func (*ContainerWrapper) Extract

func (c *ContainerWrapper) Extract(typ interface{}, opts ...ExtractOption) (interface{}, error)

Extract a value from dig.Container by type of value.

if want to extract a non-interface, reflect.TypeOf(result) == reflect.TypeOf(typ). look like

func(int) -> int    // func(int(0)) -> int
func(*int) -> *int  // func(new(int)) -> *int

if want to extract a interface, reflect.TypeOf(result) == reflect.TypeOf(typ).Elem(). look like

type A interface { ... }
func(A) -> error   // func(A(nil)) -> error
func(*A) -> A      // func(new(A)) -> A
func(**A) -> *A    // func(new(*A)) -> *A

for example

c := digpro.New()
_ = c.Supply(1)  // please handle error in production
i, _ := c.Extract(int(0))
fmt.Println(i.(int) == 1)
// Output: true
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
)

func main() {
	c := digpro.New()
	_ = c.Supply(1) // please handle error in production
	i, _ := c.Extract(int(0))
	fmt.Println(i.(int) == 1)
}
Output:

true

func (*ContainerWrapper) Invoke added in v1.2.0

func (c *ContainerWrapper) Invoke(function interface{}, opts ...dig.InvokeOption) error

func (*ContainerWrapper) Provide added in v1.1.0

func (c *ContainerWrapper) Provide(constructor interface{}, opts ...dig.ProvideOption) error

Provide teaches the container how to build values of one or more types and expresses their dependencies. more see: https://pkg.go.dev/go.uber.org/dig#Container.Provide.

digpro.ContainerWrapper.Provide() support digpro.Override() options, but dig.Container.Provide() not support

func (*ContainerWrapper) Struct

func (c *ContainerWrapper) Struct(structOrStructPtr interface{}, opts ...dig.ProvideOption) error

Struct make a struct constructor.

support all dig tags and `digpro:"ignore"`

struct {
	A string   `name:"a"`
	B []string `group:"b"`
	C bool     `optional:"true"`
	D string   `digpro:"ignore"`  // ignore this field
}

for example

type Foo struct {
	A       string
	B       int
	C       int `name:"c"`
	private bool
	ignore  int `digpro:"ignore"`
}
// new a *dig.Container
c := digpro.New()
// provide some constructor
digpro.QuickPanic(
	// register object
	c.Supply("a"),
	c.Supply(1),
	c.Supply(true),
	c.Supply(2, dig.Name("c")),
	// register a struct
	c.Struct(Foo{
		ignore: 3,
	}),
	// equals to
	// c.Provide(func(in struct {
	// 	A       string
	// 	B       int
	// 	C       int `name:"c"`
	// 	Private bool
	// }) Foo {
	// 	return Foo{
	// 		A:       in.A,
	// 		B:       in.B,
	// 		C:       in.C,
	// 		private: in.Private,
	// 		ignore:  3,
	// 	}
	// }),
)
// extract object from container
foo, err := c.Extract(Foo{})
if err != nil {
	digpro.QuickPanic(err)
}
fmt.Printf("%#v", foo)
// Output: digpro_test.Foo{A:"a", B:1, C:2, private:true, ignore:3}
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
	"go.uber.org/dig"
)

func main() {
	type Foo struct {
		A       string
		B       int
		C       int  `name:"c"`
		private bool //lint:ignore U1000 for test
		ignore  int  `digpro:"ignore"`
	}
	// new a *dig.Container
	c := digpro.New()
	// provide some constructor
	digpro.QuickPanic(
		// register object
		c.Supply("a"),
		c.Supply(1),
		c.Supply(true),
		c.Supply(2, dig.Name("c")),
		// register a struct
		c.Struct(Foo{
			ignore: 3,
		}),
		// equals to
		// c.Provide(func(in struct {
		// 	A       string
		// 	B       int
		// 	C       int `name:"c"`
		// 	Private bool
		// }) Foo {
		// 	return Foo{
		// 		A:       in.A,
		// 		B:       in.B,
		// 		C:       in.C,
		// 		private: in.Private,
		// 		ignore:  3,
		// 	}
		// }),
	)
	// extract object from container
	foo, err := c.Extract(Foo{})
	if err != nil {
		digpro.QuickPanic(err)
	}
	fmt.Printf("%#v", foo)
}
Output:

digpro_test.Foo{A:"a", B:1, C:2, private:true, ignore:3}

func (*ContainerWrapper) Supply

func (c *ContainerWrapper) Supply(value interface{}, opts ...dig.ProvideOption) error

Supply a value into container. for example

c := digpro.New()
digpro.QuickPanic(
	// register object
	c.Supply("a"),
	// equals to
	// c.Provide(func() string {return "a"}),
)
foo, err := c.Extract(string(""))
if err != nil {
	digpro.QuickPanic(err)
}
fmt.Println(foo)
// Output: a
Example
package main

import (
	"fmt"

	"github.com/rectcircle/digpro"
)

func main() {
	c := digpro.New()
	digpro.QuickPanic(
		// register object
		c.Supply("a"),
		// equals to
		// c.Provide(func() string {return "a"}),
	)
	foo, err := c.Extract(string(""))
	if err != nil {
		digpro.QuickPanic(err)
	}
	fmt.Println(foo)
}
Output:

a

func (*ContainerWrapper) Unwrap

func (c *ContainerWrapper) Unwrap() *dig.Container

Unwrap *ContainerWrapper to obtain *dig.Container.

WARNING: the methold only for debug, please not use in production

func (*ContainerWrapper) Visualize

func (c *ContainerWrapper) Visualize(w io.Writer, opts ...dig.VisualizeOption) error

Visualize for write dot graph to io.Writer

type ExtractOption

type ExtractOption = internal.ExtractOption

func ExtractByGroup

func ExtractByGroup(name string) ExtractOption

ExtractByGroup, for example

c := digpro.New()
_ = c.Supply(1, dig.Group("ints"))  // please handle error in production
_ = c.Supply(1, dig.Group("ints"))
is, _ := c.Extract(int(0), digpro.ExtractByGroup("ints"))
fmt.Println(reflect.DeepEqual(is.([]int), []int{1, 1})) // true

func ExtractByName

func ExtractByName(name string) ExtractOption

ExtractByName, for example

c := digpro.New()
_ = c.Supply(1, dig.Name("int"))  // please handle error in production
i, _ := c.Extract(int(0), digpro.ExtractByName("int"))
fmt.Println(i.(int) == 1) // true

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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