Skip to content

Commit 08ad091

Browse files
sywhangabhinav
andauthored
Misc. fixes from #305 (#311)
* Misc. fixes from #305 This contains some miscellaneous fixes from additional feedback from #305. Notably: - Make provider resolution for parameter building iterate the other way around (from self to root) and break once a provider is found. - Rename appendLeafScopes to appendSubscopes. - Rename getScopesFromRoot to ancestors - Change getStoresFromRoot to use storesToRoot. Co-authored-by: Abhinav Gupta <mail@abhinavg.net> Co-authored-by: Abhinav Gupta <abg@uber.com>
1 parent 5e5a20d commit 08ad091

File tree

5 files changed

+67
-45
lines changed

5 files changed

+67
-45
lines changed

container.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,7 +111,9 @@ type containerStore interface {
111111
// type across all the Scopes that are in effect of this containerStore.
112112
getAllValueProviders(name string, t reflect.Type) []provider
113113

114-
getStoresFromRoot() []containerStore
114+
// Reports a list of stores (starting at this store) up to the root
115+
// store.
116+
storesToRoot() []containerStore
115117

116118
createGraph() *dot.Graph
117119

param.go

Lines changed: 17 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -146,36 +146,28 @@ func (pl paramList) Build(containerStore) (reflect.Value, error) {
146146
// to the underlying constructor.
147147
func (pl paramList) BuildList(c containerStore) ([]reflect.Value, error) {
148148
args := make([]reflect.Value, len(pl.Params))
149-
argsBuilt := make([]bool, len(pl.Params))
150-
allContainers := c.getStoresFromRoot()
149+
allContainers := c.storesToRoot()
151150
for i, p := range pl.Params {
152-
var err error
153-
var arg reflect.Value
154151
// iterate through the tree path of scopes.
152+
containerLoop:
155153
for _, c := range allContainers {
156-
if arg, err = p.Build(c); err == nil {
154+
arg, err := p.Build(c)
155+
if err == nil {
157156
args[i] = arg
158-
argsBuilt[i] = true
157+
break containerLoop
158+
}
159+
// If argument has successfully been built, it's possible
160+
// for these errors to occur in child scopes that don't
161+
// contain the given parameter type. We can safely ignore
162+
// these.
163+
// If it's an error other than missing types/dependencies,
164+
// this means some constructor returned an error that must
165+
// be reported.
166+
_, isErrMissingTypes := err.(errMissingTypes)
167+
_, isErrMissingDeps := err.(errMissingDependencies)
168+
if err != nil && !isErrMissingTypes && !isErrMissingDeps {
169+
return nil, err
159170
}
160-
}
161-
162-
// If an argument failed to build, that means none of the
163-
// scopes had the type. This should be reported.
164-
if !argsBuilt[i] {
165-
return nil, err
166-
}
167-
168-
// If argument has successfully been built, it's possible
169-
// for these errors to occur in child scopes that don't
170-
// contain the given parameter type. We can safely ignore
171-
// these.
172-
// If it's an error other than missing types/dependencies,
173-
// this means some constructor returned an error that must
174-
// be reported.
175-
_, isErrMissingTypes := err.(errMissingTypes)
176-
_, isErrMissingDeps := err.(errMissingDependencies)
177-
if err != nil && !isErrMissingTypes && !isErrMissingDeps {
178-
return nil, err
179171
}
180172
}
181173
return args, nil

provide.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -434,7 +434,7 @@ func (s *Scope) provide(ctor interface{}, opts provideOptions) (err error) {
434434
// take a snapshot of the current graph state before
435435
// we start making changes to it as we may need to
436436
// undo them upon encountering errors.
437-
allScopes := s.appendLeafScopes(nil)
437+
allScopes := s.appendSubscopes(nil)
438438
for _, s := range allScopes {
439439
s := s
440440
s.gh.Snapshot()

scope.go

Lines changed: 11 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -115,34 +115,29 @@ func (s *Scope) Scope(name string, opts ...ScopeOption) *Scope {
115115
return child
116116
}
117117

118-
// getScopesFromRoot returns a list of Scopes from the root Container
119-
// until the current Scope.
120-
func (s *Scope) getScopesFromRoot() []*Scope {
118+
// ancestors returns a list of scopes of ancestors of this scope up to the
119+
// root. The scope at at index 0 is this scope itself.
120+
func (s *Scope) ancestors() []*Scope {
121121
var scopes []*Scope
122122
for s := s; s != nil; s = s.parentScope {
123123
scopes = append(scopes, s)
124124
}
125-
for i, j := 0, len(scopes)-1; i < j; i, j = i+1, j-1 {
126-
scopes[i], scopes[j] = scopes[j], scopes[i]
127-
}
128125
return scopes
129126
}
130127

131-
func (s *Scope) appendLeafScopes(dest []*Scope) []*Scope {
128+
func (s *Scope) appendSubscopes(dest []*Scope) []*Scope {
132129
dest = append(dest, s)
133130
for _, cs := range s.childScopes {
134-
dest = cs.appendLeafScopes(dest)
131+
dest = cs.appendSubscopes(dest)
135132
}
136133
return dest
137134
}
138135

139-
func (s *Scope) getStoresFromRoot() []containerStore {
140-
var stores []containerStore
141-
for s := s; s != nil; s = s.parentScope {
142-
stores = append(stores, s)
143-
}
144-
for i, j := 0, len(stores)-1; i < j; i, j = i+1, j-1 {
145-
stores[i], stores[j] = stores[j], stores[i]
136+
func (s *Scope) storesToRoot() []containerStore {
137+
scopes := s.ancestors()
138+
stores := make([]containerStore, len(scopes))
139+
for i, s := range scopes {
140+
stores[i] = s
146141
}
147142
return stores
148143
}
@@ -207,7 +202,7 @@ func (s *Scope) getAllValueProviders(name string, t reflect.Type) []provider {
207202
}
208203

209204
func (s *Scope) getAllProviders(k key) []provider {
210-
allScopes := s.getScopesFromRoot()
205+
allScopes := s.ancestors()
211206
var providers []provider
212207
for _, scope := range allScopes {
213208
providers = append(providers, scope.getProviders(k)...)

scope_test.go

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,8 @@ func TestScopedOperations(t *testing.T) {
3636
s2 := s1.Scope("child2")
3737
s3 := s2.Scope("child2")
3838

39-
assert.Equal(t, []containerStore{c.scope, s1, s2, s3}, s3.getStoresFromRoot())
40-
assert.Equal(t, []*Scope{c.scope, s1, s2, s3}, s3.getScopesFromRoot())
39+
assert.Equal(t, []containerStore{s3, s2, s1, c.scope}, s3.storesToRoot())
40+
assert.Equal(t, []*Scope{s3, s2, s1, c.scope}, s3.ancestors())
4141
})
4242

4343
t.Run("private provides", func(t *testing.T) {
@@ -130,6 +130,39 @@ func TestScopedOperations(t *testing.T) {
130130
assert.NoError(t, scope.Invoke(func(a *A) {}))
131131
}
132132
})
133+
134+
t.Run("parent shares values with children", func(t *testing.T) {
135+
type (
136+
T1 struct{ s string }
137+
T2 struct{}
138+
)
139+
140+
parent := New()
141+
142+
require.NoError(t, parent.Provide(func() T1 {
143+
assert.Fail(t, "parent should not be called")
144+
return T1{"parent"}
145+
}))
146+
147+
child := parent.Scope("child")
148+
149+
var childCalled bool
150+
defer func() {
151+
assert.True(t, childCalled, "child constructor must be called")
152+
}()
153+
require.NoError(t, child.Provide(func() T1 {
154+
childCalled = true
155+
return T1{"child"}
156+
}))
157+
158+
require.NoError(t, child.Provide(func(v T1) T2 {
159+
assert.Equal(t, "child", v.s,
160+
"value should be built by child")
161+
return T2{}
162+
}))
163+
164+
require.NoError(t, child.Invoke(func(T2) {}))
165+
})
133166
}
134167

135168
func TestScopeFailures(t *testing.T) {

0 commit comments

Comments
 (0)