-
Notifications
You must be signed in to change notification settings - Fork 56
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Parser for list of parameters #8
Changes from 13 commits
f70eff4
c4117bb
7a93338
550282b
db74700
6186196
406180f
c40ed43
5159be2
dd774e2
77a8b27
91f4cc0
476a384
717d7a3
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
// | ||
// Context.swift | ||
// Pods | ||
// | ||
// Created by David Jennes on 14/02/2017. | ||
// | ||
// | ||
|
||
import Foundation | ||
|
||
public func enrich(context: [AnyHashable: Any], parameters: [String]) throws -> [AnyHashable: Any] { | ||
var context = context | ||
|
||
context["env"] = ProcessInfo().environment | ||
context["param"] = try Parameters.parse(items: parameters) | ||
|
||
return context | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
// | ||
// StencilSwiftKit | ||
// Copyright (c) 2017 SwiftGen | ||
// MIT Licence | ||
// | ||
|
||
import Foundation | ||
|
||
public enum ParametersError: Error { | ||
case invalidSyntax(value: Any) | ||
case invalidKey(key: String, value: Any) | ||
case invalidStructure(key: String, oldValue: Any, newValue: Any) | ||
} | ||
|
||
public enum Parameters { | ||
typealias Parameter = (key: String, value: Any) | ||
public typealias StringDict = [String: Any] | ||
|
||
public static func parse(items: [String]) throws -> StringDict { | ||
let parameters: [Parameter] = try items.map { item in | ||
let parts = item.components(separatedBy: "=") | ||
if parts.count >= 2 { | ||
return (key: parts[0], value: parts.dropFirst().joined(separator: "=")) | ||
} else if let part = parts.first, parts.count == 1 && validate(key: part) { | ||
return (key: part, value: true) | ||
} else { | ||
throw ParametersError.invalidSyntax(value: item) | ||
} | ||
} | ||
|
||
return try parameters.reduce(StringDict()) { | ||
try parse(parameter: $1, result: $0) | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. That french autocorrect 😆 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 😂 |
||
} | ||
|
||
private static func parse(parameter: Parameter, result: StringDict) throws -> StringDict { | ||
let parts = parameter.key.components(separatedBy: ".") | ||
let key = parts.first ?? "" | ||
var result = result | ||
|
||
// validate key | ||
guard validate(key: key) else { throw ParametersError.invalidKey(key: parameter.key, value: parameter.value) } | ||
|
||
// no sub keys, may need to convert to array if repeat key if possible | ||
if parts.count == 1 { | ||
if let current = result[key] as? [Any] { | ||
result[key] = current + [parameter.value] | ||
} else if let current = result[key] as? String { | ||
result[key] = [current, parameter.value] | ||
} else if let current = result[key] { | ||
throw ParametersError.invalidStructure(key: key, oldValue: current, newValue: parameter.value) | ||
} else { | ||
result[key] = parameter.value | ||
} | ||
} else if parts.count > 1 { | ||
guard result[key] is StringDict || result[key] == nil else { | ||
throw ParametersError.invalidStructure(key: key, oldValue: result[key] ?? "", newValue: parameter.value) | ||
} | ||
|
||
// recurse into sub keys | ||
let current = result[key] as? StringDict ?? StringDict() | ||
let sub = (key: parts.suffix(from: 1).joined(separator: "."), value: parameter.value) | ||
result[key] = try parse(parameter: sub, result: current) | ||
} | ||
|
||
return result | ||
} | ||
|
||
// a valid key is not empty and only alphanumerical or dot | ||
private static func validate(key: String) -> Bool { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Does this means There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right now, yeah. Shouldn't matter that much, say I want to create a (fake) tuple. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ok. Fine by be |
||
return !key.isEmpty && | ||
key.rangeOfCharacter(from: notAlfanumericsAndDot) == nil | ||
} | ||
|
||
private static let notAlfanumericsAndDot: CharacterSet = { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. s/alfa/alpha 😄 |
||
var result = CharacterSet.alphanumerics | ||
result.insert(".") | ||
return result.inverted | ||
}() | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
// | ||
// ContextTests.swift | ||
// StencilSwiftKit | ||
// | ||
// Created by David Jennes on 14/02/2017. | ||
// Copyright © 2017 AliSoftware. All rights reserved. | ||
// | ||
|
||
import XCTest | ||
import StencilSwiftKit | ||
|
||
class ContextTests: XCTestCase { | ||
func testEmpty() { | ||
let context = [String: Any]() | ||
|
||
let result = try! enrich(context: context, parameters: []) | ||
XCTAssertEqual(result.count, 2, "2 items have been added") | ||
|
||
guard let env = result["env"] as? [AnyHashable: Any] else { XCTFail("`env` should be a dictionary"); return } | ||
XCTAssertNotNil(env["PATH"] as? String) | ||
guard let params = result["param"] as? [AnyHashable: Any] else { XCTFail("`param` should be a dictionary"); return } | ||
XCTAssertEqual(params.count, 0) | ||
} | ||
|
||
func testWithContext() { | ||
let context: [String : Any] = ["foo": "bar", "hello": true] | ||
|
||
let result = try! enrich(context: context, parameters: []) | ||
XCTAssertEqual(result.count, 4, "4 items have been added") | ||
XCTAssertEqual(result["foo"] as? String, "bar") | ||
XCTAssertEqual(result["hello"] as? Bool, true) | ||
|
||
guard let env = result["env"] as? [AnyHashable: Any] else { XCTFail("`env` should be a dictionary"); return } | ||
XCTAssertNotNil(env["PATH"] as? String) | ||
guard let params = result["param"] as? [AnyHashable: Any] else { XCTFail("`param` should be a dictionary"); return } | ||
XCTAssertEqual(params.count, 0) | ||
} | ||
|
||
func testWithParameters() { | ||
let context = [String: Any]() | ||
|
||
let result = try! enrich(context: context, parameters: ["foo=bar", "hello"]) | ||
XCTAssertEqual(result.count, 2, "2 items have been added") | ||
|
||
guard let env = result["env"] as? [AnyHashable: Any] else { XCTFail("`env` should be a dictionary"); return } | ||
XCTAssertNotNil(env["PATH"] as? String) | ||
guard let params = result["param"] as? [AnyHashable: Any] else { XCTFail("`param` should be a dictionary"); return } | ||
XCTAssertEqual(params["foo"] as? String, "bar") | ||
XCTAssertEqual(params["hello"] as? Bool, true) | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does that mean that
foo.bar.baz
isn't a valid boolean key? (asvalidate(key: "foo.bar.baz")
will return false)?