diff --git a/README.md b/README.md index 81860bf..429f415 100644 --- a/README.md +++ b/README.md @@ -18,11 +18,13 @@ produce a value. These functions are ordinary Go code. ```go package foobarbaz -type Foo int +type Foo struct { + X int +} // ProvideFoo returns a 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. 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. func ProvideBaz(ctx context.Context, bar Bar) (Baz, error) { if bar == 0 { 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. 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 -above providers were defined in a package called `example.com/foobarbaz`. The -following would declare an injector to obtain a `Baz`: +to `wire.Build`. The return values don't matter as long as they are of the +correct type. The values themselves will be ignored in the generated code. 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 wireinject @@ -121,7 +129,8 @@ import ( ) 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. ```go -type Foo int +type Foo struct { + X int +} 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 func injectFoo() Foo { - foo := Foo(42) + foo := Foo{X: 42} 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 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(/* ... */)) +} +``` diff --git a/internal/wire/parse.go b/internal/wire/parse.go index 6b07b3c..d2116fc 100644 --- a/internal/wire/parse.go +++ b/internal/wire/parse.go @@ -578,6 +578,11 @@ func isInjector(info *types.Info, fn *ast.FuncDecl) *ast.CallExpr { only = stmt case *ast.EmptyStmt: // Do nothing. + case *ast.ReturnStmt: + // Allow the function to end in a return. + if only == nil { + return nil + } default: return nil } @@ -585,29 +590,24 @@ func isInjector(info *types.Info, fn *ast.FuncDecl) *ast.CallExpr { if only == nil { return nil } - panicCall, ok := only.X.(*ast.CallExpr) + call, ok := only.X.(*ast.CallExpr) if !ok { return nil } - panicIdent, ok := panicCall.Fun.(*ast.Ident) - if !ok { - return nil + 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 { + return nil + } } - if info.ObjectOf(panicIdent) != types.Universe.Lookup("panic") { - return nil - } - if len(panicCall.Args) != 1 { - return nil - } - buildCall, ok := panicCall.Args[0].(*ast.CallExpr) - if !ok { - return nil - } - buildObj := qualifiedIdentObject(info, buildCall.Fun) + buildObj := qualifiedIdentObject(info, call.Fun) if !isWireImport(buildObj.Pkg().Path()) || buildObj.Name() != "Build" { return nil } - return buildCall + return call } func isWireImport(path string) bool { diff --git a/internal/wire/testdata/InjectWithReturn/foo/foo.go b/internal/wire/testdata/InjectWithReturn/foo/foo.go new file mode 100644 index 0000000..c20a0b3 --- /dev/null +++ b/internal/wire/testdata/InjectWithReturn/foo/foo.go @@ -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!" +} diff --git a/internal/wire/testdata/InjectWithReturn/foo/wire.go b/internal/wire/testdata/InjectWithReturn/foo/wire.go new file mode 100644 index 0000000..fcaecc3 --- /dev/null +++ b/internal/wire/testdata/InjectWithReturn/foo/wire.go @@ -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 "" +} diff --git a/internal/wire/testdata/InjectWithReturn/out.txt b/internal/wire/testdata/InjectWithReturn/out.txt new file mode 100644 index 0000000..8ab686e --- /dev/null +++ b/internal/wire/testdata/InjectWithReturn/out.txt @@ -0,0 +1 @@ +Hello, World! diff --git a/internal/wire/testdata/InjectWithReturn/pkg b/internal/wire/testdata/InjectWithReturn/pkg new file mode 100644 index 0000000..257cc56 --- /dev/null +++ b/internal/wire/testdata/InjectWithReturn/pkg @@ -0,0 +1 @@ +foo