diff --git a/Mew.xcodeproj/project.pbxproj b/Mew.xcodeproj/project.pbxproj index d64ac18..7f9cb42 100644 --- a/Mew.xcodeproj/project.pbxproj +++ b/Mew.xcodeproj/project.pbxproj @@ -18,6 +18,9 @@ 29350EB622BF04C0003A86B4 /* TableViewCell.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29350EB222BF04BF003A86B4 /* TableViewCell.swift */; }; 29350EB722BF04C0003A86B4 /* TableViewHeaderFooterView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29350EB322BF04C0003A86B4 /* TableViewHeaderFooterView.swift */; }; 29350EB822BF04C0003A86B4 /* CollectionReusableView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29350EB422BF04C0003A86B4 /* CollectionReusableView.swift */; }; + 29D7467922C2F85900C9FCF4 /* EnvironmentRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29D7467822C2F85900C9FCF4 /* EnvironmentRequest.swift */; }; + 29D7468722C2FC2700C9FCF4 /* ViewControllerRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29D7468622C2FC2700C9FCF4 /* ViewControllerRequest.swift */; }; + 29D7468922C2FC3000C9FCF4 /* ViewControllerResponse.swift in Sources */ = {isa = PBXBuildFile; fileRef = 29D7468822C2FC3000C9FCF4 /* ViewControllerResponse.swift */; }; D2568DE6214BC86800FCA44A /* CollectionViewCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2568DE3214BC86400FCA44A /* CollectionViewCellTests.swift */; }; D2568DE7214BC86800FCA44A /* TableViewCellTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2568DE2214BC86400FCA44A /* TableViewCellTests.swift */; }; D2568DEF214BCA3B00FCA44A /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = D2568DEE214BCA3B00FCA44A /* AppDelegate.swift */; }; @@ -63,6 +66,9 @@ 29350EB222BF04BF003A86B4 /* TableViewCell.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCell.swift; sourceTree = ""; }; 29350EB322BF04C0003A86B4 /* TableViewHeaderFooterView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewHeaderFooterView.swift; sourceTree = ""; }; 29350EB422BF04C0003A86B4 /* CollectionReusableView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionReusableView.swift; sourceTree = ""; }; + 29D7467822C2F85900C9FCF4 /* EnvironmentRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = EnvironmentRequest.swift; sourceTree = ""; }; + 29D7468622C2FC2700C9FCF4 /* ViewControllerRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerRequest.swift; sourceTree = ""; }; + 29D7468822C2FC3000C9FCF4 /* ViewControllerResponse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewControllerResponse.swift; sourceTree = ""; }; D2568DE2214BC86400FCA44A /* TableViewCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TableViewCellTests.swift; sourceTree = ""; }; D2568DE3214BC86400FCA44A /* CollectionViewCellTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CollectionViewCellTests.swift; sourceTree = ""; }; D2568DEC214BCA3B00FCA44A /* MewTestsApp.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = MewTestsApp.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -108,6 +114,16 @@ /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ + 29D7467722C2F7B700C9FCF4 /* Environment */ = { + isa = PBXGroup; + children = ( + 29D7467822C2F85900C9FCF4 /* EnvironmentRequest.swift */, + 29D7468822C2FC3000C9FCF4 /* ViewControllerResponse.swift */, + 29D7468622C2FC2700C9FCF4 /* ViewControllerRequest.swift */, + ); + path = Environment; + sourceTree = ""; + }; D2568DD7214BC00A00FCA44A /* Cells */ = { isa = PBXGroup; children = ( @@ -223,6 +239,7 @@ OBJ_8 /* Mew */ = { isa = PBXGroup; children = ( + 29D7467722C2F7B700C9FCF4 /* Environment */, D25C01C621620BEC00935A18 /* Utils */, D279A3042136B31A007B045A /* Protocols */, D279A3052136B31F007B045A /* ContainerView */, @@ -357,12 +374,15 @@ buildActionMask = 0; files = ( 29350EAB22BF0491003A86B4 /* CellProtocol.swift in Sources */, + 29D7468922C2FC3000C9FCF4 /* ViewControllerResponse.swift in Sources */, D25C01C821620C0100935A18 /* BackwardCompatibility.swift in Sources */, 29350EB522BF04C0003A86B4 /* CollectionViewCell.swift in Sources */, 29350EAA22BF0491003A86B4 /* Interactable.swift in Sources */, + 29D7468722C2FC2700C9FCF4 /* ViewControllerRequest.swift in Sources */, 29350EA822BF0491003A86B4 /* Instantiatable.swift in Sources */, 29350EB622BF04C0003A86B4 /* TableViewCell.swift in Sources */, 29350EA922BF0491003A86B4 /* Emittable.swift in Sources */, + 29D7467922C2F85900C9FCF4 /* EnvironmentRequest.swift in Sources */, 29350EB722BF04C0003A86B4 /* TableViewHeaderFooterView.swift in Sources */, 29350EB022BF04AB003A86B4 /* ContainerView.swift in Sources */, 29350EB822BF04C0003A86B4 /* CollectionReusableView.swift in Sources */, diff --git a/README.md b/README.md index cd83eb2..b60eb30 100644 --- a/README.md +++ b/README.md @@ -44,7 +44,7 @@ https://www.icloud.com/keynote/0vgTYDXyHQTd0l1FKTiF1jT7g#MicroViewController-en ----|---- | ContainerView | ✅ | | Container | ✅ | -| Environment, Testing support | WIP | +| Environment, Testing support | ✅ | | UITableView support | ✅ | | UICollectionView support | ✅ | @@ -61,5 +61,6 @@ https://www.mercari.com/cla/ ## License Copyright 2018 Mercari, Inc. +Copyright 2019 Yenom, Inc. Licensed under the MIT License. diff --git a/Sources/Mew/Environment/EnvironmentRequest.swift b/Sources/Mew/Environment/EnvironmentRequest.swift new file mode 100644 index 0000000..49060b9 --- /dev/null +++ b/Sources/Mew/Environment/EnvironmentRequest.swift @@ -0,0 +1,13 @@ +// +// EnvironmentRequest.swift +// Mew +// +// Created by Shun Usami on 2019/06/26. +// Copyright © 2019 Mercari. All rights reserved. +// + +import Foundation + +public protocol EnvironmentRequest { + associatedtype EnvironmentResponse +} diff --git a/Sources/Mew/Environment/ViewControllerRequest.swift b/Sources/Mew/Environment/ViewControllerRequest.swift new file mode 100644 index 0000000..2451b14 --- /dev/null +++ b/Sources/Mew/Environment/ViewControllerRequest.swift @@ -0,0 +1,103 @@ +// +// ViewControllerRequest.swift +// Mew +// +// Created by Shun Usami on 2019/06/26. +// Copyright © 2019 Mercari. All rights reserved. +// + +import Foundation +import UIKit + +// Instantiatable +public protocol ViewControllerRequest: EnvironmentRequest where EnvironmentResponse == ViewControllerResponse { + associatedtype Input + associatedtype EnvironmentResponse = ViewControllerResponse + + var inputValue: Input { get } +} + +extension ViewControllerRequest { + public func response(for type: V.Type, environment: V.Environment) + -> ViewControllerResponse + where V: UIViewController, + V: Instantiatable, + V.Input == Input { + let viewController = V(with: inputValue, environment: environment) + return ViewControllerResponse(viewController: viewController) + } +} + +// Injectable +public protocol InjectableViewControllerRequest: EnvironmentRequest where EnvironmentResponse == InjectableViewControllerResponse { + associatedtype Input + associatedtype EnvironmentResponse = InjectableViewControllerResponse + + var inputValue: Input { get } +} + +extension InjectableViewControllerRequest { + public func response(for type: V.Type, environment: V.Environment) + -> InjectableViewControllerResponse + where V: UIViewController, + V: Instantiatable, + V: Injectable, + V.Input == Input { + let viewController = V(with: inputValue, environment: environment) + return InjectableViewControllerResponse( + viewController: viewController, + input: viewController.input + ) + } +} + +// Emittable +public protocol EmittableViewControllerRequest: EnvironmentRequest where EnvironmentResponse == EmittableViewControllerResponse { + associatedtype Input + associatedtype Output + associatedtype EnvironmentResponse = EmittableViewControllerResponse + + var inputValue: Input { get } +} + +extension EmittableViewControllerRequest { + public func response(for type: V.Type, environment: V.Environment) + -> EmittableViewControllerResponse + where V: UIViewController, + V: Instantiatable, + V: Emittable, + V.Input == Input, + V.Output == Output { + let viewController = V(with: inputValue, environment: environment) + return EmittableViewControllerResponse( + viewController: viewController, + output: viewController.output + ) + } +} + +// Interactable +public protocol InteractableViewControllerRequest: EnvironmentRequest where EnvironmentResponse == InteractableViewControllerResponse { + associatedtype Input + associatedtype Output + associatedtype EnvironmentResponse = InteractableViewControllerResponse + + var inputValue: Input { get } +} + +extension InteractableViewControllerRequest { + public func response(for type: V.Type, environment: V.Environment) + -> InteractableViewControllerResponse + where V: UIViewController, + V: Instantiatable, + V: Interactable, + V.Input == Input, + V.Output == Output { + let viewController = V(with: inputValue, environment: environment) + return InteractableViewControllerResponse( + viewController: viewController, + input: viewController.input, + output: viewController.output + ) + } +} diff --git a/Sources/Mew/Environment/ViewControllerResponse.swift b/Sources/Mew/Environment/ViewControllerResponse.swift new file mode 100644 index 0000000..9d8f718 --- /dev/null +++ b/Sources/Mew/Environment/ViewControllerResponse.swift @@ -0,0 +1,54 @@ +// +// ViewControllerResponse.swift +// Mew +// +// Created by Shun Usami on 2019/06/26. +// Copyright © 2019 Mercari. All rights reserved. +// + +import Foundation +import UIKit + +public final class ViewControllerResponse { + public let viewController: UIViewController + + public init(viewController: UIViewController) { + self.viewController = viewController + } +} + +public final class InjectableViewControllerResponse { + public let viewController: UIViewController + public let input: (Input) -> Void + + public init(viewController: UIViewController, + input: @escaping (Input) -> Void) { + self.viewController = viewController + self.input = input + } +} + +public final class EmittableViewControllerResponse { + public let viewController: UIViewController + public let output: (((Output) -> Void)?) -> Void + + public init(viewController: UIViewController, + output: @escaping (((Output) -> Void)?) -> Void) { + self.viewController = viewController + self.output = output + } +} + +public final class InteractableViewControllerResponse { + public let viewController: UIViewController + public let input: (Input) -> Void + public let output: (((Output) -> Void)?) -> Void + + public init(viewController: UIViewController, + input: @escaping (Input) -> Void, + output: @escaping (((Output) -> Void)?) -> Void) { + self.viewController = viewController + self.input = input + self.output = output + } +}