di

package module
v1.0.1 Latest Latest
Warning

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

Go to latest
Published: Mar 31, 2023 License: MIT Imports: 8 Imported by: 19

README

GoZix DI

License Documentation

Release Build Status Go Report Card Code Coverage

Dependency injection for Go programming language.

Features

  • Auto wiring
  • Constructor injection
  • Instance injection
  • Interfaces support
  • Optional injection
  • Field injection
  • Lazy loading
  • Tagging
  • Cleaning

Installation

go get github.com/gozix/di

Documentation

You can find documentation on pkg.go.dev and read source code if needed.

Questions

If you have any questions, feel free to create an issue.

Documentation

Overview

Package di allows you to standardize and centralize the way objects are constructed in your application.

Example (HttpServer)

This is example demonstrates how use dependency container for simple http application.

var builder, err = di.NewBuilder(
	di.BuilderOptions(
		di.Autowire((*BarController)(nil), di.As((*Controller)(nil))), // provide autowired type
		di.Autowire((*BazController)(nil), di.As((*Controller)(nil))), // provide autowired type
	),
	di.BuilderOptions(
		di.Provide(NewServerMux), // provide constructor
		di.Provide(NewServer),    // provide constructor
	),
)

if err != nil {
	fmt.Println()
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

// build container
var container di.Container
if container, err = builder.Build(); err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

// Call function with resolved dependencies
_ = container.Call(func(srv *http.Server) {
	if srv == nil {
		_, _ = fmt.Fprint(os.Stderr, err)
		os.Exit(1)
	}
})

fmt.Println("Listening...")
Output:

Listening...
Example (Interfaces)

This is example demonstrates Container.Resolve usage with aliases.

var builder, err = di.NewBuilder(
	// provide constructor
	di.Provide(NewBarController, di.As(new(Controller))),
	di.Provide(NewBazController, di.As(new(Controller))),
)

if err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

var container di.Container
if container, err = builder.Build(); err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

var controllers []Controller
if err = container.Resolve(&controllers); err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

fmt.Println("resolved", len(controllers), "controllers")
Output:

resolved 2 controllers
Example (OptionalFieldInjection)

This is example demonstrates optional field injection.

type Foo struct {
	Bar *BarController
	Baz *BazController
}

var builder, err = di.NewBuilder(
	// provide autowired type with optional field Baz
	di.Autowire((*Foo)(nil), di.Constraint("Baz", di.Optional(true))),
	// provide constructor
	di.Provide(NewBarController),
)

if err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

var container di.Container
if container, err = builder.Build(); err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

err = container.Call(func(foo *Foo) error {
	if foo == nil {
		return errors.New("foo is nil")
	}

	if foo.Bar == nil {
		return errors.New("foo.Bar is nil")
	}

	if foo.Baz != nil {
		return errors.New("foo.Baz is not nil")
	}

	return nil
})

if err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

fmt.Println("Looks like something is fine")
Output:

Looks like something is fine
Example (Tags)

This is example demonstrates Container.Has usage with modifiers.

var builder, err = di.NewBuilder(
	// provide constructor
	di.Provide(NewBarController, di.Tags{{
		Name: "controller",
	}}),
)

if err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

var container di.Container
if container, err = builder.Build(); err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

if container.Has((*BarController)(nil), di.WithTags("controller")) {
	fmt.Println("container has *BarController with tag controller")
}

var c *BarController
if err = container.Resolve(&c, di.WithTags("controller")); err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}

if c != nil {
	fmt.Println("container resolved *BarController with tag controller")
}

err = container.Call(func(c *BarController) error {
	if c == nil {
		return errors.New("container call has nil *BarController")
	}

	fmt.Println("container call *BarController with tag controller")

	return nil
}, di.Constraint(0, di.WithTags("controller")))

if err != nil {
	_, _ = fmt.Fprint(os.Stderr, err)
	os.Exit(1)
}
Output:

container has *BarController with tag controller
container resolved *BarController with tag controller
container call *BarController with tag controller

Index

Examples

Constants

This section is empty.

Variables

View Source
var (
	// ErrNotPointerToInterface is error triggered when provided alias not pointer to interface.
	ErrNotPointerToInterface = errors.New("not pointer to interface")

	// ErrIsNil is error triggered when provided nil alias.
	ErrIsNil = errors.New("is nil")

	// ErrNotImplementInterface is error triggered when provided type not implement alias interface.
	ErrNotImplementInterface = errors.New("not implement interface")

	// ErrDoesNotExist triggered when type not present in container.
	ErrDoesNotExist = errors.New("does not exist")

	// ErrMustBeSliceOrPointer triggered when resolved in invalid target.
	ErrMustBeSliceOrPointer = errors.New("must be a slice or pointer")

	// ErrMultipleDefinitions triggered when type resolved in single instance, but container contain multiple types.
	ErrMultipleDefinitions = errors.New("multiple definitions")

	// ErrorMustBeFunction triggered when value not a function.
	ErrorMustBeFunction = errors.New("must be a function")

	// ErrInvalidConstructor is error triggered when constructor have invalid signature.
	ErrInvalidConstructor = compiler.ErrInvalidConstructor

	// ErrInvalidType is error triggered when provided invalid type.
	ErrInvalidType = compiler.ErrInvalidType

	// ErrInvalidValue is error triggered when provided invalid value.
	ErrInvalidValue = compiler.ErrInvalidValue
)

Functions

func NewTypeError

func NewTypeError(typ reflect.Type, err error) error

NewTypeError is error constructor.

Types

type AddOption

type AddOption interface {
	// contains filtered or unexported methods
}

AddOption is specified for Builder.Add method option interface.

func AddOptions

func AddOptions(options ...AddOption) AddOption

AddOptions allow to organize logical groups of add options.

var builder = di.NewBuilder()
builder.Add(di.AddOptions(
	di.As(new(io.Writer)),
	di.Tags{{
		Name: "tag",
	}},
))

type Arg

type Arg struct {
	Key   string
	Value string
}

Arg is representation.

type Args

type Args []Arg

Args is arg collection.

type AsOption

type AsOption interface {
	AddOption
	ProvideOption
}

AsOption is an option

func As

func As(aliases ...any) AsOption

As sets type alias.

type Builder

type Builder interface {
	// Add provides value as is.
	//
	// The value argument must contain any value what you want, fre example:
	//   - new(http.Server)
	//   - *http.Server{}
	//   - etc.
	// The options argument may be one of:
	//   - di.Tags{}
	//   - di.As()
	Add(value Value, options ...AddOption) error

	// Apply applies options to Builder.
	// The options argument may be one of:
	//   - di.BuilderOptions()
	//   - di.Add()
	//   - di.Autowire()
	//   - di.Provide()
	Apply(options ...BuilderOption) error

	// Autowire providers autowired type.
	//
	// The target argument must contain the wanted type, for example:
	//   - (*http.Server)(nil)
	//   - (*io.Writer)(nil)
	//   - new(io.Writer)
	//   - etc.
	// The options argument may be one of:
	//   - di.As()
	//   - di.Constraint()
	//   - di.Tags{}
	//   - di.Unshared()
	Autowire(target Type, options ...ProvideOption) error

	// Provide provides any constructor.
	//
	// The constructor argument must be a function with one of the following signatures:
	//   - func New(constraints ...any) (value any)
	//   - func New(constraints ...any) (value any, err error)
	//   - func New(constraints ...any) (value any, closer func(){})
	//   - func New(constraints ...any) (value any, closer func(){}, err error)
	// The options argument may be one of:
	//   - di.As()
	//   - di.Constraint()
	//   - di.Tags{}
	//   - di.Unshared()
	Provide(constructor Constructor, options ...ProvideOption) error

	// Build is container build method.
	Build() (Container, error)

	// Definitions are build snapshot of definitions.
	Definitions() []Definition
}

Builder must be used to create a Container. The Builder should be created with NewBuilder. Then you can provide any definition with various allowed methods and finally build the Container with the Build method.

func NewBuilder

func NewBuilder(options ...BuilderOption) (_ Builder, err error)

NewBuilder is builder constructor.

type BuilderOption

type BuilderOption interface {
	// contains filtered or unexported methods
}

BuilderOption is specified for NewBuilder option interface.

func Add

func Add(value Value, options ...AddOption) BuilderOption

Add is builder constructor option. This is a syntax sugar for builder constructor usage.

func Autowire

func Autowire(value Type, options ...ProvideOption) BuilderOption

Autowire is builder constructor option. This is a syntax sugar for builder constructor usage.

func BuilderOptions

func BuilderOptions(options ...BuilderOption) BuilderOption

BuilderOptions allow to organize logical groups of builder options.

var builder = di.NewBuilder(
	di.BuilderOptions(
		di.Provide(NewBarController),
		di.Provide(NewBazController),
	),
	di.BuilderOptions(
		di.Provide(NewMuxServer),
		di.Provide(NewServer),
	),
)

func Provide

func Provide(value Constructor, options ...ProvideOption) BuilderOption

Provide is builder constructor option. This is a syntax sugar for builder constructor usage.

type ConstraintOption

type ConstraintOption interface {
	ProvideOption
	// contains filtered or unexported methods
}

ConstraintOption is an option

func Constraint

func Constraint(key any, restrictions ...Restriction) ConstraintOption

Constraint restricts the dependency resolving.

The key argument may be string, int or any other type

type Constructor

type Constructor any

Constructor is any constructor.

type Container

type Container interface {
	// Call calls the function with resolved arguments.
	//
	// The fn argument must contain any function. If the function contains error in the last return type,
	// then Call will return that value as own return type value.
	// The options argument may be one of:
	//   - di.Constraint()
	Call(fn Function, options ...ConstraintOption) (err error)

	// Close runs closers in reverse order that has been created.
	//
	// Any close function can return any error that stop the calling loop for all rest closers. Any close function
	// can return any error that stop the calling loop for all rest closers. That error will return in function
	// return type.
	Close() error

	// Has checks that type exists in container, if not it return false.
	//
	// The value argument must contain the wanted type, for example:
	//   - (*http.Server)(nil)
	//   - (*io.Writer)(nil)
	//   - new(io.Writer)
	//   - etc.
	// The modifiers argument may be one of:
	//   - di.WithTags()
	Has(value Type, modifiers ...Modifier) (exist bool)

	// Resolve resolves type and fills target pointer.
	//
	// The target argument must contain reference to wanted variable.
	// The modifiers argument may be one of:
	//   - di.WithTags()
	Resolve(target Value, modifiers ...Modifier) (err error)
}

Container represents a dependency injection container. To create a container, you should use a builder.

type Definition

type Definition interface {
	// ID is definition unique identificator getter.
	ID() int

	// Dependencies is definition type dependencies getter.
	Dependencies() []Dependency

	// Tags is definition tags getter.
	Tags() Tags

	// Type is definition type getter.
	Type() reflect.Type

	// Unshared is definition unshared getter.
	Unshared() bool
}

Definition represent container definition.

type Dependency

type Dependency struct {
	// Type is type of dependency.
	Type reflect.Type

	// Optional is optional flag.
	Optional bool

	// Definitions are list of matched definitions.
	Definitions []Definition
}

Dependency represent definition dependency.

type Function

type Function any

Function is any function.

type Modifier

type Modifier func(defs []Definition) []Definition

Modifier calling with definitions founded by type in container. Modifiers should use for filtering, sorting or any other modifications list of definitions before they should resolve.

func Filter

func Filter(match func(def Definition) bool) Modifier

Filter filters the definitions the provided match function.

func Sort

func Sort(less func(a, b Definition) bool) Modifier

Sort sorts the definitions the provided less function.

func WithTags

func WithTags(tags ...string) Modifier

WithTags filters out definitions without needed tags.

func WithoutTags

func WithoutTags(tags ...string) Modifier

WithoutTags filters out definitions with needed tags.

type ProvideOption

type ProvideOption interface {
	// contains filtered or unexported methods
}

ProvideOption is specified for Builder.Provide method option interface.

func ProvideOptions

func ProvideOptions(options ...ProvideOption) ProvideOption

ProvideOptions allow to organize logical groups of provide options.

var builder = di.NewBuilder()
builder.Provide(di.ProvideOptions(
	di.As(new(io.Writer)),
	di.Tags{{
		Name: "tag",
	}},
))

func Unshared

func Unshared() ProvideOption

Unshared mark definition as Unshared.

type Restriction

type Restriction interface {
	// contains filtered or unexported methods
}

Restriction is an option.

func Optional

func Optional(v bool) Restriction

Optional set dependency optional or not, by default all dependencies are required.

type Tag

type Tag struct {
	Name string
	Args Args
}

Tag is tag representation.

type Tags

type Tags []Tag

Tags is tag collection.

type Type

type Type any

Type is any type.

type TypeError

type TypeError struct {
	Type reflect.Type
	Err  error
}

TypeError records an error and type that caused it.

func (*TypeError) Error

func (e *TypeError) Error() string

func (*TypeError) Unwrap

func (e *TypeError) Unwrap() error

type Value

type Value any

Value is any value.

Directories

Path Synopsis
internal

Jump to

Keyboard shortcuts

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