feat: Support singleton providers (#501)

* feat: Support singleton providers

This change adds support for provider functions that are
not reinvoked even if requested by multiple other providers.
Instead, their value is cached and reused between invocations.

To make this possible, we change how bindings are stored:
instead of just a function reference, we now store a binding object
which records whether the binding is a singleton,
and records the resolved singleton value (if any).

Resolves #500

* refac(bindings): hide singleton status

Don't require callAnyFunction to be aware of
whether a binding is a singleton or not.
This commit is contained in:
Abhinav Gupta
2025-02-16 22:44:03 -08:00
committed by GitHub
parent 7f94c902b9
commit 3b9af5bdce
4 changed files with 140 additions and 16 deletions
+37
View File
@@ -119,6 +119,43 @@ func TestBindToProvider(t *testing.T) {
assert.True(t, cli.Called)
}
func TestBindSingletonProvider(t *testing.T) {
type (
Connection struct{}
ClientA struct{ conn *Connection }
ClientB struct{ conn *Connection }
)
var numConnections int
newConnection := func() *Connection {
numConnections++
return &Connection{}
}
var cli struct{}
app, err := New(&cli,
BindSingletonProvider(newConnection),
BindToProvider(func(conn *Connection) *ClientA {
return &ClientA{conn: conn}
}),
BindToProvider(func(conn *Connection) *ClientB {
return &ClientB{conn: conn}
}),
)
assert.NoError(t, err)
ctx, err := app.Parse([]string{})
assert.NoError(t, err)
_, err = ctx.Call(func(a *ClientA, b *ClientB) {
assert.NotZero(t, a.conn)
assert.NotZero(t, b.conn)
assert.Equal(t, 1, numConnections, "expected newConnection to be called only once")
})
assert.NoError(t, err)
}
func TestFlagNamer(t *testing.T) {
var cli struct {
SomeFlag string