You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

124 lines
5.0 KiB

2 years ago
  1. //
  2. // Copyright © 2019 Swinject Contributors. All rights reserved.
  3. //
  4. /// The `Assembler` provides a means to build a container via `Assembly` instances.
  5. public final class Assembler {
  6. /// the container that each assembly will build its `Service` definitions into
  7. private let container: Container
  8. /// expose the container as a resolver so `Service` registration only happens within an assembly
  9. public var resolver: Resolver {
  10. return container
  11. }
  12. /// Will create an empty `Assembler`
  13. ///
  14. /// - parameter container: the baseline container
  15. ///
  16. public init(container: Container? = Container()) {
  17. self.container = container!
  18. }
  19. /// Will create an empty `Assembler`
  20. ///
  21. /// - parameter parentAssembler: the baseline assembler
  22. /// - parameter defaultObjectScope: default object scope for container
  23. /// - parameter behaviors: list of behaviors to be added to the container
  24. public init(parentAssembler: Assembler?, defaultObjectScope: ObjectScope = .graph, behaviors: [Behavior] = []) {
  25. container = Container(
  26. parent: parentAssembler?.container,
  27. defaultObjectScope: defaultObjectScope,
  28. behaviors: behaviors
  29. )
  30. }
  31. /// Will create a new `Assembler` with the given `Assembly` instances to build a `Container`
  32. ///
  33. /// - parameter assemblies: the list of assemblies to build the container from
  34. /// - parameter container: the baseline container
  35. ///
  36. @available(*, deprecated, message: "Use not throwing alternative: init(_:, container:)")
  37. public convenience init(assemblies: [Assembly], container: Container? = Container()) throws {
  38. if let container = container {
  39. self.init(assemblies, container: container)
  40. } else {
  41. self.init(assemblies)
  42. }
  43. }
  44. /// Will create a new `Assembler` with the given `Assembly` instances to build a `Container`
  45. ///
  46. /// - parameter assemblies: the list of assemblies to build the container from
  47. /// - parameter container: the baseline container
  48. ///
  49. public init(_ assemblies: [Assembly], container: Container = Container()) {
  50. self.container = container
  51. run(assemblies: assemblies)
  52. }
  53. /// Will create a new `Assembler` with the given `Assembly` instances to build a `Container`
  54. ///
  55. /// - parameter assemblies: the list of assemblies to build the container from
  56. /// - parameter parentAssembler: the baseline assembler
  57. ///
  58. @available(*, deprecated, message: "Use not throwing alternative: init(_:, parent:)")
  59. public convenience init(assemblies: [Assembly], parentAssembler: Assembler?) throws {
  60. self.init(_: assemblies, parent: parentAssembler)
  61. }
  62. /// Will create a new `Assembler` with the given `Assembly` instances to build a `Container`
  63. ///
  64. /// - parameter assemblies: the list of assemblies to build the container from
  65. /// - parameter parent: the baseline assembler
  66. /// - parameter defaultObjectScope: default object scope for container
  67. /// - parameter behaviors: list of behaviors to be added to the container
  68. public init(
  69. _ assemblies: [Assembly],
  70. parent: Assembler?,
  71. defaultObjectScope: ObjectScope = .graph,
  72. behaviors: [Behavior] = []
  73. ) {
  74. container = Container(parent: parent?.container, defaultObjectScope: defaultObjectScope, behaviors: behaviors)
  75. run(assemblies: assemblies)
  76. }
  77. /// Will apply the assembly to the container. This is useful if you want to lazy load an assembly into the
  78. /// assembler's container.
  79. ///
  80. /// If this assembly type is load aware, the loaded hook will be invoked right after the container has assembled
  81. /// since after each call to `addAssembly` the container is fully loaded in its current state. If you wish to
  82. /// lazy load several assemblies that have interdependencies between each other use `appyAssemblies`
  83. ///
  84. /// - parameter assembly: the assembly to apply to the container
  85. ///
  86. public func apply(assembly: Assembly) {
  87. run(assemblies: [assembly])
  88. }
  89. /// Will apply the assemblies to the container. This is useful if you want to lazy load several assemblies into the
  90. /// assembler's container
  91. ///
  92. /// If this assembly type is load aware, the loaded hook will be invoked right after the container has assembled
  93. /// since after each call to `addAssembly` the container is fully loaded in its current state.
  94. ///
  95. /// - parameter assemblies: the assemblies to apply to the container
  96. ///
  97. public func apply(assemblies: [Assembly]) {
  98. run(assemblies: assemblies)
  99. }
  100. // MARK: Private
  101. private func run(assemblies: [Assembly]) {
  102. // build the container from each assembly
  103. for assembly in assemblies {
  104. assembly.assemble(container: container)
  105. }
  106. // inform all of the assemblies that the container is loaded
  107. for assembly in assemblies {
  108. assembly.loaded(resolver: resolver)
  109. }
  110. }
  111. }