Skip to content

Commit

Permalink
Refactor comments and add more docs
Browse files Browse the repository at this point in the history
  • Loading branch information
tiendc committed Sep 6, 2024
1 parent f9ccff0 commit 4878956
Show file tree
Hide file tree
Showing 4 changed files with 52 additions and 9 deletions.
43 changes: 37 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@
## Functionalities

- Automatically wiring/injecting objects on creation.
- Easy to use (see Usages below).
- `Shared mode` by default that creates only one instance for a type. This option is configurable.
- Easy to use (see Usage section).
- `Shared mode` by default that creates only one instance for a type (this option is configurable).
- Ability to overwrite objects of specific types on building which is convenient for unit testing.
- No code generation.

Expand Down Expand Up @@ -42,7 +42,7 @@ go get github.com/tiendc/autowire
// and RepoY
type RepoY interface {}
func NewRepoY(redisClient RedisClient) RepoY {
return <RepoY-instance>, nil
return <RepoY-instance>
}

// and a struct provider
Expand Down Expand Up @@ -97,13 +97,44 @@ go get github.com/tiendc/autowire
This is convenient in unit testing to overwrite specific types only.

```go
// In unit testing, you may want to overwrite some `repos` and `clients` with fake instances
serviceA, err := Build[ServiceA](container, ProviderOverwrite[RepoX](fakeRepoX),
// In unit testing, you may want to overwrite some `repos` and `clients` with fake instances.
// NOTE: you may need to use `non-shared mode` to make sure cached objects are not used.
serviceA, err := Build[ServiceA](container, NonSharedMode(),
ProviderOverwrite[RepoX](fakeRepoX),
ProviderOverwrite[RepoY](fakeRepoY))
serviceA, err := Build[ServiceA](container, ProviderOverwrite[RedisClient](fakeRedisClient),
serviceA, err := Build[ServiceA](container, NonSharedMode(),
ProviderOverwrite[RedisClient](fakeRedisClient),
ProviderOverwrite[S3Client](fakeS3Client))
```

### Reclaim memory after use

Typically, dependency injection is often only used at the initialization phase of a program.
However, it can take some space in memory which will become wasted after the phase.
Use the below trick to reclaim the memory taken by the autowire variables.

```go
var (
// create a global container
container = MustNewContainer(...)
)

func autowireCleanUp() {
// Assign nil to allow the garbage collector to reclaim the taken memory
container = nil
}

func main() {
// Initialization phase
// Create services and use them
serviceA, _ := autowire.Build[ServiceA](container)
serviceB, _ := autowire.Build[ServiceB](container)

// Clean up the usage, make sure you won't use the vars any more
autowireCleanUp()
}
```

## Contributing

- You are welcome to make pull requests for new functions and bug fixes.
Expand Down
12 changes: 9 additions & 3 deletions container.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,24 @@ type Container interface {
// In this mode, ServiceX will be created only one time, so ServiceA and ServiceB will share the
// same ServiceX object.
SharedMode() bool

// setSharedMode sets shared mode
setSharedMode(bool)

// ProviderSet gets provider set within the container
ProviderSet() ProviderSet

// Get gets a value stored in the container for the specified type.
// If not found, returns ErrNotFound.
Get(targetType reflect.Type) (reflect.Value, error)

// Build creates a value for the specified type and all other required values.
Build(targetType reflect.Type, opts ...ContextOption) (reflect.Value, error)

// BuildWithCtx creates a value for the specified type with passing a context.Context object.
// The context object will be passed to every provider which requires a context.
BuildWithCtx(ctx context.Context, targetType reflect.Type, opts ...ContextOption) (reflect.Value, error)

// Resolve builds dependency graph for the specified type
Resolve(targetType reflect.Type) (DependencyGraph, error)
}
Expand Down Expand Up @@ -82,9 +87,10 @@ func (c *container) Get(targetType reflect.Type) (value reflect.Value, err error
// func(<arg1>, ..., <argN>) <ServiceType>
// func(<arg1>, ..., <argN>) (<ServiceType>, error)
// func(context.Context, <arg1>, ..., <argN>) (<ServiceType>, error)
// - struct pointers
// - objects of type `ProviderSet`
// - objects of type `Provider`
//
// - struct pointers
// - objects of type `ProviderSet`
// - objects of type `Provider`
func NewContainer(providers []any, opts ...ContainerConfigOption) (Container, error) {
providerSet, err := parseProviders(providers...)
if err != nil {
Expand Down
3 changes: 3 additions & 0 deletions provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,17 @@ var (
type Provider interface {
// Source returns provider source which can be a function, a struct pointer, or a value
Source() any

// TargetTypes returns a list of target types that the provider can create objects of.
// A function provider can provide only one target type, whereas a struct provider can
// provide multiple target types through its fields.
TargetTypes() []reflect.Type

// DependentTypes returns a list of types that will be required when the provider creates
// objects of the target types. Typically, a function provider can have no dependent types
// or multiple ones, whereas a struct provider have no dependent types.
DependentTypes() []reflect.Type

// Build builds an object of the specified type.
Build(*Context, reflect.Type) (reflect.Value, error)
}
Expand Down
3 changes: 3 additions & 0 deletions provider_set.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,10 +9,13 @@ import (
type ProviderSet interface {
// GetFor returns a provider for the specified type, or ErrNotFound.
GetFor(reflect.Type) (Provider, error)

// GetAll returns all providers contained within the set
GetAll() []Provider

// Overwrite replaces the existing provider by its target type with the specified one
Overwrite(Provider)

// shallowClone clones the set (shallow clone only)
shallowClone() ProviderSet
}
Expand Down

0 comments on commit 4878956

Please sign in to comment.