Skip to content

Commit

Permalink
Merge pull request #109 from uber/foundation-plugin_ext_key-master
Browse files Browse the repository at this point in the history
PluginExtensionProvider is unique per PluginizedComponent regardless …
  • Loading branch information
Rudro Samanta authored Jul 2, 2018
2 parents 1e54061 + dd5377b commit 83acaff
Show file tree
Hide file tree
Showing 7 changed files with 79 additions and 20 deletions.
59 changes: 55 additions & 4 deletions Foundation/NeedleFoundation.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@
41F0681420D45AD100FD67C7 /* PluginizedLifecycle.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginizedLifecycle.swift; sourceTree = "<group>"; };
41F0681A20D45B1300FD67C7 /* PluginizedComponentTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = PluginizedComponentTests.swift; sourceTree = "<group>"; };
"NeedleFoundation::NeedleFoundation::Product" /* NeedleFoundation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = NeedleFoundation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
"NeedleFoundation::NeedleFoundationTests::Product" /* NeedleFoundationTests.xctest */ = {isa = PBXFileReference; lastKnownFileType = file; path = NeedleFoundationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
"NeedleFoundation::NeedleFoundationTests::Product" /* NeedleFoundationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; path = NeedleFoundationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
OBJ_10 /* Component.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Component.swift; sourceTree = "<group>"; };
OBJ_12 /* DependencyProviderRegistry.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DependencyProviderRegistry.swift; sourceTree = "<group>"; };
OBJ_15 /* ComponentTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ComponentTests.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -198,7 +198,7 @@
OBJ_1 /* Project object */ = {
isa = PBXProject;
attributes = {
LastUpgradeCheck = 9999;
LastUpgradeCheck = 0940;
};
buildConfigurationList = OBJ_2 /* Build configuration list for PBXProject "NeedleFoundation" */;
compatibilityVersion = "Xcode 3.2";
Expand Down Expand Up @@ -304,12 +304,38 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_NS_ASSERTIONS = YES;
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = 0;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.10;
ONLY_ACTIVE_ARCH = YES;
Expand All @@ -327,11 +353,36 @@
isa = XCBuildConfiguration;
buildSettings = {
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
CLANG_WARN_CONSTANT_CONVERSION = YES;
CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
CLANG_WARN_EMPTY_BODY = YES;
CLANG_WARN_ENUM_CONVERSION = YES;
CLANG_WARN_INFINITE_RECURSION = YES;
CLANG_WARN_INT_CONVERSION = YES;
CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
CLANG_WARN_STRICT_PROTOTYPES = YES;
CLANG_WARN_SUSPICIOUS_MOVE = YES;
CLANG_WARN_UNREACHABLE_CODE = YES;
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
COMBINE_HIDPI_IMAGES = YES;
COPY_PHASE_STRIP = YES;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DYLIB_INSTALL_NAME_BASE = "@rpath";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_NO_COMMON_BLOCKS = YES;
GCC_OPTIMIZATION_LEVEL = s;
GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
GCC_WARN_ABOUT_RETURN_TYPE = YES;
GCC_WARN_UNDECLARED_SELECTOR = YES;
GCC_WARN_UNINITIALIZED_AUTOS = YES;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
IPHONEOS_DEPLOYMENT_TARGET = 8.0;
MACOSX_DEPLOYMENT_TARGET = 10.10;
OTHER_SWIFT_FLAGS = "-DXcode";
Expand All @@ -347,7 +398,7 @@
OBJ_42 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
Expand All @@ -366,7 +417,7 @@
OBJ_43 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
EMBEDDED_CONTENT_CONTAINS_SWIFT = YES;
ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
FRAMEWORK_SEARCH_PATHS = (
"$(inherited)",
"$(PLATFORM_DIR)/Developer/Library/Frameworks",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<Scheme
LastUpgradeVersion = "0930"
LastUpgradeVersion = "0940"
version = "1.3">
<BuildAction
parallelizeBuildables = "YES"
Expand Down
2 changes: 1 addition & 1 deletion Foundation/Sources/NeedleFoundation/Bootstrap.swift
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public class EmptyDependencyProvider: EmptyDependency {
public class BootstrapComponent: ComponentType {

/// The path to reach this scope on the dependnecy graph.
public let path: String = "^"
public let path: [String] = ["^"]

/// This component does not have a parent
public var parent: ComponentType {
Expand Down
15 changes: 9 additions & 6 deletions Foundation/Sources/NeedleFoundation/Component.swift
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public protocol Dependency: AnyObject {}
/// base class, instead of using this protocol directly.
public protocol ComponentType: AnyObject {
/// The path to reach this component on the dependnecy graph.
var path: String { get }
var path: [String] { get }

/// The parent of this component.
// This property cannot be of `ComponentType`, since the root of the dependency graph
Expand All @@ -43,11 +43,9 @@ open class Component<DependencyType>: ComponentType {
/// The path to reach this scope on the dependnecy graph.
// Use `lazy var` to avoid computing the path repeatedly. Internally, this is always
// accessed with the `__DependencyProviderRegistry`'s lock acquired.
public lazy var path: String = {
let fullyQualifiedSelfName = String(describing: self)
let parts = fullyQualifiedSelfName.components(separatedBy: ".")
let name = parts.last ?? fullyQualifiedSelfName
return parent.path + "->\(name)"
public lazy var path: [String] = {
let name = self.name
return parent.path + ["\(name)"]
}()

/// The dependency of this component.
Expand Down Expand Up @@ -94,6 +92,11 @@ open class Component<DependencyType>: ComponentType {

private let sharedInstanceLock = NSRecursiveLock()
private var sharedInstances = [String: Any]()
private lazy var name: String = {
let fullyQualifiedSelfName = String(describing: self)
let parts = fullyQualifiedSelfName.components(separatedBy: ".")
return parts.last ?? fullyQualifiedSelfName
}()

// TODO: Replace this with an `open` method, once Swift supports extension overriding methods.
private func createDependencyProvider() -> DependencyType {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,8 @@ public class __DependencyProviderRegistry {
providerFactoryLock.unlock()
}

if let factory = providerFactories[component.path.hashValue] {
let pathString = component.path.joined(separator: "->")
if let factory = providerFactories[pathString.hashValue] {
return factory(component)
} else {
fatalError("Missing dependency provider factory for \(component.path)")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,19 +33,21 @@ public class __PluginExtensionProviderRegistry {
/// Register the given factory closure with given key.
///
/// - note: This method is thread-safe.
/// - parameter componentPath: The dependency graph path of the component
/// the provider is for.
/// - note: Plugin extension provider is unique per pluginized component
/// regardless of its path, since it only extracts properties from its
/// corresponding non-core component.
/// - parameter componentName: The name of the component the provider is for.
/// - parameter pluginExtensionProviderFactory: The closure that takes in
/// a component to be injected and returns a provider instance that conforms
/// to the component's plugin extensions protocol.
public func registerPluginExtensionProviderFactory(`for` componentPath: String, _ pluginExtensionProviderFactory: @escaping (PluginizedComponentType) -> AnyObject) {
public func registerPluginExtensionProviderFactory(`for` componentName: String, _ pluginExtensionProviderFactory: @escaping (PluginizedComponentType) -> AnyObject) {
// Lock on `providerFactories` access.
lock.lock()
defer {
lock.unlock()
}

providerFactories[componentPath.hashValue] = pluginExtensionProviderFactory
providerFactories[componentName] = pluginExtensionProviderFactory
}

func pluginExtensionProvider(`for` component: PluginizedComponentType) -> AnyObject {
Expand All @@ -55,15 +57,17 @@ public class __PluginExtensionProviderRegistry {
lock.unlock()
}

if let factory = providerFactories[component.path.hashValue] {
// The last element of the path is the component itself and it always exists.
let key = component.path.last!
if let factory = providerFactories[key] {
return factory(component)
} else {
fatalError("Missing plugin extension provider factory for \(component.path)")
}
}

private let lock = NSRecursiveLock()
private var providerFactories = [Int: (PluginizedComponentType) -> AnyObject]()
private var providerFactories = [String: (PluginizedComponentType) -> AnyObject]()

private init() {}
}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ class PluginizedComponentTests: XCTestCase {
return EmptyDependencyProvider(component: component)
}

__PluginExtensionProviderRegistry.instance.registerPluginExtensionProviderFactory(for: "^->MockPluginizedComponent") { pluginizedComponent in
__PluginExtensionProviderRegistry.instance.registerPluginExtensionProviderFactory(for: "MockPluginizedComponent") { pluginizedComponent in
return EmptyPluginExtensionsProvider()
}
}
Expand Down

0 comments on commit 83acaff

Please sign in to comment.