diff --git a/decorate.go b/decorate.go index 5cc500d7..c684bed7 100644 --- a/decorate.go +++ b/decorate.go @@ -83,7 +83,9 @@ func newDecoratorNode(dcor interface{}, s *Scope, opts decorateOptions) (*decora return nil, err } - rl, err := newResultList(dtype, resultOptions{}) + rl, err := newResultList(dtype, resultOptions{ + Name: opts.Name, + }) if err != nil { return nil, err } @@ -171,11 +173,43 @@ type DecorateOption interface { } type decorateOptions struct { + Name string Info *DecorateInfo Callback Callback BeforeCallback BeforeCallback } +// Name is a ProvideOption that specifies that all values produced by a +// constructor should have the given name. See also the package documentation +// about Named Values. +// +// Given, +// +// func NewReadOnlyConnection(...) (*Connection, error) +// func NewReadWriteConnection(...) (*Connection, error) +// +// The following will provide two connections to the container: one under the +// name "ro" and the other under the name "rw". +// +// c.Provide(NewReadOnlyConnection, dig.Name("ro")) +// c.Provide(NewReadWriteConnection, dig.Name("rw")) +// +// This option cannot be provided for constructors which produce result +// objects. +func DecorateName(name string) DecorateOption { + return decorateNameOption(name) +} + +type decorateNameOption string + +func (o decorateNameOption) String() string { + return fmt.Sprintf("DecorateName(%q)", string(o)) +} + +func (o decorateNameOption) apply(opt *decorateOptions) { + opt.Name = string(o) +} + // FillDecorateInfo is a DecorateOption that writes info on what Dig was // able to get out of the provided decorator into the provided DecorateInfo. func FillDecorateInfo(info *DecorateInfo) DecorateOption { diff --git a/decorate_test.go b/decorate_test.go index 611a0f1c..06ed52a8 100644 --- a/decorate_test.go +++ b/decorate_test.go @@ -81,6 +81,30 @@ func TestDecorateSuccess(t *testing.T) { assert.Equal(t, "*dig_test.A", info.Outputs[0].String()) }) + t.Run("simple decorate with name", func(t *testing.T) { + t.Parallel() + type A struct { + name string + } + + c := digtest.New(t) + c.RequireProvide(func() *A { return &A{name: "A"} }, dig.Name("a")) + + type B struct { + dig.In + A *A `name:"a"` + } + + c.RequireInvoke(func(b B) { + assert.Equal(t, "A", b.A.name, "expected name to not be decorated yet.") + }) + + c.RequireDecorate(func(b B) *A { return &A{name: b.A.name + "'"} }, dig.DecorateName("a")) + c.RequireInvoke(func(b B) { + assert.Equal(t, "A'", b.A.name, "expected name to equal decorated name.") + }) + }) + t.Run("simple decorate a provider from child scope", func(t *testing.T) { t.Parallel() type A struct {