Skip to content

Commit

Permalink
make keyed Environment objects type aware
Browse files Browse the repository at this point in the history
fix a bug
  • Loading branch information
khanlou committed Sep 6, 2020
1 parent ece9a71 commit e5b57c7
Show file tree
Hide file tree
Showing 6 changed files with 74 additions and 51 deletions.
30 changes: 0 additions & 30 deletions Meridian/EnvironmentStorage.swift

This file was deleted.

34 changes: 34 additions & 0 deletions Meridian/EnvironmentValues.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
//
// EnvironmentStorage.swift
// Meridian
//
// Created by Soroush Khanlou on 8/29/20.
//

import Foundation

public protocol EnvironmentKey {

associatedtype Value

static var defaultValue: Value { get }

}

public final class EnvironmentValues {

static let shared = EnvironmentValues()

var objects: [AnyObject] = []

var keyedObjects: [Any] = []

public subscript<Key: EnvironmentKey>(key: Key.Type) -> Key.Value {
get {
keyedObjects.lazy.compactMap({ $0 as? Key.Value }).first ?? Key.defaultValue
}
set {
keyedObjects.append(newValue)
}
}
}
17 changes: 14 additions & 3 deletions Meridian/OptionsRoute.swift
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,27 @@

import Foundation

extension EnvironmentKey {
static let routes = EnvironmentKey()
struct RouterEnvironmentKey: EnvironmentKey {
static var defaultValue = Router(routesByPrefix: [:], defaultErrorRenderer: BasicErrorRenderer.self)
}

extension EnvironmentValues {
var router: Router {
get {
self[RouterEnvironmentKey.self]
}
set {
self[RouterEnvironmentKey.self] = newValue
}
}
}

struct OptionsRoute: Route {
static var route = RouteMatcher(matches: { header in
header.method == .OPTIONS ? MatchedRoute() : nil
})

@Environment(.routes) var router: Router
@Environment(\.router) var router

@Path var path: String

Expand Down
14 changes: 5 additions & 9 deletions Meridian/Property Wrappers/Environment.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,17 @@ public typealias EnvironmentObject<Type> = Custom<EnvironmentObjectExtractor<Typ

public struct EnvironmentObjectExtractor<Type>: NonParameterizedExtractor {
public static func extract(from context: RequestContext) throws -> Type {
guard let value = EnvironmentStorage.shared.objects.lazy.compactMap({ $0 as? Type }).first else {
guard let value = EnvironmentValues.shared.objects.lazy.compactMap({ $0 as? Type }).first else {
throw MissingEnvironmentObject(type: Type.self)
}
return value
}
}

public typealias Environment<Type> = CustomWithParameters<EnvironmentKeyExtractor<Type>>
public typealias Environment<Value> = CustomWithParameters<EnvironmentKeyExtractor<Value>>

public struct EnvironmentKeyExtractor<Type>: ParameterizedExtractor {
public static func extract(from context: RequestContext, parameters: EnvironmentKey) throws -> Type {
if let value = EnvironmentStorage.shared.keyedObjects[parameters] as? Type {
return value
} else {
throw MissingEnvironmentObject(type: Type.self)
}
public struct EnvironmentKeyExtractor<Value>: ParameterizedExtractor {
public static func extract(from context: RequestContext, parameters: KeyPath<EnvironmentValues, Value>) throws -> Value {
EnvironmentValues.shared[keyPath: parameters]
}
}
8 changes: 4 additions & 4 deletions Meridian/Server.swift
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ public final class Server {

public func listen() {

EnvironmentStorage.shared.keyedObjects[.routes] = self.router
EnvironmentValues.shared[RouterEnvironmentKey.self] = self.router

let reuseAddrOpt = ChannelOptions.socket(SocketOptionLevel(SOL_SOCKET), SO_REUSEADDR)

Expand Down Expand Up @@ -99,12 +99,12 @@ public final class Server {

extension Server {
public func environmentObject(_ object: AnyObject) -> Self {
EnvironmentStorage.shared.objects.append(object)
EnvironmentValues.shared.objects.append(object)
return self
}

public func environment(_ key: EnvironmentKey, _ value: AnyObject) -> Self {
EnvironmentStorage.shared.keyedObjects[key] = value
public func environment<Key: EnvironmentKey>(_ key: Key, _ value: Key.Value) -> Self {
// EnvironmentValues.shared.keyedObjects[key] = value
return self
}
}
22 changes: 17 additions & 5 deletions MeridianTests/EnvironmentTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,14 +10,26 @@ import NIO
import NIOHTTP1
@testable import Meridian

extension EnvironmentKey {
static let formatter = EnvironmentKey()
struct NumberFormatterEnvironmentKey: EnvironmentKey {
static var defaultValue = NumberFormatter()
}

extension EnvironmentValues {
var formatter: NumberFormatter {
get {
self[NumberFormatterEnvironmentKey.self]
}
set {
self[NumberFormatterEnvironmentKey.self] = newValue
}
}
}


struct EnvironmentKeyTestRoute: Route {
static let route: RouteMatcher = "/environmentKey"

@Environment(.formatter) var formatter: NumberFormatter
@Environment(\.formatter) var formatter

func execute() throws -> Response {
formatter.string(from: 343) ?? "formatter couldn't format"
Expand Down Expand Up @@ -65,9 +77,9 @@ final class EnvironmentTests: XCTestCase {
let formatter = NumberFormatter()
formatter.locale = Locale(identifier: "en_US")
formatter.numberStyle = .spellOut
EnvironmentStorage.shared.keyedObjects[.formatter] = formatter
EnvironmentValues.shared[NumberFormatterEnvironmentKey.self] = formatter

EnvironmentStorage.shared.objects.append(Database())
EnvironmentValues.shared.objects.append(Database())

return channel
}
Expand Down

0 comments on commit e5b57c7

Please sign in to comment.