Skip to content

Commit

Permalink
Add implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
dhardiman committed Jun 24, 2019
1 parent 0666a0f commit cd4be1e
Show file tree
Hide file tree
Showing 5 changed files with 74 additions and 20 deletions.
37 changes: 20 additions & 17 deletions Sources/Config/ConfigurationFile.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ struct Configuration {
let properties: [String: Property]
let childConfigurations: [String: Configuration]

init(config: [String: Any], referenceSource: [String: Any]?, customTypes: [CustomType], defaultType: PropertyType?) {
init(config: [String: Any], referenceSource: [String: Any]?, customTypes: [CustomType], defaultType: PropertyType?, commonPatterns: [OverridePattern]) {
properties = config.reduce([String: Property]()) { properties, pair in
return parseNextProperty(properties: properties, pair: pair, config: config, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType)
return parseNextProperty(properties: properties, pair: pair, config: config, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType, patterns: commonPatterns)
}
childConfigurations = config.reduce([String: Configuration]()) { configurations, pair in
return parseNextConfiguration(configurations: configurations, pair: pair, config: config, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType)
return parseNextConfiguration(configurations: configurations, pair: pair, config: config, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType, patterns: commonPatterns)
}
}

Expand Down Expand Up @@ -90,7 +90,7 @@ extension String {
}
}

func parseNextProperty(properties: [String: Property], pair: (key: String, value: Any), config: [String: Any], referenceSource: [String: Any]?, customTypes: [CustomType], defaultType: PropertyType?) -> [String: Property] {
func parseNextProperty(properties: [String: Property], pair: (key: String, value: Any), config: [String: Any], referenceSource: [String: Any]?, customTypes: [CustomType], defaultType: PropertyType?, patterns: [OverridePattern]) -> [String: Property] {
guard let dict = pair.value as? [String: Any] else {
return properties
}
Expand All @@ -101,21 +101,21 @@ func parseNextProperty(properties: [String: Property], pair: (key: String, value
if let typeHint = PropertyType(rawValue: typeHintValue) {
switch typeHint {
case .string, .url, .encrypted, .encryptionKey, .colour, .image, .regex:
copy[pair.key] = ConfigurationProperty<String>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<String>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .optionalString:
copy[pair.key] = ConfigurationProperty<String?>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<String?>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .double, .float:
copy[pair.key] = ConfigurationProperty<Double>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<Double>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .int:
copy[pair.key] = ConfigurationProperty<Int>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<Int>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .optionalInt:
copy[pair.key] = ConfigurationProperty<Int?>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<Int?>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .dictionary:
copy[pair.key] = ConfigurationProperty<[String: Any]>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<[String: Any]>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .bool:
copy[pair.key] = ConfigurationProperty<Bool>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<Bool>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .stringArray:
copy[pair.key] = ConfigurationProperty<[String]>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<[String]>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
case .reference:
guard let referenceType = referenceTypeHint(for: dict, in: config, referenceSource: referenceSource) else {
return properties
Expand All @@ -129,7 +129,7 @@ func parseNextProperty(properties: [String: Property], pair: (key: String, value
copy[pair.key] = CustomPropertyArray(key: pair.key, customType: customType, dict: dict)
}
else {
copy[pair.key] = ConfigurationProperty<String>(key: pair.key, typeHint: typeHintValue, dict: dict)
copy[pair.key] = ConfigurationProperty<String>(key: pair.key, typeHint: typeHintValue, dict: dict, patterns: patterns)
}
}
return copy
Expand All @@ -153,12 +153,12 @@ private func referenceDict(for key: String, from config: [String: Any], or refer
return referenceSource?[key] as? [String: Any]
}

func parseNextConfiguration(configurations: [String: Configuration], pair: (key: String, value: Any), config: [String: Any], referenceSource: [String: Any]?, customTypes: [CustomType], defaultType: PropertyType?) -> [String: Configuration] {
func parseNextConfiguration(configurations: [String: Configuration], pair: (key: String, value: Any), config: [String: Any], referenceSource: [String: Any]?, customTypes: [CustomType], defaultType: PropertyType?, patterns: [OverridePattern]) -> [String: Configuration] {
guard let dict = pair.value as? [String: Any], dict["defaultValue"] == nil, pair.key != "template" else {
return configurations
}
var copy = configurations
copy[pair.key] = Configuration(config: dict, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType)
copy[pair.key] = Configuration(config: dict, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType, commonPatterns: patterns)
return copy
}

Expand All @@ -177,6 +177,8 @@ struct ConfigurationFile: Template {

let customTypes: [CustomType]

let commonPatterns: [OverridePattern]

let defaultType: PropertyType?

init(config: [String: Any], name: String, scheme: String, source: URL) throws {
Expand All @@ -188,6 +190,7 @@ struct ConfigurationFile: Template {
self.imports = ["Foundation"] + ((self.template?["imports"] as? [String]) ?? [])

self.customTypes = CustomType.typeArray(from: self.template)
self.commonPatterns = OverridePattern.patterns(from: self.template)

if let defaultType = template?["defaultType"] as? String {
self.defaultType = PropertyType(rawValue: defaultType)
Expand All @@ -203,15 +206,15 @@ struct ConfigurationFile: Template {

iv = try IV(dict: config)

let root = Configuration(config: config, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType)
let root = Configuration(config: config, referenceSource: referenceSource, customTypes: customTypes, defaultType: defaultType, commonPatterns: commonPatterns)
var parsedProperties = root.properties

encryptionKey = parsedProperties.values.compactMap { $0 as? ConfigurationProperty<String> }
.first(where: { $0.type == .encryptionKey })?.defaultValue
if encryptionKey != nil {
parsedProperties[iv.key] = iv
}
if template?["extensionOn"] == nil, let schemeProperty = ConfigurationProperty<String>(key: "schemeName", typeHint: "String", dict: ["defaultValue": scheme]) {
if template?["extensionOn"] == nil, let schemeProperty = ConfigurationProperty<String>(key: "schemeName", typeHint: "String", dict: ["defaultValue": scheme], patterns: commonPatterns) {
parsedProperties[schemeProperty.key] = schemeProperty
}
rootConfiguration = Configuration(properties: parsedProperties, childConfigurations: root.childConfigurations)
Expand Down
14 changes: 12 additions & 2 deletions Sources/Config/ConfigurationProperty.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct ConfigurationProperty<T>: Property, AssociatedPropertyKeyProviding {
let defaultValue: T
let associatedProperty: String?
let overrides: [String: T]
let patterns: [OverridePattern]

var typeName: String {
if let type = type {
Expand Down Expand Up @@ -51,7 +52,7 @@ struct ConfigurationProperty<T>: Property, AssociatedPropertyKeyProviding {
throw Failure.notConvertible
}

init?(key: String, typeHint: String, dict: [String: Any]) {
init?(key: String, typeHint: String, dict: [String: Any], patterns: [OverridePattern] = []) {
do {
self.defaultValue = try ConfigurationProperty.transformValueToType(value: dict["defaultValue"])

Expand All @@ -60,6 +61,7 @@ struct ConfigurationProperty<T>: Property, AssociatedPropertyKeyProviding {
self.associatedProperty = dict["associatedProperty"] as? String
self.type = PropertyType(rawValue: typeHint)
self.description = dict["description"] as? String
self.patterns = patterns

let overrides = try? dict["overrides"]
.flatMap { $0 as? [String: Any] }?
Expand All @@ -71,12 +73,20 @@ struct ConfigurationProperty<T>: Property, AssociatedPropertyKeyProviding {
}
}

private func pattern(for override: String) -> String {
guard let pattern = patterns.first(where: { $0.alias == override }) else {
return override
}
return pattern.pattern
}

func value(for scheme: String) -> T {

if let override = overrides.first(where: { item in
if associatedProperty != nil {
return item.key == scheme
}
return scheme.range(of: item.key, options: .regularExpression) != nil
return scheme.range(of: pattern(for: item.key), options: .regularExpression) != nil
}) {
return override.value
}
Expand Down
2 changes: 1 addition & 1 deletion Sources/Config/EnumConfiguration.swift
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ struct EnumConfiguration: Template {
var copy = properties
switch type {
case "String":
copy[pair.key] = ConfigurationProperty<String>(key: pair.key, typeHint: "", dict: dict)
copy[pair.key] = ConfigurationProperty<String>(key: pair.key, typeHint: "", dict: dict, patterns: OverridePattern.patterns(from: template))
default: throw EnumError.unknownType
}
return copy
Expand Down
28 changes: 28 additions & 0 deletions Sources/Config/OverridePattern.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//
// OverridePattern.swift
// Config
//
// Created by David Hardiman on 24/06/2019.
//

import Foundation

struct OverridePattern {
let alias: String
let pattern: String

init?(source: [String: String]) {
guard let alias = source["alias"], let pattern = source["pattern"] else {
return nil
}
self.alias = alias
self.pattern = pattern
}

static func patterns(from template: [String: Any]?) -> [OverridePattern] {
guard let types = template?["patterns"] as? [[String: String]] else {
return []
}
return types.compactMap { OverridePattern(source: $0) }
}
}
13 changes: 13 additions & 0 deletions Tests/ConfigTests/ConfigurationPropertyTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -294,4 +294,17 @@ class ConfigurationPropertyTests: XCTestCase {
let actualValue = try whenTheDeclarationIsWritten(for: property)
expect(actualValue).to(equal(expectedValue))
}

func testItCanUseCommonPatternsForOverrides() throws {
let dict: [String: Any] = [
"defaultValue": "test value",
"overrides": [
"barry": "pattern value"
]
]
let property = ConfigurationProperty<String>(key: "test", typeHint: "String", dict: dict, patterns: [OverridePattern(source: ["alias": "barry", "pattern": "gary"])!])
let expectedValue = ##" static let test: String = #"pattern value"#"##
let actualValue = try whenTheDeclarationIsWritten(for: property, scheme: "gary")
expect(actualValue).to(equal(expectedValue))
}
}

0 comments on commit cd4be1e

Please sign in to comment.