mirror of
https://github.com/IBM/fp-go.git
synced 2025-08-10 22:31:32 +02:00
fix: experiment with doc links
Signed-off-by: Dr. Carsten Leue <carsten.leue@de.ibm.com>
This commit is contained in:
@@ -62,7 +62,7 @@ func generateMakeProvider(f *os.File, i int) {
|
|||||||
|
|
||||||
func generateMakeTokenWithDefault(f *os.File, i int) {
|
func generateMakeTokenWithDefault(f *os.File, i int) {
|
||||||
// non generic version
|
// non generic version
|
||||||
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependenciess\n", i, i)
|
fmt.Fprintf(f, "\n// MakeTokenWithDefault%d creates an [InjectionToken] with a default implementation with %d dependencies\n", i, i)
|
||||||
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
|
fmt.Fprintf(f, "func MakeTokenWithDefault%d[", i)
|
||||||
for j := 0; j < i; j++ {
|
for j := 0; j < i; j++ {
|
||||||
if j > 0 {
|
if j > 0 {
|
||||||
|
15
di/doc.go
15
di/doc.go
@@ -14,6 +14,21 @@
|
|||||||
// See the License for the specific language governing permissions and
|
// See the License for the specific language governing permissions and
|
||||||
// limitations under the License.
|
// limitations under the License.
|
||||||
|
|
||||||
|
// Package implements functions and data types supporting dependency injection patterns
|
||||||
|
//
|
||||||
|
// The fundamental building block is the concept of a [Dependency]. This describes the abstract concept of a function, service or value together with its type.
|
||||||
|
// Examples for dependencies can be as simple as configuration values such as the API URL for a service, the current username, a [Dependency] could be the map
|
||||||
|
// of the configuration environment, an http client or as complex as a service interface. Important is that a [Dependency] only defines the concept but
|
||||||
|
// not the implementation.
|
||||||
|
//
|
||||||
|
// The implementation of a [Dependency] is called a [Provider], the dependency of an `API URL` could e.g. be realized by a provider that consults the environment to read the information
|
||||||
|
// or a config file or simply hardcode it.
|
||||||
|
// In many cases the implementation of a [DIE.Provider] depends in turn on other [Dependency]s (but never directly on other [DIE.Provider]s), a provider for an `API URL` that reads
|
||||||
|
// the information from the environment would e.g. depend on a [Dependency] that represents this environment.
|
||||||
|
//
|
||||||
|
// It is the resposibility of the [DIE.InjectableFactory] to
|
||||||
|
//
|
||||||
|
// [Provider]: [github.com/IBM/fp-go/di/erasure.Provider]
|
||||||
package di
|
package di
|
||||||
|
|
||||||
//go:generate go run .. di --count 10 --filename gen.go
|
//go:generate go run .. di --count 10 --filename gen.go
|
||||||
|
@@ -115,6 +115,9 @@ func itemProviderFactory(fcts []ProviderFactory) ProviderFactory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MakeInjector creates an [InjectableFactory] based on a set of [Provider]s
|
// MakeInjector creates an [InjectableFactory] based on a set of [Provider]s
|
||||||
|
//
|
||||||
|
// The resulting [InjectableFactory] can then be used to retrieve service instances given their [Dependency]. The implementation
|
||||||
|
// makes sure to transitively resolve the required dependencies.
|
||||||
func MakeInjector(providers []Provider) InjectableFactory {
|
func MakeInjector(providers []Provider) InjectableFactory {
|
||||||
|
|
||||||
type Result = IOE.IOEither[error, any]
|
type Result = IOE.IOEither[error, any]
|
||||||
|
@@ -32,6 +32,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
type (
|
type (
|
||||||
|
// InjectableFactory is a factory function that can create an untyped instance of a service based on its [Dependency] identifier
|
||||||
InjectableFactory = func(Dependency) IOE.IOEither[error, any]
|
InjectableFactory = func(Dependency) IOE.IOEither[error, any]
|
||||||
ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any]
|
ProviderFactory = func(InjectableFactory) IOE.IOEither[error, any]
|
||||||
|
|
||||||
@@ -83,6 +84,8 @@ var (
|
|||||||
mergeMaps = R.UnionLastMonoid[int, any]()
|
mergeMaps = R.UnionLastMonoid[int, any]()
|
||||||
collectParams = R.CollectOrd[any, any](Int.Ord)(F.SK[int, any])
|
collectParams = R.CollectOrd[any, any](Int.Ord)(F.SK[int, any])
|
||||||
|
|
||||||
|
mapDeps = F.Curry2(A.MonadMap[Dependency, IOE.IOEither[error, any]])
|
||||||
|
|
||||||
handlers = map[int]handler{
|
handlers = map[int]handler{
|
||||||
Identity: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
Identity: func(mp paramIndex) func([]IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||||
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
return func(res []IOE.IOEither[error, any]) IOE.IOEither[error, paramValue] {
|
||||||
@@ -171,7 +174,7 @@ func MakeProviderFactory(
|
|||||||
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
|
fct func(param ...any) IOE.IOEither[error, any]) ProviderFactory {
|
||||||
|
|
||||||
return F.Flow3(
|
return F.Flow3(
|
||||||
F.Curry2(A.MonadMap[Dependency, IOE.IOEither[error, any]])(deps),
|
mapDeps(deps),
|
||||||
handleMapping(foldDeps(deps)),
|
handleMapping(foldDeps(deps)),
|
||||||
IOE.Chain(F.Unvariadic0(fct)),
|
IOE.Chain(F.Unvariadic0(fct)),
|
||||||
)
|
)
|
||||||
|
@@ -39,17 +39,17 @@ func eraseTuple[A, R any](f func(A) IOE.IOEither[error, R]) func(E.Either[error,
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
func eraseProviderFactory0[R any](f func() IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
func eraseProviderFactory0[R any](f IOE.IOEither[error, R]) func(params ...any) IOE.IOEither[error, any] {
|
||||||
return func(params ...any) IOE.IOEither[error, any] {
|
return func(params ...any) IOE.IOEither[error, any] {
|
||||||
return F.Pipe1(
|
return F.Pipe1(
|
||||||
f(),
|
f,
|
||||||
IOE.Map[error](F.ToAny[R]),
|
IOE.Map[error](F.ToAny[R]),
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeProviderFactory0[R any](
|
func MakeProviderFactory0[R any](
|
||||||
fct func() IOE.IOEither[error, R],
|
fct IOE.IOEither[error, R],
|
||||||
) DIE.ProviderFactory {
|
) DIE.ProviderFactory {
|
||||||
return DIE.MakeProviderFactory(
|
return DIE.MakeProviderFactory(
|
||||||
A.Empty[DIE.Dependency](),
|
A.Empty[DIE.Dependency](),
|
||||||
@@ -57,14 +57,14 @@ func MakeProviderFactory0[R any](
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeTokenWithDefault0 create a unique `InjectionToken` for a specific type with an attached default provider
|
// MakeTokenWithDefault0 creates a unique [InjectionToken] for a specific type with an attached default [DIE.Provider]
|
||||||
func MakeTokenWithDefault0[R any](name string, fct func() IOE.IOEither[error, R]) InjectionToken[R] {
|
func MakeTokenWithDefault0[R any](name string, fct IOE.IOEither[error, R]) InjectionToken[R] {
|
||||||
return MakeTokenWithDefault[R](name, MakeProviderFactory0(fct))
|
return MakeTokenWithDefault[R](name, MakeProviderFactory0(fct))
|
||||||
}
|
}
|
||||||
|
|
||||||
func MakeProvider0[R any](
|
func MakeProvider0[R any](
|
||||||
token InjectionToken[R],
|
token InjectionToken[R],
|
||||||
fct func() IOE.IOEither[error, R],
|
fct IOE.IOEither[error, R],
|
||||||
) DIE.Provider {
|
) DIE.Provider {
|
||||||
return DIE.MakeProvider(
|
return DIE.MakeProvider(
|
||||||
token,
|
token,
|
||||||
@@ -74,5 +74,5 @@ func MakeProvider0[R any](
|
|||||||
|
|
||||||
// ConstProvider simple implementation for a provider with a constant value
|
// ConstProvider simple implementation for a provider with a constant value
|
||||||
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
func ConstProvider[R any](token InjectionToken[R], value R) DIE.Provider {
|
||||||
return MakeProvider0[R](token, F.Constant(IOE.Of[error](value)))
|
return MakeProvider0[R](token, IOE.Of[error](value))
|
||||||
}
|
}
|
||||||
|
@@ -38,14 +38,12 @@ func TestSimpleProvider(t *testing.T) {
|
|||||||
|
|
||||||
var staticCount int
|
var staticCount int
|
||||||
|
|
||||||
staticValue := func(value string) func() IOE.IOEither[error, string] {
|
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||||
return func() IOE.IOEither[error, string] {
|
|
||||||
return func() E.Either[error, string] {
|
return func() E.Either[error, string] {
|
||||||
staticCount++
|
staticCount++
|
||||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var dynamicCount int
|
var dynamicCount int
|
||||||
|
|
||||||
@@ -82,14 +80,12 @@ func TestOptionalProvider(t *testing.T) {
|
|||||||
|
|
||||||
var staticCount int
|
var staticCount int
|
||||||
|
|
||||||
staticValue := func(value string) func() IOE.IOEither[error, string] {
|
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||||
return func() IOE.IOEither[error, string] {
|
|
||||||
return func() E.Either[error, string] {
|
return func() E.Either[error, string] {
|
||||||
staticCount++
|
staticCount++
|
||||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var dynamicCount int
|
var dynamicCount int
|
||||||
|
|
||||||
@@ -182,14 +178,12 @@ func TestEagerAndLazyProvider(t *testing.T) {
|
|||||||
|
|
||||||
var staticCount int
|
var staticCount int
|
||||||
|
|
||||||
staticValue := func(value string) func() IOE.IOEither[error, string] {
|
staticValue := func(value string) IOE.IOEither[error, string] {
|
||||||
return func() IOE.IOEither[error, string] {
|
|
||||||
return func() E.Either[error, string] {
|
return func() E.Either[error, string] {
|
||||||
staticCount++
|
staticCount++
|
||||||
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
return E.Of[error](fmt.Sprintf("Static based on [%s], at [%s]", value, time.Now()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
var dynamicCount int
|
var dynamicCount int
|
||||||
|
|
||||||
@@ -307,7 +301,7 @@ func TestTokenWithDefaultProvider(t *testing.T) {
|
|||||||
// token without a default
|
// token without a default
|
||||||
injToken1 := MakeToken[string]("Token1")
|
injToken1 := MakeToken[string]("Token1")
|
||||||
// token with a default
|
// token with a default
|
||||||
injToken2 := MakeTokenWithDefault0("Token2", F.Constant(IOE.Of[error]("Carsten")))
|
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
|
||||||
// dependency
|
// dependency
|
||||||
injToken3 := MakeToken[string]("Token3")
|
injToken3 := MakeToken[string]("Token3")
|
||||||
|
|
||||||
@@ -330,7 +324,7 @@ func TestTokenWithDefaultProvider(t *testing.T) {
|
|||||||
|
|
||||||
func TestTokenWithDefaultProviderAndOverride(t *testing.T) {
|
func TestTokenWithDefaultProviderAndOverride(t *testing.T) {
|
||||||
// token with a default
|
// token with a default
|
||||||
injToken2 := MakeTokenWithDefault0("Token2", F.Constant(IOE.Of[error]("Carsten")))
|
injToken2 := MakeTokenWithDefault0("Token2", IOE.Of[error]("Carsten"))
|
||||||
// dependency
|
// dependency
|
||||||
injToken3 := MakeToken[string]("Token3")
|
injToken3 := MakeToken[string]("Token3")
|
||||||
|
|
||||||
|
17
di/token.go
17
di/token.go
@@ -42,20 +42,21 @@ type InjectionToken[T any] interface {
|
|||||||
// Identity idenifies this dependency as a mandatory, required dependency, it will be resolved eagerly and injected as `T`.
|
// Identity idenifies this dependency as a mandatory, required dependency, it will be resolved eagerly and injected as `T`.
|
||||||
// If the dependency cannot be resolved, the resolution process fails
|
// If the dependency cannot be resolved, the resolution process fails
|
||||||
Identity() Dependency[T]
|
Identity() Dependency[T]
|
||||||
// Option identifies this dependency as optional, it will be resolved eagerly and injected as `O.Option[T]`.
|
// Option identifies this dependency as optional, it will be resolved eagerly and injected as [O.Option[T]].
|
||||||
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as `O.None[T]`
|
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as [O.None[T]]
|
||||||
Option() Dependency[O.Option[T]]
|
Option() Dependency[O.Option[T]]
|
||||||
// IOEither identifies this dependency as mandatory but it will be resolved lazily as a `IOE.IOEither[error, T]`. This
|
// IOEither identifies this dependency as mandatory but it will be resolved lazily as a [IOE.IOEither[error, T]]. This
|
||||||
// value is memoized to make sure the dependency is a singleton.
|
// value is memoized to make sure the dependency is a singleton.
|
||||||
// If the dependency cannot be resolved, the resolution process fails
|
// If the dependency cannot be resolved, the resolution process fails
|
||||||
IOEither() Dependency[IOE.IOEither[error, T]]
|
IOEither() Dependency[IOE.IOEither[error, T]]
|
||||||
// IOOption identifies this dependency as optional but it will be resolved lazily as a `IOO.IOOption[T]`. This
|
// IOOption identifies this dependency as optional but it will be resolved lazily as a [IOO.IOOption[T]]. This
|
||||||
// value is memoized to make sure the dependency is a singleton.
|
// value is memoized to make sure the dependency is a singleton.
|
||||||
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as the none value.
|
// If the dependency cannot be resolved, the resolution process continues and the dependency is represented as the none value.
|
||||||
IOOption() Dependency[IOO.IOOption[T]]
|
IOOption() Dependency[IOO.IOOption[T]]
|
||||||
}
|
}
|
||||||
|
|
||||||
// MultiInjectionToken uniquely identifies a dependency by giving it an Id, Type and name.
|
// MultiInjectionToken uniquely identifies a dependency by giving it an Id, Type and name that can have multiple implementations.
|
||||||
|
// Implementations are provided via the [MultiInjectionToken.Item] injection token.
|
||||||
type MultiInjectionToken[T any] interface {
|
type MultiInjectionToken[T any] interface {
|
||||||
// Container returns the injection token used to request an array of all provided items
|
// Container returns the injection token used to request an array of all provided items
|
||||||
Container() InjectionToken[[]T]
|
Container() InjectionToken[[]T]
|
||||||
@@ -146,7 +147,7 @@ func (m *multiInjectionToken[T]) Item() InjectionToken[T] {
|
|||||||
return m.item
|
return m.item
|
||||||
}
|
}
|
||||||
|
|
||||||
// makeToken create a unique `InjectionToken` for a specific type
|
// makeToken create a unique [InjectionToken] for a specific type
|
||||||
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.ProviderFactory]) InjectionToken[T] {
|
||||||
id := genId()
|
id := genId()
|
||||||
toIdentity := toType[T]()
|
toIdentity := toType[T]()
|
||||||
@@ -158,12 +159,12 @@ func makeInjectionToken[T any](name string, providerFactory O.Option[DIE.Provide
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeToken create a unique `InjectionToken` for a specific type
|
// MakeToken create a unique [InjectionToken] for a specific type
|
||||||
func MakeToken[T any](name string) InjectionToken[T] {
|
func MakeToken[T any](name string) InjectionToken[T] {
|
||||||
return makeInjectionToken[T](name, O.None[DIE.ProviderFactory]())
|
return makeInjectionToken[T](name, O.None[DIE.ProviderFactory]())
|
||||||
}
|
}
|
||||||
|
|
||||||
// MakeToken create a unique `InjectionToken` for a specific type
|
// MakeToken create a unique [InjectionToken] for a specific type
|
||||||
func MakeTokenWithDefault[T any](name string, providerFactory DIE.ProviderFactory) InjectionToken[T] {
|
func MakeTokenWithDefault[T any](name string, providerFactory DIE.ProviderFactory) InjectionToken[T] {
|
||||||
return makeInjectionToken[T](name, O.Of(providerFactory))
|
return makeInjectionToken[T](name, O.Of(providerFactory))
|
||||||
}
|
}
|
||||||
|
@@ -21,13 +21,12 @@ import (
|
|||||||
DI "github.com/IBM/fp-go/di"
|
DI "github.com/IBM/fp-go/di"
|
||||||
IOE "github.com/IBM/fp-go/ioeither"
|
IOE "github.com/IBM/fp-go/ioeither"
|
||||||
IOEH "github.com/IBM/fp-go/ioeither/http"
|
IOEH "github.com/IBM/fp-go/ioeither/http"
|
||||||
L "github.com/IBM/fp-go/lazy"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
// InjHttpClient is the injection token for the default http client
|
// InjHttpClient is the [DI.InjectionToken] for the [http.DefaultClient]
|
||||||
InjHttpClient = DI.MakeTokenWithDefault0("HTTP_CLIENT", L.Of(IOE.Of[error](http.DefaultClient)))
|
InjHttpClient = DI.MakeTokenWithDefault0("HTTP_CLIENT", IOE.Of[error](http.DefaultClient))
|
||||||
|
|
||||||
// InjClient is the injection token for the default [Client]
|
// InjClient is the [DI.InjectionToken] for the default [IOEH.Client]
|
||||||
InjClient = DI.MakeTokenWithDefault1("CLIENT", InjHttpClient.IOEither(), IOE.Map[error](IOEH.MakeClient))
|
InjClient = DI.MakeTokenWithDefault1("CLIENT", InjHttpClient.IOEither(), IOE.Map[error](IOEH.MakeClient))
|
||||||
)
|
)
|
||||||
|
Reference in New Issue
Block a user