From 9a46a4b50b776fd59170fcac3d8542109feef50f Mon Sep 17 00:00:00 2001 From: "coderabbitai[bot]" <136622811+coderabbitai[bot]@users.noreply.github.com> Date: Mon, 24 Mar 2025 22:36:06 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=93=9D=20Add=20docstrings=20to=20`before-?= =?UTF-8?q?callback`?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Docstrings generation was requested by @moisesvega. * https://github.com/uber-go/dig/pull/431#issuecomment-2749513335 The following files were modified: * `before_callback.go` * `constructor.go` * `decorate.go` --- before_callback.go | 95 ++++++++++++++++++++++++++++++++++++++++++++++ constructor.go | 42 ++++++++++++-------- decorate.go | 37 ++++++++++++------ 3 files changed, 148 insertions(+), 26 deletions(-) create mode 100644 before_callback.go diff --git a/before_callback.go b/before_callback.go new file mode 100644 index 00000000..c499a3c3 --- /dev/null +++ b/before_callback.go @@ -0,0 +1,95 @@ +// Copyright (c) 2023 Uber Technologies, Inc. +// +// Permission is hereby granted, free of charge, to any person obtaining a copy +// of this software and associated documentation files (the "Software"), to deal +// in the Software without restriction, including without limitation the rights +// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +// copies of the Software, and to permit persons to whom the Software is +// furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in +// all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +// THE SOFTWARE. + +package dig + +// BeforeCallbackInfo contains information about a provided function or decorator +// called by Dig, and is passed to a [BeforeCallback] registered with +// [WithProviderBeforeCallback] or [WithDecoratorBeforeCallback]. +type BeforeCallbackInfo struct { + // Name is the name of the function in the format: + // . + Name string +} + +// BeforeCallback is a function that can be registered with a provided function +// or decorator with [WithCallback] to cause it to be called before the +// provided function or decorator is run. +type BeforeCallback func(bci BeforeCallbackInfo) + +// WithProviderBeforeCallback returns a [ProvideOption] which has Dig call +// the passed in [BeforeCallback] before the corresponding constructor begins running. +// +// For example, the following prints a message +// before "myConstructor" is called: +// +// c := dig.New() +// myCallback := func(bci BeforeCallbackInfo) { +// fmt.Printf("%q started", bci.Name) +// } +// c.Provide(myConstructor, WithProviderBeforeCallback(myCallback)), +// +// BeforeCallbacks can also be specified for Decorators with [WithDecoratorBeforeCallback]. +// +// WithProviderBeforeCallback returns a ProvideOption that registers the specified BeforeCallback to be invoked before a constructor function is executed. The provided callback receives a BeforeCallbackInfo detailing the target function's fully-qualified name in the format ".". +func WithProviderBeforeCallback(callback BeforeCallback) ProvideOption { + return withBeforeCallbackOption{ + callback: callback, + } +} + +// WithDecoratorBeforeCallback returns a [DecorateOption] which has Dig call +// the passed in [BeforeCallback] before the corresponding decorator begins running. +// +// For example, the following prints a message +// before "myDecorator" is called: +// +// c := dig.New() +// myCallback := func(bci BeforeCallbackInfo) { +// fmt.Printf("%q started", bci.Name) +// } +// c.Decorate(myDecorator, WithDecoratorBeforeCallback(myCallback)), +// +// BeforeCallbacks can also be specified for Constructors with [WithProviderBeforeCallback]. +// +// WithDecoratorBeforeCallback returns a DecorateOption that registers the given BeforeCallback to be executed before a decorator is applied. +// The callback is invoked with a BeforeCallbackInfo that includes the name of the target decorator. +func WithDecoratorBeforeCallback(callback BeforeCallback) DecorateOption { + return withBeforeCallbackOption{ + callback: callback, + } +} + +type withBeforeCallbackOption struct { + callback BeforeCallback +} + +var ( + _ ProvideOption = withBeforeCallbackOption{} + _ DecorateOption = withBeforeCallbackOption{} +) + +func (o withBeforeCallbackOption) applyProvideOption(po *provideOptions) { + po.BeforeCallback = o.callback +} + +func (o withBeforeCallbackOption) apply(do *decorateOptions) { + do.BeforeCallback = o.callback +} diff --git a/constructor.go b/constructor.go index adec5fd5..47cfb7f1 100644 --- a/constructor.go +++ b/constructor.go @@ -66,18 +66,23 @@ type constructorNode struct { // Callback for this provided function, if there is one. callback Callback + + // BeforeCallback for this provided function, if there is one. + beforeCallback BeforeCallback } type constructorOptions struct { // If specified, all values produced by this constructor have the provided name // belong to the specified value group or implement any of the interfaces. - ResultName string - ResultGroup string - ResultAs []interface{} - Location *digreflect.Func - Callback Callback + ResultName string + ResultGroup string + ResultAs []interface{} + Location *digreflect.Func + Callback Callback + BeforeCallback BeforeCallback } +// newConstructorNode creates a new constructor node for the dependency injection graph. It uses reflection to inspect the provided constructor function, initializing its parameter and result lists with the given options (such as result naming, grouping, and type assertions). If no location is provided in the options, the constructor’s location is automatically determined. The new node is associated with both the current and original scopes and is configured with callbacks—including an optional pre-callback—to be executed during dependency resolution. An error is returned if the initialization of the parameter or result lists fails. func newConstructorNode(ctor interface{}, s *Scope, origS *Scope, opts constructorOptions) (*constructorNode, error) { cval := reflect.ValueOf(ctor) ctype := cval.Type() @@ -106,16 +111,17 @@ func newConstructorNode(ctor interface{}, s *Scope, origS *Scope, opts construct } n := &constructorNode{ - ctor: ctor, - ctype: ctype, - location: location, - id: dot.CtorID(cptr), - paramList: params, - resultList: results, - orders: make(map[*Scope]int), - s: s, - origS: origS, - callback: opts.Callback, + ctor: ctor, + ctype: ctype, + location: location, + id: dot.CtorID(cptr), + paramList: params, + resultList: results, + orders: make(map[*Scope]int), + s: s, + origS: origS, + callback: opts.Callback, + beforeCallback: opts.BeforeCallback, } s.newGraphNode(n, n.orders) return n, nil @@ -160,6 +166,12 @@ func (n *constructorNode) Call(c containerStore) (err error) { } } + if n.beforeCallback != nil { + n.beforeCallback(BeforeCallbackInfo{ + Name: fmt.Sprintf("%v.%v", n.location.Package, n.location.Name), + }) + } + if n.callback != nil { start := c.clock().Now() // Wrap in separate func to include PanicErrors diff --git a/decorate.go b/decorate.go index f4c6be18..d2f19c0b 100644 --- a/decorate.go +++ b/decorate.go @@ -68,8 +68,16 @@ type decoratorNode struct { // Callback for this decorator, if there is one. callback Callback + + // BeforeCallback for this decorator, if there is one + beforeCallback BeforeCallback } +// newDecoratorNode creates a new decorator node for the given decorator function, scope, and decoration options. +// +// It uses reflection to extract type information and a unique identifier from the decorator function, constructs the necessary +// parameter and result lists, and initializes the node with any specified callbacks, including a pre-execution callback if provided. +// An error is returned if initialization of the parameter or result lists fails. func newDecoratorNode(dcor interface{}, s *Scope, opts decorateOptions) (*decoratorNode, error) { dval := reflect.ValueOf(dcor) dtype := dval.Type() @@ -86,15 +94,16 @@ func newDecoratorNode(dcor interface{}, s *Scope, opts decorateOptions) (*decora } n := &decoratorNode{ - dcor: dcor, - dtype: dtype, - id: dot.CtorID(dptr), - location: digreflect.InspectFunc(dcor), - orders: make(map[*Scope]int), - params: pl, - results: rl, - s: s, - callback: opts.Callback, + dcor: dcor, + dtype: dtype, + id: dot.CtorID(dptr), + location: digreflect.InspectFunc(dcor), + orders: make(map[*Scope]int), + params: pl, + results: rl, + s: s, + callback: opts.Callback, + beforeCallback: opts.BeforeCallback, } return n, nil } @@ -120,6 +129,11 @@ func (n *decoratorNode) Call(s containerStore) (err error) { Reason: err, } } + if n.beforeCallback != nil { + n.beforeCallback(BeforeCallbackInfo{ + Name: fmt.Sprintf("%v.%v", n.location.Package, n.location.Name), + }) + } if n.callback != nil { start := s.clock().Now() @@ -162,8 +176,9 @@ type DecorateOption interface { } type decorateOptions struct { - Info *DecorateInfo - Callback Callback + Info *DecorateInfo + Callback Callback + BeforeCallback BeforeCallback } // FillDecorateInfo is a DecorateOption that writes info on what Dig was