Examples
Code that this repository compiles.
Each target in Examples uses the local Skein checkout. These blocks are read from the source files at build time, not copied into the site by hand.
BasicUsage
Owned SkeinApplication, lazy singletons, factories, assisted factories, and a typed scope.
Run: swift run --package-path Examples BasicUsage
Examples/Sources/BasicUsage/main.swift
import Skein
let applicationModule = module {
// Created lazily on the first resolution, then reused.
single(Logger.self, using: Logger.init)
// Created again for each resolution.
factory(RequestHandler.self, using: RequestHandler.init)
// Assisted factories accept one strongly typed runtime value.
factory(RequestPresenter.self, arguments: RequestPath.self, using: RequestPresenter.init)
// Scoped values are shared only by one typed scope instance.
scoped(RequestCache.self, scope: RequestScope.self, provider: { _ in RequestCache() })
}
do {
let application = try SkeinApplication {
applicationModule
}
let firstLogger: Logger = try application.get()
let secondLogger: Logger = try application.get()
print("Singleton reused: \(firstLogger === secondLogger)")
let firstHandler: RequestHandler = try application.get()
let secondHandler: RequestHandler = try application.get()
print("Factory creates new values: \(firstHandler !== secondHandler)")
print("Nested singleton reused: \(firstHandler.logger === secondHandler.logger)")
firstHandler.handle("/examples")
let presenter: RequestPresenter = try application.get(
arguments: RequestPath(value: "/examples")
)
print("Assisted path: \(presenter.path.value)")
let scope = try application.createScope(RequestScope.self, id: "example")
let firstCache: RequestCache = try scope.get()
let secondCache: RequestCache = try scope.get()
print("Scoped cache reused: \(firstCache === secondCache)")
} catch {
print("Skein setup or resolution failed: \(error)")
}
ModularComposition
Feature modules and a protocol registration for a live API client.
Run: swift run --package-path Examples ModularComposition
Examples/Sources/ModularComposition/main.swift
import Skein
let networkingModule = module {
single((any APIClient).self, provider: { _ in LiveAPIClient() })
}
let dataModule = module {
single(UserRepository.self, using: UserRepository.init)
}
let featureModule = module {
factory(ProfilePresenter.self, using: ProfilePresenter.init)
}
do {
try startSkein {
networkingModule
dataModule
featureModule
}
defer { stopSkein() }
let presenter: ProfilePresenter = try get()
print(presenter.title())
} catch {
print("Skein setup or resolution failed: \(error)")
}
QualifiedBindings
Multiple values of the same type, separated by qualifiers.
Run: swift run --package-path Examples QualifiedBindings
Examples/Sources/QualifiedBindings/main.swift
import Skein
let endpointModule = module {
single(ServiceEndpoint.self, qualifier: ServiceEnvironment.production, provider: { _ in
ServiceEndpoint(baseURL: "https://api.example.com")
})
single(ServiceEndpoint.self, qualifier: ServiceEnvironment.staging, provider: { _ in
ServiceEndpoint(baseURL: "https://staging.example.com")
})
}
do {
try startSkein {
endpointModule
}
defer { stopSkein() }
let production = try get(
ServiceEndpoint.self,
qualifier: ServiceEnvironment.production
)
let staging = try get(
ServiceEndpoint.self,
qualifier: ServiceEnvironment.staging
)
print("Production: \(production.baseURL)")
print("Staging: \(staging.baseURL)")
} catch {
print("Skein setup or resolution failed: \(error)")
}
ErrorHandling
Provider failures wrapped in SkeinResolutionError and retried singletons.
Run: swift run --package-path Examples ErrorHandling
Examples/Sources/ErrorHandling/main.swift
import Skein
let attempts = Attempts()
let retryModule = module {
single(String.self, provider: { _ in
attempts.count += 1
guard attempts.count > 1 else {
throw ConnectionError.unavailable
}
return "connected"
})
}
do {
let _: Int = try get()
} catch SkeinError.notStarted {
print("Resolution requires an active container")
} catch {
print("Unexpected pre-start error: \(error)")
}
do {
try startSkein {
retryModule
}
defer { stopSkein() }
do {
let _: String = try get()
} catch let error as SkeinResolutionError {
if error.underlying is ConnectionError {
print("Provider error retained as the diagnostic underlying error")
}
}
// A failed singleton is not cached, so its provider is tried again.
let connection: String = try get()
print("Second attempt: \(connection)")
do {
let _: Int = try get()
} catch let error as SkeinResolutionError {
if case let SkeinError.missingBinding(type, qualifier) = error.underlying {
print("Missing binding for \(type), qualifier: \(qualifier ?? "none")")
}
}
} catch {
print("Skein setup or resolution failed: \(error)")
}
MainActorValidation
MainActor bindings, eager roots, and async startup validation.
Run: swift run --package-path Examples MainActorValidation
Examples/Sources/MainActorValidation/MainActorValidation.swift
import Skein
@main
@MainActor private struct MainActorValidation {
private static let applicationModule = module {
instance(AppConfiguration())
single(AccountScreenModel.self, using: AccountScreenModel.init)
.root(.eager)
}
static func main() async {
do {
// The application owns this policy and may log or fail fast here.
try await startSkein(validation: .declaredRoots) {
applicationModule
}
defer { stopSkein() }
let screenModel: AccountScreenModel = try get()
print("Validated main-actor screen model for \(screenModel.apiBaseURL)")
} catch {
print("Application startup validation failed: \(error)")
}
}
}
TestingExampleTests
A production module replaced with a hand-written fake in an isolated test container.
Run: swift test --package-path Examples
Examples/Tests/TestingExampleTests/TestingExampleTests.swift
import Skein
import XCTest
private protocol GreetingService {
func greeting() -> String
}
private final class LiveGreetingService: GreetingService {
func greeting() -> String {
"Hello from production"
}
}
private final class FakeGreetingService: GreetingService {
func greeting() -> String {
"Hello from a test"
}
}
private final class WelcomeMessage {
private let service: any GreetingService
init(service: any GreetingService) {
self.service = service
}
var text: String {
service.greeting()
}
}
@MainActor private func makeProductionModule() -> Module {
module {
single((any GreetingService).self, provider: { _ in LiveGreetingService() })
factory(WelcomeMessage.self, using: WelcomeMessage.init)
}
}
@MainActor private func makeTestModule() -> Module {
module {
single((any GreetingService).self, provider: { _ in FakeGreetingService() })
factory(WelcomeMessage.self, using: WelcomeMessage.init)
}
}
@MainActor final class TestingExampleTests: XCTestCase {
func testProductionGraph() throws {
let application = try SkeinApplication { makeProductionModule() }
let message: WelcomeMessage = try application.get()
XCTAssertEqual(message.text, "Hello from production")
}
func testGraphWithHandWrittenFake() throws {
let application = try SkeinApplication { makeTestModule() }
let message: WelcomeMessage = try application.get()
XCTAssertEqual(message.text, "Hello from a test")
}
}