Skip to content
This repository has been archived by the owner on Jun 13, 2024. It is now read-only.

Commit

Permalink
Merge 621081b into f8fd844
Browse files Browse the repository at this point in the history
  • Loading branch information
mikelikespie committed Sep 28, 2016
2 parents f8fd844 + 621081b commit 27c63a3
Show file tree
Hide file tree
Showing 56 changed files with 1,306 additions and 627 deletions.
112 changes: 62 additions & 50 deletions Cleanse.xcodeproj/project.pbxproj

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,32 @@

},
"DVTSourceControlWorkspaceBlueprintWorkingCopyStatesKey" : {
"FA78EFA588CAAA527A39EFF7FEB4200B880E2491" : 0,
"C29DD0E89C17000393FD71820E9E7C86451DD28A" : 0
"C29DD0E89C17000393FD71820E9E7C86451DD28A" : 0,
"7F4664FA65AADBC384859AD71F1C93E5320699FF" : 9223372036854775807,
"68EDA75FC77F318B0BF9BAED4D569D9555E8E0D3" : 9223372036854775807,
"FA78EFA588CAAA527A39EFF7FEB4200B880E2491" : 0
},
"DVTSourceControlWorkspaceBlueprintIdentifierKey" : "85D0171F-7EAD-4682-B2C2-5BBDC5C235DD",
"DVTSourceControlWorkspaceBlueprintWorkingCopyPathsKey" : {
"FA78EFA588CAAA527A39EFF7FEB4200B880E2491" : "Cleanse\/",
"C29DD0E89C17000393FD71820E9E7C86451DD28A" : ".."
"C29DD0E89C17000393FD71820E9E7C86451DD28A" : "..\/..\/..\/..",
"7F4664FA65AADBC384859AD71F1C93E5320699FF" : "..\/..",
"68EDA75FC77F318B0BF9BAED4D569D9555E8E0D3" : "..",
"FA78EFA588CAAA527A39EFF7FEB4200B880E2491" : "Cleanse\/"
},
"DVTSourceControlWorkspaceBlueprintNameKey" : "Cleanse",
"DVTSourceControlWorkspaceBlueprintVersion" : 204,
"DVTSourceControlWorkspaceBlueprintRelativePathToProjectKey" : "Cleanse.xcodeproj",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoriesKey" : [
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/git.corp.squareup.com\/ml\/UITestRunner.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "68EDA75FC77F318B0BF9BAED4D569D9555E8E0D3"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/git.corp.squareup.com\/ml\/snapshottestbinaries.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryIdentifierKey" : "7F4664FA65AADBC384859AD71F1C93E5320699FF"
},
{
"DVTSourceControlWorkspaceBlueprintRemoteRepositoryURLKey" : "ssh:\/\/git.corp.squareup.com\/ios\/appointments.git",
"DVTSourceControlWorkspaceBlueprintRemoteRepositorySystemKey" : "com.apple.dt.Xcode.sourcecontrol.Git",
Expand Down
7 changes: 4 additions & 3 deletions Cleanse/BaseComponent.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import Foundation
public protocol _AnyBaseComponent : Configurable {
}


/// Base protocol for both Components and Subcomponenents

public protocol _BaseComponent : _AnyBaseComponent {
/// This is the binding required to construct a new Component. Think of it as somewhat of an initialization value.
associatedtype Seed = Void

/// This should be set to the root type of object that is created.
associatedtype Root

associatedtype Scope: Cleanse.Scope
}
}
15 changes: 5 additions & 10 deletions Cleanse/BindingBuilder.swift
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ extension Binder {
public protocol _StandardProvider : ProviderProtocol {
}

extension Provider : _StandardProvider {
protocol _AnyStandardProvider : AnyProvider {
}

extension Provider : _StandardProvider, _AnyStandardProvider {
}

/// MARK: Building steps
Expand Down Expand Up @@ -126,14 +129,6 @@ extension BindingBuilder {
anyCollectionMergeFunc = nil
}

let componentOrSubcomponentProvider: AnyProvider?

if MaybeComponentOrSubcomponent.self is _AnyBaseComponent.Type && Input.self == MaybeComponentOrSubcomponent.self {
componentOrSubcomponentProvider = provider.asProvider()
} else {
componentOrSubcomponentProvider = nil
}

let scope: Scope.Type?

// If we explicitely declared our scope (e.g. `scopedIn(
Expand All @@ -149,7 +144,7 @@ extension BindingBuilder {
scope: scope,
provider: mappedProvider as! AnyProvider,
collectionMergeFunc: anyCollectionMergeFunc,
componentOrSubcomponentProvider: componentOrSubcomponentProvider
sourceLocation: SourceLocation(file: file, line: line, function: function)
)

binder._internalBind(binding: rpb)
Expand Down
2 changes: 0 additions & 2 deletions Cleanse/BindingBuilderDecorator.swift
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,6 @@ public protocol BindingBuilderDecorator : BindingBuilder {

associatedtype CollectionOrUnique: _CollectionOrUniqueBindingBase = Wrapped.CollectionOrUnique

associatedtype MaybeComponentOrSubcomponent: Any = Wrapped.MaybeComponentOrSubcomponent

static var collectionMergeFunc: Optional<[FinalProvider.Element] -> FinalProvider.Element> { get }
}

Expand Down
43 changes: 5 additions & 38 deletions Cleanse/Component.swift
Original file line number Diff line number Diff line change
@@ -1,48 +1,15 @@
//
// RootComponent.swift
// Component.swift
// Cleanse
//
// Created by Mike Lewis on 5/2/16.
// Created by Mike Lewis on 7/6/16.
// Copyright © 2016 Square, Inc. All rights reserved.
//

import Foundation

/// Used to detect if things being bound are a component.
/// Un-typed base protocol of component. Probably shouldn't be used directly
public protocol _AnyRootComponent : _AnyBaseComponent {
}


/// RootComponent has been renamed to RootComponent
#if swift(>=3.0)
@available(*, deprecated, renamed:"RootComponent")
public typealias Component = RootComponent
#else
@available(*, deprecated, renamed="RootComponent")
public typealias Component = RootComponent
#endif

public protocol RootComponent : Module, _BaseComponent, _AnyRootComponent {
/// This should be set to the root type of object that is created.
associatedtype Root

associatedtype Scope = Singleton
public protocol Component : _BaseComponent {
/// can have custom scopes associated with them.
associatedtype Scope = _Unscoped
}

public extension RootComponent {
/// Builds the component and returns the root object.
/// - throws: `CleanseError` if the component fails validation.
public func build() throws -> Root {
let graph = Graph(scope: Self.Scope.scopeOrNil)

let p = graph.provider(Root.self)

graph.install(module: self)

try graph.finalize()

return p.get()
}
}

26 changes: 26 additions & 0 deletions Cleanse/ComponentFactory.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,3 +7,29 @@
//

import Foundation

public protocol ComponentFactoryProtocol {
associatedtype ComponentElement: Cleanse.Component

func build(seed: ComponentElement.Seed) -> ComponentElement.Root
}

public struct ComponentFactory<C: Component> : ComponentFactoryProtocol {
public typealias ComponentElement = C
private let factoryFunction: (seed: ComponentElement.Seed) -> C.Root

init(factoryFunction: (seed: ComponentElement.Seed) -> C.Root) {
self.factoryFunction = factoryFunction
}

/// Builds the Component and returns its root object.
public func build(seed: ComponentElement.Seed) -> ComponentElement.Root {
return factoryFunction(seed: seed)
}
}

extension ComponentFactoryProtocol where ComponentElement.Seed: ProviderProtocol {
public func build(seed: ComponentElement.Seed.Element) -> ComponentElement.Root {
return build(ComponentElement.Seed.init(value: seed))
}
}
72 changes: 47 additions & 25 deletions Cleanse/ComponentVisitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import Foundation

class VisitorState<V: ComponentVisitor> {
private var enqueuedRequirementFutures = [Any.Type]()
private var enqueuedRequirementFutures = [AnyProvider.Type]()
/// These are for errors that make it impossible to traverse the module hierarchy
private var accumulatedErrors = [CleanseError]()

Expand Down Expand Up @@ -39,23 +39,24 @@ protocol ComponentVisitor : Binder {

/// Have to implement this to have a return value for a provider. Default implementation explodes
func resolveProvider<Element>(_ type: Element.Type, requiredBy: Any.Type?) -> Provider<Element>
func enterModule<M: Module>(module module: M)
func leaveModule<M: Module>(module module: M)

func enterModule<M: Module>(module module: M.Type)
func leaveModule<M: Module>(module module: M.Type)

func enterSubcomponent<S: Subcomponent>(dependency dependency: S)
func leaveSubcomponent<S: Subcomponent>(dependency dependency: S)
func enterComponent<C: Component>(dependency dependency: C.Type)
func leaveComponent<C: Component>(dependency dependency: C.Type)

func enterProvider(binding binding: RawProviderBinding)
func leaveProvider(binding binding: RawProviderBinding)

func visitRequirement(requirement requirement: Any.Type, binding: RawProviderBinding)
func visitRequirement(requirement requirement: AnyProvider.Type, binding: RawProviderBinding)
}

extension ComponentVisitor {
func enterModule<M : Module>(module module: M) {
func enterModule<M : Module>(module module: M.Type) {
}

func leaveModule<M : Module>(module module: M) {
func leaveModule<M : Module>(module module: M.Type) {
}

func enterProvider(binding binding: RawProviderBinding) {
Expand All @@ -64,21 +65,13 @@ extension ComponentVisitor {
func leaveProvider(binding binding: RawProviderBinding) {
}

func enterSubcomponent<S: Subcomponent>(dependency dependency: S) {
func enterComponent<C: Component>(dependency dependency: C.Type) {
}

func leaveSubcomponent<S: Subcomponent>(dependency dependency: S) {
func leaveComponent<C: Component>(dependency dependency: C.Type) {
}

func visitRequirement(requirement requirement: Any.Type, binding: RawProviderBinding) {
}
}

extension Subcomponent {
private func doComponentVisit<V: ComponentVisitor>(visitor visitor: V) {
visitor.enterSubcomponent(dependency: self)
configure(binder: visitor)
visitor.leaveSubcomponent(dependency: self)
func visitRequirement(requirement requirement: AnyProvider.Type, binding: RawProviderBinding) {
}
}

Expand All @@ -87,7 +80,7 @@ extension ComponentVisitor {
enterProvider(binding: binding)

let requirements = visitorState.enqueuedRequirementFutures
defer { visitorState.enqueuedRequirementFutures.removeAll() }
visitorState.enqueuedRequirementFutures.removeAll()

for requirement in requirements {
visitRequirement(requirement: requirement, binding: binding)
Expand All @@ -97,20 +90,49 @@ extension ComponentVisitor {
}


func install<M : Module>(module module: M) {
func install<M : Module>(module module: M.Type) {
enterModule(module: module)
module.configure(binder: self)
leaveModule(module: module)
}

func install<S : Subcomponent>(dependency dependency: S) {
enterSubcomponent(dependency: dependency)
func install<C : Cleanse.Component>(dependency dependency: C.Type) {
bind(ComponentFactory<C>.self).to { () -> ComponentFactory<C> in
preconditionFailure("Should not ever evaluate"); _ = Void()
}

enterComponent(dependency: dependency)

// If the seed isn't void
if C.Seed.self != Void.self {
if let seed = C.Seed.self as? AnyProvider.Type {
_internalBind(binding: RawProviderBinding(
scope: nil,
provider: seed.makeNew { preconditionFailure(); _ = Void() },
collectionMergeFunc: nil,
sourceLocation: nil
))
} else {
_internalBind(binding: RawProviderBinding(
scope: nil,
provider: Provider<C.Seed> { preconditionFailure(); _ = Void() },
collectionMergeFunc: nil,
sourceLocation: nil
))
}

}

dependency.configure(binder: self)
leaveSubcomponent(dependency: dependency)
leaveComponent(dependency: dependency)
}

func _internalProvider<Element>(_ type: Element.Type, debugInfo: ProviderRequestDebugInfo?) -> Provider<Element> {
visitorState.enqueuedRequirementFutures.append(Element.self)
if let type = type as? AnyProvider.Type {
visitorState.enqueuedRequirementFutures.append(type)
} else {
visitorState.enqueuedRequirementFutures.append(Provider<Element>.self)
}

return resolveProvider(Element.self, requiredBy: debugInfo?.providerRequiredFor)
}
Expand Down
4 changes: 2 additions & 2 deletions Cleanse/Configurable.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,5 @@ import Foundation

/// Base protocol for Components and Models. It allows for shared installation, but disambguates function call
public protocol Configurable {
func configure<B: Binder>(binder binder: B)
}
static func configure<B: Binder>(binder binder: B)
}
Loading

0 comments on commit 27c63a3

Please sign in to comment.