wire: allow non-panic version of injector (google/go-cloud#91)
Fixes google/go-cloud#7
This commit is contained in:
50
README.md
50
README.md
@@ -18,11 +18,13 @@ produce a value. These functions are ordinary Go code.
|
|||||||
```go
|
```go
|
||||||
package foobarbaz
|
package foobarbaz
|
||||||
|
|
||||||
type Foo int
|
type Foo struct {
|
||||||
|
X int
|
||||||
|
}
|
||||||
|
|
||||||
// ProvideFoo returns a Foo.
|
// ProvideFoo returns a Foo.
|
||||||
func ProvideFoo() Foo {
|
func ProvideFoo() Foo {
|
||||||
return 42
|
return Foo{X: 42}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -33,11 +35,13 @@ package foobarbaz
|
|||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
type Bar int
|
type Bar struct {
|
||||||
|
X int
|
||||||
|
}
|
||||||
|
|
||||||
// ProvideBar returns a Bar: a negative Foo.
|
// ProvideBar returns a Bar: a negative Foo.
|
||||||
func ProvideBar(foo Foo) Bar {
|
func ProvideBar(foo Foo) Bar {
|
||||||
return Bar(-foo)
|
return Bar{X: -foo.X}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -53,14 +57,16 @@ import (
|
|||||||
|
|
||||||
// ...
|
// ...
|
||||||
|
|
||||||
type Baz int
|
type Baz struct {
|
||||||
|
X int
|
||||||
|
}
|
||||||
|
|
||||||
// ProvideBaz returns a value if Bar is not zero.
|
// ProvideBaz returns a value if Bar is not zero.
|
||||||
func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {
|
func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) {
|
||||||
if bar == 0 {
|
if bar == 0 {
|
||||||
return 0, errors.New("cannot provide baz when bar is zero")
|
return 0, errors.New("cannot provide baz when bar is zero")
|
||||||
}
|
}
|
||||||
return Baz(bar), nil
|
return Baz{X: bar.X}, nil
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -102,9 +108,11 @@ calls providers in dependency order. With Wire, you write the injector's
|
|||||||
signature, then Wire generates the function's body.
|
signature, then Wire generates the function's body.
|
||||||
|
|
||||||
An injector is declared by writing a function declaration whose body is a call
|
An injector is declared by writing a function declaration whose body is a call
|
||||||
to `panic()` with a call to `wire.Build` as its argument. Let's say that the
|
to `wire.Build`. The return values don't matter as long as they are of the
|
||||||
above providers were defined in a package called `example.com/foobarbaz`. The
|
correct type. The values themselves will be ignored in the generated code. Let's
|
||||||
following would declare an injector to obtain a `Baz`:
|
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
|
```go
|
||||||
// +build wireinject
|
// +build wireinject
|
||||||
@@ -121,7 +129,8 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
func initializeApp(ctx context.Context) (foobarbaz.Baz, error) {
|
func initializeApp(ctx context.Context) (foobarbaz.Baz, error) {
|
||||||
panic(wire.Build(foobarbaz.MegaSet))
|
wire.Build(foobarbaz.MegaSet)
|
||||||
|
return foobarbaz.Baz{}, nil
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -311,10 +320,13 @@ Instead of having injectors depend on a throwaway provider function, you can
|
|||||||
add a value expression to a provider set.
|
add a value expression to a provider set.
|
||||||
|
|
||||||
```go
|
```go
|
||||||
type Foo int
|
type Foo struct {
|
||||||
|
X int
|
||||||
|
}
|
||||||
|
|
||||||
func injectFoo() Foo {
|
func injectFoo() Foo {
|
||||||
panic(wire.Build(wire.Value(Foo(42))))
|
wire.Build(wire.Value(Foo{X: 42}))
|
||||||
|
return Foo{}
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -322,7 +334,7 @@ The generated injector would look like this:
|
|||||||
|
|
||||||
```go
|
```go
|
||||||
func injectFoo() Foo {
|
func injectFoo() Foo {
|
||||||
foo := Foo(42)
|
foo := Foo{X: 42}
|
||||||
return foo
|
return foo
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -355,3 +367,15 @@ func provideFile(log Logger, path Path) (*os.File, func(), error) {
|
|||||||
|
|
||||||
A cleanup function is guaranteed to be called before the cleanup function of any
|
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()`.
|
of the provider's inputs and must have the signature `func()`.
|
||||||
|
|
||||||
|
### Alternate Injector Syntax
|
||||||
|
|
||||||
|
If you grow weary of writing `return foobarbaz.Foo{}, nil` at the end of your
|
||||||
|
injector function declaration, you can instead write it more concisely with a
|
||||||
|
`panic`:
|
||||||
|
|
||||||
|
```go
|
||||||
|
func injectFoo() Foo {
|
||||||
|
panic(wire.Build(/* ... */))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|||||||
@@ -578,6 +578,11 @@ func isInjector(info *types.Info, fn *ast.FuncDecl) *ast.CallExpr {
|
|||||||
only = stmt
|
only = stmt
|
||||||
case *ast.EmptyStmt:
|
case *ast.EmptyStmt:
|
||||||
// Do nothing.
|
// Do nothing.
|
||||||
|
case *ast.ReturnStmt:
|
||||||
|
// Allow the function to end in a return.
|
||||||
|
if only == nil {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@@ -585,29 +590,24 @@ func isInjector(info *types.Info, fn *ast.FuncDecl) *ast.CallExpr {
|
|||||||
if only == nil {
|
if only == nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
panicCall, ok := only.X.(*ast.CallExpr)
|
call, ok := only.X.(*ast.CallExpr)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
panicIdent, ok := panicCall.Fun.(*ast.Ident)
|
if qualifiedIdentObject(info, call.Fun) == types.Universe.Lookup("panic") {
|
||||||
|
if len(call.Args) != 1 {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
call, ok = call.Args[0].(*ast.CallExpr)
|
||||||
if !ok {
|
if !ok {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
if info.ObjectOf(panicIdent) != types.Universe.Lookup("panic") {
|
|
||||||
return nil
|
|
||||||
}
|
}
|
||||||
if len(panicCall.Args) != 1 {
|
buildObj := qualifiedIdentObject(info, call.Fun)
|
||||||
return nil
|
|
||||||
}
|
|
||||||
buildCall, ok := panicCall.Args[0].(*ast.CallExpr)
|
|
||||||
if !ok {
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
buildObj := qualifiedIdentObject(info, buildCall.Fun)
|
|
||||||
if !isWireImport(buildObj.Pkg().Path()) || buildObj.Name() != "Build" {
|
if !isWireImport(buildObj.Pkg().Path()) || buildObj.Name() != "Build" {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
return buildCall
|
return call
|
||||||
}
|
}
|
||||||
|
|
||||||
func isWireImport(path string) bool {
|
func isWireImport(path string) bool {
|
||||||
|
|||||||
26
internal/wire/testdata/InjectWithReturn/foo/foo.go
vendored
Normal file
26
internal/wire/testdata/InjectWithReturn/foo/foo.go
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import "fmt"
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
fmt.Println(injectedMessage())
|
||||||
|
}
|
||||||
|
|
||||||
|
// provideMessage provides a friendly user greeting.
|
||||||
|
func provideMessage() string {
|
||||||
|
return "Hello, World!"
|
||||||
|
}
|
||||||
26
internal/wire/testdata/InjectWithReturn/foo/wire.go
vendored
Normal file
26
internal/wire/testdata/InjectWithReturn/foo/wire.go
vendored
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
// Copyright 2018 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// https://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//+build wireinject
|
||||||
|
|
||||||
|
package main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/google/go-cloud/wire"
|
||||||
|
)
|
||||||
|
|
||||||
|
func injectedMessage() string {
|
||||||
|
wire.Build(provideMessage)
|
||||||
|
return ""
|
||||||
|
}
|
||||||
1
internal/wire/testdata/InjectWithReturn/out.txt
vendored
Normal file
1
internal/wire/testdata/InjectWithReturn/out.txt
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
Hello, World!
|
||||||
1
internal/wire/testdata/InjectWithReturn/pkg
vendored
Normal file
1
internal/wire/testdata/InjectWithReturn/pkg
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
foo
|
||||||
Reference in New Issue
Block a user