Skip to content

Commit

Permalink
Built-in Assembly traversal
Browse files Browse the repository at this point in the history
  • Loading branch information
Jonathan Crooke committed Jan 23, 2021
1 parent d204ced commit 95f085e
Show file tree
Hide file tree
Showing 5 changed files with 104 additions and 5 deletions.
19 changes: 16 additions & 3 deletions Sources/Assembler.swift
Original file line number Diff line number Diff line change
Expand Up @@ -113,12 +113,25 @@ public final class Assembler {
private func run(assemblies: [Assembly]) {
// build the container from each assembly
for assembly in assemblies {
assembly.assemble(container: container)
assemble(assembly)
}

// inform all of the assemblies that the container is loaded
for assembly in assemblies {
assembly.loaded(resolver: resolver)
loaded(assembly)
}
}

private func assemble(_ assembly: Assembly) {
for child in assembly.children {
assemble(child)
}
assembly.assemble(container: container)
}

private func loaded(_ assembly: Assembly) {
for child in assembly.children {
loaded(child)
}
assembly.loaded(resolver: resolver)
}
}
12 changes: 12 additions & 0 deletions Sources/Assembly.swift
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,22 @@ public protocol Assembly {
/// - parameter resolver: the resolver that can resolve instances from the built container
///
func loaded(resolver: Resolver)

/// Provides a hook to allow `Assembler` to traverse down an Assembly tree. Child `Assembly` instances
/// are automatically assembled and any `loaded(...)` hooks are called in depth-first order
///
/// - parameter container: the container provided by the `Assembler`
///
var children: [Assembly] { get }
}

public extension Assembly {
func loaded(resolver _: Resolver) {
// no-op
}

var children: [Assembly] {
// no-op (empty children)
[]
}
}
12 changes: 10 additions & 2 deletions Swinject.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,10 @@
FED7D8B8C74876D03B5D09DE /* Assembler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 944B981A9157833AC3397B4A /* Assembler.swift */; };
FF222640214C9F4DA56130C4 /* InstanceStorage.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3B7688D6F1E3466891D0582E /* InstanceStorage.swift */; };
FF9DCB0AB20B0DBBE79451BB /* BehaviorFakes.swift in Sources */ = {isa = PBXBuildFile; fileRef = BEF07245CC462D98868097A3 /* BehaviorFakes.swift */; };
FFEB22D425BC935500EC89A1 /* NestedAssemblers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEB22D325BC935500EC89A1 /* NestedAssemblers.swift */; };
FFEB22D525BC935500EC89A1 /* NestedAssemblers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEB22D325BC935500EC89A1 /* NestedAssemblers.swift */; };
FFEB22D625BC935500EC89A1 /* NestedAssemblers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEB22D325BC935500EC89A1 /* NestedAssemblers.swift */; };
FFEB22D725BC935500EC89A1 /* NestedAssemblers.swift in Sources */ = {isa = PBXBuildFile; fileRef = FFEB22D325BC935500EC89A1 /* NestedAssemblers.swift */; };
/* End PBXBuildFile section */

/* Begin PBXContainerItemProxy section */
Expand Down Expand Up @@ -383,6 +387,7 @@
F388AD8E55D8C6F1E31D0522 /* FunctionType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FunctionType.swift; sourceTree = "<group>"; };
FCC59458E04C20587D870946 /* BasicAssembly.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = BasicAssembly.swift; sourceTree = "<group>"; };
FFBC1F44A2B361CB169F7B66 /* Animal.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Animal.swift; sourceTree = "<group>"; };
FFEB22D325BC935500EC89A1 /* NestedAssemblers.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = NestedAssemblers.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */

/* Begin PBXFrameworksBuildPhase section */
Expand Down Expand Up @@ -436,6 +441,7 @@
FFBC1F44A2B361CB169F7B66 /* Animal.swift */,
1525F92CDAA706A848343E2B /* AssemblerSpec.swift */,
FCC59458E04C20587D870946 /* BasicAssembly.swift */,
FFEB22D325BC935500EC89A1 /* NestedAssemblers.swift */,
BEF07245CC462D98868097A3 /* BehaviorFakes.swift */,
47328731EED63322AD76FB3A /* Circularity.swift */,
2C662DAE2FD2FCCA8585DB89 /* ContainerSpec.Arguments.swift */,
Expand Down Expand Up @@ -768,8 +774,6 @@
isa = PBXProject;
attributes = {
LastUpgradeCheck = 1200;
TargetAttributes = {
};
};
buildConfigurationList = 0102B3F56FB5455C665EC043 /* Build configuration list for PBXProject "Swinject" */;
compatibilityVersion = "Xcode 10.0";
Expand Down Expand Up @@ -953,6 +957,7 @@
229E0EAD0D8413D4CA67094C /* ContainerSpec.DebugHelper.swift in Sources */,
B3A1A6E559CC128BF501EC1D /* ContainerSpec.GraphCaching.swift in Sources */,
2A207632400E46F722193C7E /* ContainerSpec.TypeForwarding.swift in Sources */,
FFEB22D425BC935500EC89A1 /* NestedAssemblers.swift in Sources */,
A9E5D5915FE433CD1DCD0022 /* ContainerSpec.swift in Sources */,
1276420B3D3ED5ACFC2C5B4F /* EmploymentAssembly.swift in Sources */,
0266A3114C82246F18B52860 /* Food.swift in Sources */,
Expand Down Expand Up @@ -984,6 +989,7 @@
499ADF9E7F4ADEEB5465FFB6 /* ContainerSpec.DebugHelper.swift in Sources */,
50FC209AE23CD1E502149C5C /* ContainerSpec.GraphCaching.swift in Sources */,
2AED444F7141B101091A1464 /* ContainerSpec.TypeForwarding.swift in Sources */,
FFEB22D525BC935500EC89A1 /* NestedAssemblers.swift in Sources */,
07C2E78624A40118D0316CB6 /* ContainerSpec.swift in Sources */,
75A776D4072BCF74F298D818 /* EmploymentAssembly.swift in Sources */,
44676A0D0399F323A31E0451 /* Food.swift in Sources */,
Expand Down Expand Up @@ -1015,6 +1021,7 @@
82A930EA09492BAFE7D4D2DF /* ContainerSpec.DebugHelper.swift in Sources */,
FD72CBB5F6A75CE6C785058E /* ContainerSpec.GraphCaching.swift in Sources */,
BB35F3F717A09AD398FCC67A /* ContainerSpec.TypeForwarding.swift in Sources */,
FFEB22D725BC935500EC89A1 /* NestedAssemblers.swift in Sources */,
1BD861CA392B1E63D249906B /* ContainerSpec.swift in Sources */,
3A41F4B375C1CE29A75F6AE9 /* EmploymentAssembly.swift in Sources */,
115515373F266C35E8DBE724 /* Food.swift in Sources */,
Expand Down Expand Up @@ -1046,6 +1053,7 @@
4CC5158454FA6586C84AB160 /* ContainerSpec.DebugHelper.swift in Sources */,
2DF02DA2EB1C70640DCC315D /* ContainerSpec.GraphCaching.swift in Sources */,
4077A7732A2412CBB9E8A759 /* ContainerSpec.TypeForwarding.swift in Sources */,
FFEB22D625BC935500EC89A1 /* NestedAssemblers.swift in Sources */,
41084A2F24BB4222CCFFAD27 /* ContainerSpec.swift in Sources */,
1613AE7671758A85F760C5DF /* EmploymentAssembly.swift in Sources */,
4736BF9B29704061B29BFACD /* Food.swift in Sources */,
Expand Down
29 changes: 29 additions & 0 deletions Tests/SwinjectTests/AssemblerSpec.swift
Original file line number Diff line number Diff line change
Expand Up @@ -325,5 +325,34 @@ class AssemblerSpec: QuickSpec {
expect(spy.entries).to(haveCount(1))
}
}

describe("Nested Assemblers") {
it("assembles and calls loaded depth-first") {
let container = Container()

let assemble = NestedAssembly.ArrayType()
let loaded = NestedAssembly.ArrayType()

container.register(
NestedAssembly.ArrayType.self,
name: NestedAssembly.Constants.assemble
) { _ in assemble }
.inObjectScope(.container)
container.register(
NestedAssembly.ArrayType.self,
name: NestedAssembly.Constants.loaded
) { _ in loaded }
.inObjectScope(.container)

let d = NestedAssembly(name: "d", children: [])
let c = NestedAssembly(name: "c", children: [d])
let b = NestedAssembly(name: "b", children: [])
let a = NestedAssembly(name: "a", children: [b, c])

_ = Assembler([a], container: container)
expect(assemble).to(equal(["b", "d", "c", "a"]))
expect(loaded).to(equal(["b", "d", "c", "a"]))
}
}
}
}
37 changes: 37 additions & 0 deletions Tests/SwinjectTests/NestedAssemblers.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
//
// Copyright © 2021 Swinject Contributors. All rights reserved.
//

import Swinject
import Foundation

struct NestedAssembly: Assembly {

typealias ArrayType = NSMutableArray

enum Constants {
static let assemble = "assemble"
static let loaded = "loaded"
}

struct Logger {
let name: String
let array = ArrayType()
}

let name: String
let children: [Assembly]

init(name: String, children: [Assembly]) {
self.name = name
self.children = children
}

func assemble(container: Container) {
container.resolve(ArrayType.self, name: Constants.assemble)?.add(name)
}

func loaded(resolver: Resolver) {
resolver.resolve(ArrayType.self, name: Constants.loaded)?.add(name)
}
}

0 comments on commit 95f085e

Please sign in to comment.