Skip to content

Commit

Permalink
WIP improve variable interface
Browse files Browse the repository at this point in the history
  • Loading branch information
alexdeem committed Jun 2, 2024
1 parent 234d794 commit 6f57968
Show file tree
Hide file tree
Showing 4 changed files with 61 additions and 31 deletions.
17 changes: 8 additions & 9 deletions Sources/ScreamURITemplate/Internal/Components.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import Foundation
typealias ComponentBase = Sendable

protocol Component: ComponentBase {
func expand(variables: [String: VariableValue]) throws -> String
func expand(variables: VariableProvider) throws -> String
var variableNames: [String] { get }
}

Expand All @@ -33,7 +33,7 @@ struct LiteralComponent: Component {
literal = string
}

func expand(variables _: [String: VariableValue]) throws -> String {
func expand(variables _: VariableProvider) throws -> String {
let expansion = String(literal)
guard let encodedExpansion = expansion.addingPercentEncoding(withAllowedCharacters: reservedAndUnreservedCharacterSet) else {
throw URITemplate.Error.expansionFailure(position: literal.startIndex, reason: "Percent Encoding Failed")
Expand All @@ -48,7 +48,7 @@ struct LiteralPercentEncodedTripletComponent: Component {
literal = string
}

func expand(variables _: [String: VariableValue]) throws -> String {
func expand(variables _: VariableProvider) throws -> String {
return String(literal)
}
}
Expand All @@ -65,16 +65,17 @@ struct ExpressionComponent: Component {
}

// swiftlint:disable:next cyclomatic_complexity
func expand(variables: [String: VariableValue]) throws -> String {
func expand(variables: VariableProvider) throws -> String {
let configuration = expressionOperator.expansionConfiguration()
let expansions = try variableList.compactMap { variableSpec -> String? in
guard let value = variables[String(variableSpec.name)] else {
return nil
}
do {
if let stringValue = value as? String {
switch value {
case let .string(stringValue):
return try stringValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration)
} else if let arrayValue = value as? [String] {
case let .array(arrayValue):
switch variableSpec.modifier {
case .prefix:
throw FormatError.failure(reason: "Prefix operator can only be applied to string")
Expand All @@ -83,7 +84,7 @@ struct ExpressionComponent: Component {
case .none:
return try arrayValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration)
}
} else if let dictionaryValue = value as? [String: String] {
case let .dictionary(dictionaryValue):
switch variableSpec.modifier {
case .prefix:
throw FormatError.failure(reason: "Prefix operator can only be applied to string")
Expand All @@ -92,8 +93,6 @@ struct ExpressionComponent: Component {
case .none:
return try dictionaryValue.formatForTemplateExpansion(variableSpec: variableSpec, expansionConfiguration: configuration)
}
} else {
throw FormatError.failure(reason: "Invalid Value Type")
}
} catch let FormatError.failure(reason) {
throw URITemplate.Error.expansionFailure(position: templatePosition, reason: "Failed expanding variable \"\(variableSpec.name)\": \(reason)")
Expand Down
46 changes: 41 additions & 5 deletions Sources/ScreamURITemplate/URITemplate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,42 @@

import Foundation

public protocol VariableValue {}
extension String: VariableValue {}
extension Array: VariableValue where Element: StringProtocol {}
extension Dictionary: VariableValue where Key: StringProtocol, Value: StringProtocol {}
/*
Public interface for variables
*/
public enum VariableValue {
case string(String)
case array([String])
case dictionary([String: String])
}

public protocol VariableProvider {
subscript(_: String) -> VariableValue? { get }
}

extension [String: VariableValue]: VariableProvider {}

public protocol VariableValueConvertible {
var asURITemplateVariableValue: VariableValue? { get }
}

extension String: VariableValueConvertible {
public var asURITemplateVariableValue: VariableValue? {
return .string(self)
}
}

extension [String]: VariableValueConvertible {
public var asURITemplateVariableValue: VariableValue? {
return .array(self)
}
}

extension [String: String]: VariableValueConvertible {
public var asURITemplateVariableValue: VariableValue? {
return .dictionary(self)
}
}

public struct URITemplate {
public enum Error: Swift.Error {
Expand All @@ -38,14 +70,18 @@ public struct URITemplate {
self.components = components
}

public func process(variables: [String: VariableValue]) throws -> String {
public func process(variables: VariableProvider) throws -> String {
var result = ""
for component in components {
result += try component.expand(variables: variables)
}
return result
}

public func process(variables: [String: VariableValueConvertible]) throws -> String {
return try process(variables: variables.compactMapValues { $0.asURITemplateVariableValue })
}

public var variableNames: [String] {
return components.flatMap { component in
return component.variableNames
Expand Down
2 changes: 1 addition & 1 deletion Tests/ScreamURITemplateTests/TestFileTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ import XCTest

class TestFileTests: XCTestCase {
private var templateString: String!
private var variables: [String: VariableValue]!
private var variables: [String: VariableValueConvertible]!
private var acceptableExpansions: [String]!
private var failPosition: Int?
private var failReason: String?
Expand Down
27 changes: 11 additions & 16 deletions Tests/ScreamURITemplateTests/TestModels.swift
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ private struct TestGroupDecodable: Decodable {
public struct TestGroup {
public let name: String
public let level: Int?
public let variables: [String: VariableValue]
public let variables: [String: VariableValueConvertible]
public let testcases: [TestCase]
}

Expand All @@ -38,34 +38,34 @@ public struct TestCase {
public let failReason: String?
}

extension JSONValue {
func toVariableValue() -> VariableValue? {
extension JSONValue: VariableValueConvertible {
public var asURITemplateVariableValue: ScreamURITemplate.VariableValue? {
switch self {
case let .int(int):
return String(int)
return .string(String(int))
case let .double(double):
return String(double)
return .string(String(double))
case let .string(string):
return string
return .string(string)
case let .object(object):
return object.mapValues { element -> String? in
return .dictionary(object.mapValues { element -> String? in
switch element {
case let .string(string):
return string
default:
return nil
}
}.filter { $0.value != nil }
.mapValues { $0! }
.mapValues { $0! })
case let .array(array):
return array.compactMap { element -> String? in
return .array(array.compactMap { element -> String? in
switch element {
case let .string(string):
return string
default:
return nil
}
}
})
default:
return nil
}
Expand Down Expand Up @@ -143,15 +143,10 @@ public func parseTestFile(URL: URL) -> [TestGroup]? {
}

return testCollection.map { testGroupName, testGroupData in
let variables = testGroupData.variables.mapValues { element in
return element.toVariableValue()
}.filter { return $0.value != nil }
.mapValues { return $0! }

let testcases = testGroupData.testcases.compactMap { element in
return TestCase(element)
}

return TestGroup(name: testGroupName, level: testGroupData.level, variables: variables, testcases: testcases)
return TestGroup(name: testGroupName, level: testGroupData.level, variables: testGroupData.variables, testcases: testcases)
}
}

0 comments on commit 6f57968

Please sign in to comment.