From 6ec5b742efba03080a470cfc4ca5e77134cbd83c Mon Sep 17 00:00:00 2001 From: Dariusz Rybicki <dariusz@elixxir.io> Date: Mon, 18 Jul 2022 13:01:04 +0100 Subject: [PATCH] Add CellFactory --- Sources/CollectionView/CellFactory.swift | 64 ++++++++++++++++ .../CellFactoryTests.swift | 75 +++++++++++++++++++ 2 files changed, 139 insertions(+) create mode 100644 Sources/CollectionView/CellFactory.swift create mode 100644 Tests/CollectionViewTests/CellFactoryTests.swift diff --git a/Sources/CollectionView/CellFactory.swift b/Sources/CollectionView/CellFactory.swift new file mode 100644 index 00000000..00faf2c2 --- /dev/null +++ b/Sources/CollectionView/CellFactory.swift @@ -0,0 +1,64 @@ +import UIKit + +public struct CellFactory<Model> { + public struct Registrar { + public var register: (UICollectionView) -> Void + + public func callAsFunction(in view: UICollectionView) { + register(view) + } + } + + public struct Builder { + public var buildCell: (Model, UICollectionView, IndexPath) -> UICollectionViewCell? + + public func callAsFunction( + for model: Model, + in view: UICollectionView, + at indexPath: IndexPath + ) -> UICollectionViewCell? { + buildCell(model, view, indexPath) + } + } + + public var register: Registrar + public var build: Builder + + public init( + register: Registrar, + build: Builder + ) { + self.register = register + self.build = build + } +} + +extension CellFactory { + public static func combined(_ factories: CellFactory...) -> CellFactory { + combined(factories) + } + + public static func combined(_ factories: [CellFactory]) -> CellFactory { + CellFactory( + register: .init { collectionView in + factories.forEach { $0.register(in: collectionView) } + }, + build: .init { model, collectionView, indexPath in + factories.lazy + .compactMap { $0.build(for: model, in: collectionView, at: indexPath) } + .first + } + ) + } +} + +#if DEBUG +extension CellFactory { + public static func failing() -> CellFactory { + CellFactory( + register: .init { _ in fatalError("Not implemented") }, + build: .init { _, _, _ in fatalError("Not implemented") } + ) + } +} +#endif diff --git a/Tests/CollectionViewTests/CellFactoryTests.swift b/Tests/CollectionViewTests/CellFactoryTests.swift new file mode 100644 index 00000000..c9b052dd --- /dev/null +++ b/Tests/CollectionViewTests/CellFactoryTests.swift @@ -0,0 +1,75 @@ +import XCTest +@testable import CollectionView + +final class CellFactoryTests: XCTestCase { + func testCombined() { + var didRegisterFirst = [UICollectionView]() + var didRegisterSecond = [UICollectionView]() + var didRegisterThird = [UICollectionView]() + + class Cell: UICollectionViewCell { + var collectionView: UICollectionView? + var indexPath: IndexPath? + } + + let factory = CellFactory<Int>.combined( + .init( + register: .init { didRegisterFirst.append($0) }, + build: .init { model, collectionView, indexPath in + guard model == 1 else { return nil } + let cell = Cell() + cell.collectionView = collectionView + cell.indexPath = indexPath + return cell + } + ), + .init( + register: .init { didRegisterSecond.append($0) }, + build: .init { model, collectionView, indexPath in + guard model == 2 else { return nil } + let cell = Cell() + cell.collectionView = collectionView + cell.indexPath = indexPath + return cell + } + ), + .init( + register: .init { didRegisterThird.append($0) }, + build: .init { model, collectionView, indexPath in + guard model == 3 else { return nil } + let cell = Cell() + cell.collectionView = collectionView + cell.indexPath = indexPath + return cell + } + ) + ) + + let collectionView = UICollectionView(frame: .zero, collectionViewLayout: .init()) + + factory.register(in: collectionView) + + XCTAssertEqual(didRegisterFirst, [collectionView]) + XCTAssertEqual(didRegisterSecond, [collectionView]) + XCTAssertEqual(didRegisterThird, [collectionView]) + + let firstCell = factory.build(for: 1, in: collectionView, at: IndexPath(item: 0, section: 1)) as? Cell + + XCTAssertEqual(firstCell?.collectionView, collectionView) + XCTAssertEqual(firstCell?.indexPath, IndexPath(item: 0, section: 1)) + + let secondCell = factory.build(for: 2, in: collectionView, at: IndexPath(item: 2, section: 3)) as? Cell + + XCTAssertEqual(secondCell?.collectionView, collectionView) + XCTAssertEqual(secondCell?.indexPath, IndexPath(item: 2, section: 3)) + + let thirdCell = factory.build(for: 3, in: collectionView, at: IndexPath(item: 4, section: 5)) as? Cell + + XCTAssertEqual(thirdCell?.collectionView, collectionView) + XCTAssertEqual(thirdCell?.indexPath, IndexPath(item: 4, section: 5)) + + let otherCell = factory.build(for: 4, in: collectionView, at: IndexPath(item: 0, section: 0)) + + XCTAssertNil(otherCell) + } +} -- GitLab