wire: rename from Goose (google/go-cloud#59)
Rename Goose to wire, making it more obvious what the package does, and look more like the stdlib. Fixes google/go-cloud#8
This commit is contained in:
76
README.md
76
README.md
@@ -1,6 +1,6 @@
|
||||
# goose: Compile-Time Dependency Injection for Go
|
||||
# Wire: Compile-Time Dependency Injection for Go
|
||||
|
||||
goose is a compile-time [dependency injection][] framework for Go, inspired by
|
||||
Wire is a static [dependency injection][] framework for Go, inspired by
|
||||
[Dagger][]. It works by using Go code to specify dependencies, then
|
||||
generating code to create those structures, mimicking the code that a user
|
||||
might have hand-written.
|
||||
@@ -12,7 +12,7 @@ might have hand-written.
|
||||
|
||||
### Defining Providers
|
||||
|
||||
The primary mechanism in goose is the **provider**: a function that can
|
||||
The primary mechanism in Wire is the **provider**: a function that can
|
||||
produce a value. These functions are ordinary Go code.
|
||||
|
||||
```go
|
||||
@@ -65,19 +65,19 @@ func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {
|
||||
```
|
||||
|
||||
Providers can be grouped in **provider sets**. To add these providers to a new
|
||||
set called `SuperSet`, use the `goose.NewSet` function:
|
||||
set called `SuperSet`, use the `wire.NewSet` function:
|
||||
|
||||
```go
|
||||
package foobarbaz
|
||||
|
||||
import (
|
||||
// ...
|
||||
"github.com/google/go-cloud/goose"
|
||||
"github.com/google/go-cloud/wire"
|
||||
)
|
||||
|
||||
// ...
|
||||
|
||||
var SuperSet = goose.NewSet(ProvideFoo, ProvideBar, ProvideBaz)
|
||||
var SuperSet = wire.NewSet(ProvideFoo, ProvideBar, ProvideBaz)
|
||||
```
|
||||
|
||||
You can also add other provider sets into a provider set.
|
||||
@@ -92,22 +92,22 @@ import (
|
||||
|
||||
// ...
|
||||
|
||||
var MegaSet = goose.NewSet(SuperSet, pkg.OtherSet)
|
||||
var MegaSet = wire.NewSet(SuperSet, pkg.OtherSet)
|
||||
```
|
||||
|
||||
### Injectors
|
||||
|
||||
An application wires up these providers with an **injector**: a function that
|
||||
calls providers in dependency order. With goose, you write the injector's
|
||||
signature, then goose generates the function's body.
|
||||
calls providers in dependency order. With Wire, you write the injector's
|
||||
signature, then Wire generates the function's body.
|
||||
|
||||
An injector is declared by writing a function declaration whose body is a call
|
||||
to `panic()` with a call to `goose.Build` as its argument. Let's say that the
|
||||
to `panic()` with a call to `wire.Build` as its argument. Let's say that the
|
||||
above providers were defined in a package called `example.com/foobarbaz`. The
|
||||
following would declare an injector to obtain a `Baz`:
|
||||
|
||||
```go
|
||||
// +build gooseinject
|
||||
// +build wireinject
|
||||
|
||||
// ^ build tag makes sure the stub is not built in the final build
|
||||
|
||||
@@ -116,30 +116,30 @@ package main
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/google/go-cloud/goose"
|
||||
"github.com/google/go-cloud/wire"
|
||||
"example.com/foobarbaz"
|
||||
)
|
||||
|
||||
func initializeApp(ctx context.Context) (foobarbaz.Baz, error) {
|
||||
panic(goose.Build(foobarbaz.MegaSet))
|
||||
panic(wire.Build(foobarbaz.MegaSet))
|
||||
}
|
||||
```
|
||||
|
||||
Like providers, injectors can be parameterized on inputs (which then get sent to
|
||||
providers) and can return errors. Arguments to `goose.Build` are the same as
|
||||
`goose.NewSet`: they form a provider set. This is the provider set that gets
|
||||
providers) and can return errors. Arguments to `wire.Build` are the same as
|
||||
`wire.NewSet`: they form a provider set. This is the provider set that gets
|
||||
used during code generation for that injector.
|
||||
|
||||
Any non-injector declarations found in a file with injectors will be copied into
|
||||
the generated file.
|
||||
|
||||
You can generate the injector by invoking goose in the package directory:
|
||||
You can generate the injector by invoking `gowire` in the package directory:
|
||||
|
||||
```
|
||||
goose
|
||||
gowire
|
||||
```
|
||||
|
||||
Or you can add the line `//go:generate goose` to another file in your package to
|
||||
Or you can add the line `//go:generate gowire` to another file in your package to
|
||||
use [`go generate`]:
|
||||
|
||||
```
|
||||
@@ -149,13 +149,13 @@ go generate
|
||||
(Adding the line to the injection declaration file will be silently ignored by
|
||||
`go generate`.)
|
||||
|
||||
goose will produce an implementation of the injector in a file called
|
||||
`goose_gen.go` that looks something like this:
|
||||
Wire will produce an implementation of the injector in a file called
|
||||
`wire_gen.go` that looks something like this:
|
||||
|
||||
```go
|
||||
// Code generated by goose. DO NOT EDIT.
|
||||
// Code generated by gowire. DO NOT EDIT.
|
||||
|
||||
//+build !gooseinject
|
||||
//+build !wireinject
|
||||
|
||||
package main
|
||||
|
||||
@@ -175,15 +175,15 @@ func initializeApp(ctx context.Context) (foobarbaz.Baz, error) {
|
||||
```
|
||||
|
||||
As you can see, the output is very close to what a developer would write
|
||||
themselves. Further, there is little dependency on goose at runtime: all of the
|
||||
written code is just normal Go code, and can be used without goose.
|
||||
themselves. Further, there is little dependency on Wire at runtime: all of the
|
||||
written code is just normal Go code, and can be used without Wire.
|
||||
|
||||
[`go generate`]: https://blog.golang.org/generate
|
||||
|
||||
## Best Practices
|
||||
|
||||
goose is still not mature yet, but guidance that applies to Dagger generally
|
||||
applies to goose as well. In particular, when thinking about how to group
|
||||
Wire is still not mature yet, but guidance that applies to Dagger generally
|
||||
applies to Wire as well. In particular, when thinking about how to group
|
||||
providers into sets, follow the same [guidance](https://google.github.io/dagger/testing.html#organize-modules-for-testability)
|
||||
as Dagger (provider sets are called modules in Dagger/Guice):
|
||||
|
||||
@@ -209,7 +209,7 @@ as Dagger (provider sets are called modules in Dagger/Guice):
|
||||
> - The [provider sets] should each include the no-reasonable-alternative
|
||||
> [provider sets] that require the [...] bindings each provides.
|
||||
|
||||
One goose-specific practice though: create one-off types where in Java you
|
||||
One Wire-specific practice though: create one-off types where in Java you
|
||||
would use a binding annotation. For example, if you need to pass a string
|
||||
through the dependency graph, you would create a wrapping type:
|
||||
|
||||
@@ -222,7 +222,7 @@ type MySQLConnectionString string
|
||||
### Binding Interfaces
|
||||
|
||||
Frequently, dependency injection is used to bind concrete implementations for an
|
||||
interface. goose matches inputs to outputs via [type identity][], so the
|
||||
interface. Wire matches inputs to outputs via [type identity][], so the
|
||||
inclination might be to create a provider that returns an interface type.
|
||||
However, this would not be idiomatic, since the Go best practice is to [return
|
||||
concrete types][]. Instead, you can declare an interface binding in a
|
||||
@@ -245,12 +245,12 @@ func ProvideBar() *Bar {
|
||||
return b
|
||||
}
|
||||
|
||||
var BarFooer = goose.NewSet(
|
||||
var BarFooer = wire.NewSet(
|
||||
ProvideBar,
|
||||
goose.Bind(new(Fooer), new(Bar)))
|
||||
wire.Bind(new(Fooer), new(Bar)))
|
||||
```
|
||||
|
||||
The first argument to `goose.Bind` is a pointer to a value of the desired
|
||||
The first argument to `wire.Bind` is a pointer to a value of the desired
|
||||
interface type and the second argument is a zero value of the concrete type. An
|
||||
interface binding does not necessarily need to have a provider in the same set
|
||||
that provides the concrete type.
|
||||
@@ -282,7 +282,7 @@ type FooBar struct {
|
||||
Bar Bar
|
||||
}
|
||||
|
||||
var Set = goose.NewSet(
|
||||
var Set = wire.NewSet(
|
||||
ProvideFoo,
|
||||
ProvideBar,
|
||||
FooBar{})
|
||||
@@ -314,7 +314,7 @@ add a value expression to a provider set.
|
||||
type Foo int
|
||||
|
||||
func injectFoo() Foo {
|
||||
panic(goose.Build(goose.Value(Foo(42))))
|
||||
panic(wire.Build(wire.Value(Foo(42))))
|
||||
}
|
||||
```
|
||||
|
||||
@@ -328,7 +328,7 @@ func injectFoo() Foo {
|
||||
```
|
||||
|
||||
It's important to note that the expression will be copied, so references to
|
||||
variables will be evaluated during the call to the injector. goose will emit
|
||||
variables will be evaluated during the call to the injector. `gowire` will emit
|
||||
an error if the expression calls any functions.
|
||||
|
||||
### Cleanup functions
|
||||
@@ -355,11 +355,3 @@ func provideFile(log Logger, path Path) (*os.File, func(), error) {
|
||||
|
||||
A cleanup function is guaranteed to be called before the cleanup function of any
|
||||
of the provider's inputs and must have the signature `func()`.
|
||||
|
||||
## Future Work
|
||||
|
||||
- Support for map bindings.
|
||||
- Support for multiple provider outputs.
|
||||
- Tighter validation for a provider set (cycles in unused providers goes
|
||||
unreported currently)
|
||||
- Visualization for provider sets
|
||||
|
||||
Reference in New Issue
Block a user