[Feature] Dependencies #3

Merged
javier merged 5 commits from feature/dependencies into main 2023-04-16 15:36:08 +00:00
15 changed files with 274 additions and 17 deletions

View File

@ -14,15 +14,16 @@ let package = Package(
.library(
name: "SwiftLibs",
targets: [
"Coordinator",
"Core"
"Coordination",
"Core",
"Dependencies"
]
),
],
dependencies: [],
targets: [
.target(
name: "Coordinator",
name: "Coordination",
dependencies: [],
exclude: excludePlatforms
),
@ -30,12 +31,16 @@ let package = Package(
name: "Core",
dependencies: []
),
.target(
name: "Dependencies",
dependencies: []
),
.testTarget(
name: "CoordinatorTests",
name: "CoordinationTests",
dependencies: [
"Coordinator"
"Coordination"
],
path: "Tests/Coordinator",
path: "Tests/Coordination",
exclude: excludePlatforms
),
.testTarget(
@ -45,6 +50,13 @@ let package = Package(
],
path: "Tests/Core"
),
.testTarget(
name: "DependenciesTests",
dependencies: [
"Dependencies"
],
path: "Tests/Dependencies"
),
]
)

View File

@ -1,6 +1,6 @@
//
// BaseNavigationRouter.swift
// Coordinator
// Coordination
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// ModalNavigationRouter.swift
// Coordinator
// Coordination
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// PushNavigationRouter.swift
// Coordinator
// Coordination
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// WindowRouter.swift
// Coordinator
// Coordination
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// Coordinator.swift
// Coordinator
// Coordination
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.

View File

@ -1,6 +1,6 @@
//
// Router.swift
// Coordinator
// Coordination
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.

View File

@ -0,0 +1,31 @@
//
// Dependency.swift
// Dependencies
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
/// This property wrapper provides a direct connection to the `DependencyService` service.
@propertyWrapper
public struct Dependency<D> {
// MARK: Properties
private let keyPath: WritableKeyPath<DependencyService, D>
/// This property allows direct read/write access to a defined dependency attached to a selected key path.
public var wrappedValue: D {
get { DependencyService[keyPath] }
set { DependencyService[keyPath] = newValue }
}
// MARK: Initialisers
/// Initialise the property wrapper by setting a key path to a defined dependency.
/// - Parameter keyPath: A key path to a defined dependency in the `DependencyService` service.
public init(_ keyPath: WritableKeyPath<DependencyService, D>) {
self.keyPath = keyPath
}
}

View File

@ -0,0 +1,22 @@
//
// DependencyKey.swift
// Dependencies
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
/// This protocol defines a key to use in the dependency service.
public protocol DependencyKey {
// MARK: Associated types
/// The associated type representing the type of the dependency key's value.
associatedtype Value
// MARK: Properties
/// The default value for the dependency key.
static var currentValue: Value { get set }
}

View File

@ -0,0 +1,28 @@
//
// DependencyService.swift
// Dependencies
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
/// This service provide write/read access to the injected dependencies.
public struct DependencyService {
// MARK: Properties
private static var current = DependencyService()
// MARK: Subscripts
public static subscript<DK: DependencyKey>(key: DK.Type) -> DK.Value {
get { key.currentValue }
set { key.currentValue = newValue }
}
public static subscript<D>(_ keyPath: WritableKeyPath<DependencyService, D>) -> D {
get { current[keyPath: keyPath] }
set { current[keyPath: keyPath] = newValue }
}
}

View File

@ -1,12 +1,12 @@
//
// TestCoordinators.swift
// CoordinatorTests
// CoordinationTests
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
import Coordinator
import Coordination
import UIKit
// MARK: - Test coordinators

View File

@ -1,12 +1,12 @@
//
// CoordinatorTests.swift
// CoordinatorTests
// CoordinationTests
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
import Coordinator
import Coordination
import UIKit
import XCTest

View File

@ -0,0 +1,34 @@
//
// TestServices.swift
// DependenciesTests
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
import Dependencies
// MARK: - Protocols
protocol TestService {}
// MARK: - Services
struct SomeService: TestService, Equatable {}
struct SomeOtherService: TestService, Equatable {}
// MARK: - DependencyKey
struct TestServiceKey: DependencyKey {
static var currentValue: TestService = SomeService()
}
// MARK: - DependencyService+Keys
extension DependencyService {
var testService: TestService {
get { Self[TestServiceKey.self] }
set { Self[TestServiceKey.self] = newValue }
}
}

View File

@ -0,0 +1,73 @@
//
// DependencyTests.swift
// DependenciesTests
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
import Dependencies
import XCTest
final class DependencyTests: XCTestCase {
// MARK: Properties
private var subject: TestSubject!
// MARK: Setup
override func setUp() {
DependencyService[\.testService] = SomeService()
}
// MARK: Tests
func test_readTestService() {
// GIVEN
subject = .init()
// WHEN
let service = subject.testService
// THEN
XCTAssertNotNil(service)
XCTAssert(service is SomeService)
}
func test_writeDependencyKey() async throws {
// GIVEN
subject = .init()
subject.testService = SomeOtherService()
// WHEN
let service = DependencyService[\.testService]
// THEN
XCTAssertNotNil(service)
XCTAssert(service is SomeOtherService)
}
func test_writeDependencyKeyTwice() async throws {
// GIVEN
subject = .init()
subject.testService = SomeOtherService()
subject.testService = SomeService()
// WHEN
let service = DependencyService[\.testService]
// THEN
XCTAssertNotNil(service)
XCTAssert(service is SomeService)
}
}
// MARK: - TestSubject
private struct TestSubject {
@Dependency(\.testService) var testService
}

View File

@ -0,0 +1,57 @@
//
// DependencyServiceTests.swift
// DependenciesTests
//
// Created by Javier Cicchelli on 11/04/2023.
// Copyright © 2023 Röck+Cöde. All rights reserved.
//
import Dependencies
import XCTest
final class DependencyServiceTests: XCTestCase {
// MARK: Setup
override func setUp() {
DependencyService[\.testService] = SomeService()
}
// MARK: Tests
func test_readDependencyKey() async throws {
// GIVEN
// WHEN
let service = DependencyService[\.testService]
// THEN
XCTAssertNotNil(service)
XCTAssert(service is SomeService)
}
func test_writeDependencyKey() async throws {
// GIVEN
DependencyService[\.testService] = SomeOtherService()
// WHEN
let service = DependencyService[\.testService]
// THEN
XCTAssertNotNil(service)
XCTAssert(service is SomeOtherService)
}
func test_writeDependencyKeyTwice() async throws {
// GIVEN
DependencyService[\.testService] = SomeOtherService()
DependencyService[\.testService] = SomeService()
// WHEN
let service = DependencyService[\.testService]
// THEN
XCTAssertNotNil(service)
XCTAssert(service is SomeService)
}
}