Skip to content

Commit 387470b

Browse files
fix: do not raise error if same provider is registered twice or more
1 parent 510df35 commit 387470b

5 files changed

Lines changed: 52 additions & 13 deletions

File tree

go.mod

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ module github.com/illuin-tech/goinject
22

33
go 1.24.0
44

5-
require github.com/stretchr/testify v1.10.0
5+
require github.com/stretchr/testify v1.11.1
66

77
require (
88
github.com/davecgh/go-spew v1.1.1 // indirect

go.sum

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb
44
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
55
github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA=
66
github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
7+
github.com/stretchr/testify v1.11.1 h1:7s2iGBzp5EwR7/aIZr8ao5+dra3wiQyKjjFuvgVKu7U=
8+
github.com/stretchr/testify v1.11.1/go.mod h1:wZwfW3scLgRK+23gO65QZefKpKQRnfz6sD981Nm4B6U=
79
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
810
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
911
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=

injector.go

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -19,21 +19,22 @@ type Injector struct {
1919

2020
// NewInjector builds up a new Injector out of a list of Modules with singleton scope
2121
func NewInjector(options ...Option) (*Injector, error) {
22-
mod := &configuration{
23-
bindings: make(map[*binding]bool),
24-
scopes: make(map[string]Scope),
22+
conf := &configuration{
23+
bindings: []*binding{},
24+
scopes: make(map[string]Scope),
25+
knownProviders: []*provideOption{},
2526
}
2627

27-
for _, o := range options {
28-
err := o.apply(mod)
28+
for _, option := range options {
29+
err := option.apply(conf)
2930
if err != nil {
3031
return nil, err
3132
}
3233
}
3334

3435
singletonScope := newSingletonScope()
35-
mod.scopes[Singleton] = singletonScope
36-
mod.scopes[PerLookUp] = newPerLookUpScope()
36+
conf.scopes[Singleton] = singletonScope
37+
conf.scopes[PerLookUp] = newPerLookUpScope()
3738

3839
injector := &Injector{
3940
bindings: make(map[reflect.Type]map[string][]*binding),
@@ -49,8 +50,8 @@ func NewInjector(options ...Option) (*Injector, error) {
4950
scope: Singleton,
5051
}
5152

52-
injector.scopes = mod.scopes
53-
for b := range mod.bindings {
53+
injector.scopes = conf.scopes
54+
for _, b := range conf.bindings {
5455
_, ok := injector.bindings[b.typeof]
5556
if !ok {
5657
injector.bindings[b.typeof] = make(map[string][]*binding)

injector_test.go

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,3 +685,31 @@ func TestInjectorConfigurationError(t *testing.T) {
685685
)
686686
})
687687
}
688+
689+
func TestNewInjectorShouldIgnoreMultipleBindings(t *testing.T) {
690+
provider := Provide(func() int { return 32 })
691+
692+
inj, err := NewInjector(
693+
provider,
694+
provider,
695+
)
696+
assert.Nil(t, err)
697+
err = inj.Invoke(context.Background(), func(val int) {
698+
assert.Equal(t, 32, val)
699+
})
700+
assert.Nil(t, err)
701+
}
702+
703+
func TestNewInjectorShouldIgnoreMultipleBindingsInDifferentModules(t *testing.T) {
704+
sharedModule := Module("shared", Provide(func() int { return 32 }))
705+
706+
inj, err := NewInjector(
707+
Module("module-A", sharedModule),
708+
Module("module-B", sharedModule),
709+
)
710+
assert.Nil(t, err)
711+
err = inj.Invoke(context.Background(), func(val int) {
712+
assert.Equal(t, 32, val)
713+
})
714+
assert.Nil(t, err)
715+
}

module.go

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,13 @@ package goinject
33
import (
44
"fmt"
55
"reflect"
6+
"slices"
67
)
78

89
type configuration struct {
9-
bindings map[*binding]bool
10-
scopes map[string]Scope
10+
bindings []*binding
11+
scopes map[string]Scope
12+
knownProviders []*provideOption
1113
}
1214

1315
// Option enable to configure the given injector
@@ -47,6 +49,12 @@ type provideOption struct {
4749
}
4850

4951
func (o *provideOption) apply(mod *configuration) error {
52+
if slices.Contains(mod.knownProviders, o) {
53+
// already registered, ignore
54+
return nil
55+
}
56+
mod.knownProviders = append(mod.knownProviders, o)
57+
5058
if o.constructor == nil {
5159
return newInjectorConfigurationError("cannot accept nil provider", nil)
5260
}
@@ -77,7 +85,7 @@ func (o *provideOption) apply(mod *configuration) error {
7785
}
7886
}
7987

80-
mod.bindings[b] = true
88+
mod.bindings = append(mod.bindings, b)
8189
return nil
8290
}
8391

0 commit comments

Comments
 (0)