// // DependencyRegistering.swift // // // Created by Jan Schwarz on 25.03.2021. // import Foundation /// A type that is able to register a dependency public protocol DependencyRegistering { /// Factory closure that instantiates the required dependency typealias Factory = (DependencyResolving) -> Dependency /// Register a dependency /// /// - Parameters: /// - type: Type of the dependency to register /// - scope: Scope of the dependency. If `.new` is used, the `factory` closure is called on each `resolve` call. If `.shared` is used, the `factory` closure is called only the first time, the instance is cached and it is returned for all subsequent `resolve` calls, i.e. it is a singleton /// - factory: Closure that is called when the dependency is being resolved func register(type: Dependency.Type, in scope: DependencyScope, factory: @escaping Factory) } // MARK: Overloaded factory methods public extension DependencyRegistering { /// Default ``DependencyScope`` value /// /// The default value is `shared` static var defaultScope: DependencyScope { DependencyScope.shared } /// Register a dependency in the default ``DependencyScope``, i.e. in the `shared` scope /// /// - Parameters: /// - type: Type of the dependency to register /// - factory: Closure that is called when the dependency is being resolved func register(type: Dependency.Type, factory: @escaping Factory) { register(type: type, in: Self.defaultScope, factory: factory) } /// Register a dependency with an implicit type determined by the factory closure return type /// /// - Parameters: /// - scope: Scope of the dependency. If `.new` is used, the `factory` closure is called on each `resolve` call. If `.shared` is used, the `factory` closure is called only the first time, the instance is cached and it is returned for all subsequent `resolve` calls, i.e. it is a singleton /// - factory: Closure that is called when the dependency is being resolved func register(in scope: DependencyScope, factory: @escaping Factory) { register(type: Dependency.self, in: scope, factory: factory) } /// Register a dependency with an implicit type determined by the factory closure return type and in the default ``DependencyScope``, i.e. in the `shared` scope /// /// - Parameters: /// - factory: Closure that is called when the dependency is being resolved func register(factory: @escaping Factory) { register(type: Dependency.self, in: Self.defaultScope, factory: factory) } } // MARK: Overloaded autoclosure methods public extension DependencyRegistering { /// Register a dependency /// /// DISCUSSION: Registration methods with autoclosures don't have any scope parameter for a reason. /// The container always returns the same instance of the dependency because the autoclosure simply wraps the instance passed as a parameter and returns it whenever it is called /// /// - Parameters: /// - type: Type of the dependency to register /// - dependency: Dependency that should be registered func register(type: Dependency.Type, dependency: @autoclosure @escaping () -> Dependency) { register(type: type, in: .shared) { _ -> Dependency in dependency() } } /// Register a dependency with an implicit type determined by the factory closure return type /// /// DISCUSSION: Registration methods with autoclosures don't have any scope parameter for a reason. /// The container always return the same instance of the dependency because the autoclosure simply wraps the instance passed as a parameter and returns it whenever it is called /// /// - Parameters: /// - dependency: Dependency that should be registered func register(dependency: @autoclosure @escaping () -> Dependency) { register(type: Dependency.self, in: .shared) { _ -> Dependency in dependency() } } }