diff --git a/CHANGELOG.md b/CHANGELOG.md index 9b05005fe..882d7ab77 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,7 +5,10 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). ## [Unreleased] -- Back to development. +### Added +- Value groups can use the `flatten` option to indicate values in a slice should + be provided individually rather than providing the slice itself. See package + documentation for details. ## [1.10.0] - 2019-11-20 ### Added diff --git a/annotated.go b/annotated.go index c0c477540..b0cb29f60 100644 --- a/annotated.go +++ b/annotated.go @@ -64,6 +64,10 @@ type Annotated struct { // by the constructor. For more information on value groups, see the package documentation. // // A group option may not be provided if a name option is provided. + // + // Similar to group tags, the group name may be followed by a `,flatten` + // option to indicate that each element in the slice returned by the + // constructor should be injected into the value group individually. Group string // Target is the constructor being annotated with fx.Annotated. diff --git a/app_test.go b/app_test.go index 8682785e2..2092c428b 100644 --- a/app_test.go +++ b/app_test.go @@ -141,6 +141,26 @@ func TestNewApp(t *testing.T) { require.NoError(t, app.Err()) }) + t.Run("ProvidesWithAnnotateFlattened", func(t *testing.T) { + app := fxtest.New(t, + Provide(Annotated{ + Target: func() []int { return []int{1} }, + Group: "foo,flatten", + }), + Invoke( + func(b struct { + In + Foos []int `group:"foo"` + }) { + assert.Len(t, b.Foos, 1) + }, + ), + ) + + defer app.RequireStart().RequireStop() + require.NoError(t, app.Err()) + }) + t.Run("ProvidesWithEmptyAnnotate", func(t *testing.T) { type A struct{} @@ -250,7 +270,7 @@ func TestInvokes(t *testing.T) { ) err := app.Err() require.Error(t, err) - assert.Contains(t, err.Error(), "fx_test.A is not in the container") + assert.Contains(t, err.Error(), "missing type: fx_test.A") }) t.Run("ErrorHooksAreCalled", func(t *testing.T) { diff --git a/go.mod b/go.mod index 31fdede0a..1eb289d61 100644 --- a/go.mod +++ b/go.mod @@ -4,7 +4,7 @@ go 1.13 require ( github.com/stretchr/testify v1.4.0 - go.uber.org/dig v1.8.0 + go.uber.org/dig v1.9.0 go.uber.org/goleak v0.10.0 go.uber.org/multierr v1.4.0 golang.org/x/lint v0.0.0-20190930215403-16217165b5de diff --git a/go.sum b/go.sum index 281f9030b..f304185a1 100644 --- a/go.sum +++ b/go.sum @@ -20,8 +20,8 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= go.uber.org/atomic v1.5.0 h1:OI5t8sDa1Or+q8AeE+yKeB/SDYioSHAgcVljj9JIETY= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= -go.uber.org/dig v1.8.0 h1:1rR6hnL/bu1EVcjnRDN5kx1vbIjEJDTGhSQ2B3ddpcI= -go.uber.org/dig v1.8.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= +go.uber.org/dig v1.9.0 h1:pJTDXKEhRqBI8W7rU7kwT5EgyRZuSMVSFcZolOvKK9U= +go.uber.org/dig v1.9.0/go.mod h1:X34SnWGr8Fyla9zQNO2GSO2D+TIuqB14OS8JhYocIyw= go.uber.org/goleak v0.10.0 h1:G3eWbSNIskeRqtsN/1uI5B+eP73y3JUuBsv9AZjehb4= go.uber.org/goleak v0.10.0/go.mod h1:VCZuO8V8mFPlL0F5J5GK1rtHV3DrFcQ1R8ryq7FK0aI= go.uber.org/multierr v1.4.0 h1:f3WCSC2KzAcBXGATIxAB1E2XuCpNU255wNKZ505qi3E= diff --git a/inout.go b/inout.go index c51558631..72f86bb81 100644 --- a/inout.go +++ b/inout.go @@ -251,4 +251,15 @@ type In struct{ dig.In } // value groups require parameter and result structs to use fields with // different types: if a group of constructors each returns type T, parameter // structs consuming the group must use a field of type []T. +// +// To provide multiple values for a group from a result struct, produce a +// slice and use the `,flatten` option on the group tag. This indicates that +// each element in the slice should be injected into the group individually. +// +// type IntResult struct { +// fx.Out +// +// Handler []int `group:"server"` // Consume as [][]int +// Handler []int `group:"server,flatten"` // Consume as []int +// } type Out struct{ dig.Out } diff --git a/populate_test.go b/populate_test.go index 4ab90c7ba..8f2f88009 100644 --- a/populate_test.go +++ b/populate_test.go @@ -208,7 +208,7 @@ func TestPopulateErrors(t *testing.T) { { msg: "container pointer without fx.In", opt: Populate(&containerNoIn{}), - wantErr: "is not in the container", + wantErr: "missing type: fx_test.containerNoIn", }, { msg: "function", @@ -218,7 +218,7 @@ func TestPopulateErrors(t *testing.T) { { msg: "function pointer", opt: Populate(&fn), - wantErr: "is not in the container", + wantErr: "missing type: func()", }, { msg: "invalid last argument",