From 7bc9e74e43861966bf3a14388beb343b803ab353 Mon Sep 17 00:00:00 2001 From: David Jennes Date: Fri, 18 Aug 2017 00:48:12 +0200 Subject: [PATCH 1/6] modify the swiftidentifier filter to accept an enum --- Sources/Filters+Strings.swift | 78 +++++++++++++++++++++++++---------- 1 file changed, 56 insertions(+), 22 deletions(-) diff --git a/Sources/Filters+Strings.swift b/Sources/Filters+Strings.swift index a6133dbc..523b2c9f 100644 --- a/Sources/Filters+Strings.swift +++ b/Sources/Filters+Strings.swift @@ -11,6 +11,10 @@ enum RemoveNewlinesModes: String { case all, leading } +enum SwiftIdentifierModes: String { + case normal, pretty +} + extension Filters { enum Strings { fileprivate static let reservedKeywords = [ @@ -50,9 +54,29 @@ extension Filters { return source.replacingOccurrences(of: substring, with: replacement) } - static func swiftIdentifier(_ value: Any?) throws -> Any? { - guard let value = value as? String else { throw Filters.Error.invalidInputType } - return StencilSwiftKit.swiftIdentifier(from: value, replaceWithUnderscores: true) + /// Converts an arbitrary string to a valid swift identifier. Takes an optional Mode argument: + /// - normal (default): uppercase the first character, prefix with an underscore if starting + /// with a number, replace invalid characters by underscores + /// - leading: same as the above, but apply the snaceToCamelCase filter first for a nicer + /// identifier + /// + /// - Parameters: + /// - value: the value to be processed + /// - arguments: the arguments to the function; expecting zero or one mode argument + /// - Returns: the identifier string + /// - Throws: FilterError.invalidInputType if the value parameter isn't a string + static func swiftIdentifier(_ value: Any?, arguments: [Any?]) throws -> Any? { + guard var string = value as? String else { throw Filters.Error.invalidInputType } + let mode = try Filters.parseEnum(from: arguments, default: SwiftIdentifierModes.normal) + + switch mode { + case .normal: + return StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) + case .pretty: + string = string.replacingOccurrences(of: " ", with: "_") + string = try snakeToCamelCase(string, stripLeading: true) + return StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) + } } /// Lowers the first letter of the string @@ -112,25 +136,7 @@ extension Filters { let stripLeading = try Filters.parseBool(from: arguments, required: false) ?? false guard let string = value as? String else { throw Filters.Error.invalidInputType } - let unprefixed: String - if try containsAnyLowercasedChar(string) { - let comps = string.components(separatedBy: "_") - unprefixed = comps.map { titlecase($0) }.joined(separator: "") - } else { - let comps = try snakecase(string).components(separatedBy: "_") - unprefixed = comps.map { $0.capitalized }.joined(separator: "") - } - - // only if passed true, strip the prefix underscores - var prefixUnderscores = "" - if !stripLeading { - for scalar in string.unicodeScalars { - guard scalar == "_" else { break } - prefixUnderscores += "_" - } - } - - return prefixUnderscores + unprefixed + return try snakeToCamelCase(string, stripLeading: stripLeading) } /// Converts camelCase to snake_case. Takes an optional Bool argument for making the string lower case, @@ -253,6 +259,34 @@ extension Filters { return String(chars) } + /// Converts snake_case to camelCase, stripping prefix underscores if needed + /// + /// - Parameters: + /// - string: the value to be processed + /// - stripLeading: if false, will preserve leading underscores + /// - Returns: the camel case string + static func snakeToCamelCase(_ string: String, stripLeading: Bool) throws -> String { + let unprefixed: String + if try containsAnyLowercasedChar(string) { + let comps = string.components(separatedBy: "_") + unprefixed = comps.map { titlecase($0) }.joined(separator: "") + } else { + let comps = try snakecase(string).components(separatedBy: "_") + unprefixed = comps.map { $0.capitalized }.joined(separator: "") + } + + // only if passed true, strip the prefix underscores + var prefixUnderscores = "" + if !stripLeading { + for scalar in string.unicodeScalars { + guard scalar == "_" else { break } + prefixUnderscores += "_" + } + } + + return prefixUnderscores + unprefixed + } + /// This returns the string with its first parameter uppercased. /// - note: This is quite similar to `capitalise` except that this filter doesn't /// lowercase the rest of the string but keeps it untouched. From 2ccd1277823a193a830f4eb3147dfeccb364c9d2 Mon Sep 17 00:00:00 2001 From: David Jennes Date: Fri, 18 Aug 2017 01:06:58 +0200 Subject: [PATCH 2/6] add tests and docs --- Documentation/filters-strings.md | 26 ++++++--- README.md | 2 +- .../SwiftIdentifierTests.swift | 53 ++++++++++++++++++- 3 files changed, 73 insertions(+), 8 deletions(-) diff --git a/Documentation/filters-strings.md b/Documentation/filters-strings.md index 194408ff..b4a7c50e 100644 --- a/Documentation/filters-strings.md +++ b/Documentation/filters-strings.md @@ -166,7 +166,9 @@ This filter accepts a parameter (boolean, default `false`) that controls the pre ## Filter: `swiftIdentifier` -Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference). It will apply the following rules: +This filter has a couple of modes that you can specifiy using an optional argument (defaults to "normal"): + +**normal**: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference). It will apply the following rules: - Uppercase the first character. - Prefix with an underscore if the first character is a number. @@ -175,11 +177,23 @@ Transforms an arbitrary string into a valid Swift identifier (using only valid c The list of allowed characters can be found here: https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/LexicalStructure.html -| Input | Output | -|------------|------------| -| `hello` | `Hello` | -| `42hello` | `_42hello` | -| `some$URL` | `Some_URL` | +| Input | Output | +|------------------------|-------------------------| +| `hello` | `Hello` | +| `42hello` | `_42hello` | +| `some$URL` | `Some_URL` | +| `25 Ultra Light` | `_25_Ultra_Light` | +| `26_extra_ultra_light` | `_26_extra_ultra_light` | + +**pretty**: Same as normal, but it will first replace whitespaces by underscores and apply the `snakeToCamelCase` filter. + +| Input | Output | +|------------------------|----------------------| +| `hello` | `Hello` | +| `42hello` | `_42hello` | +| `some$URL` | `Some_URL` | +| `25 Ultra Light` | `_25UltraLight` | +| `26_extra_ultra_light` | `_26ExtraUltraLight` | ## Filter: `titlecase` diff --git a/README.md b/README.md index 32d78fc6..a39375b6 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ * `removeNewlines`: Removes newlines and other whitespace characters, depending on the mode ("all" or "leading"). * `replace`: Replaces instances of a substring with a new string. * `snakeToCamelCase`: Transforms text from snake_case to camelCase. By default it keeps leading underscores, unless a single optional argument is set to "true", "yes" or "1". - * `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference) + * `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference). In "pretty" mode, it will also first apply the snakeToCamelCase filter. * `upperFirstLetter`: Uppercases only the first character * [Number filters](Documentation/filters-numbers.md): * `int255toFloat` diff --git a/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift b/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift index 922fe4af..fd035d02 100644 --- a/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift +++ b/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift @@ -8,7 +8,6 @@ import XCTest @testable import StencilSwiftKit class SwiftIdentifierTests: XCTestCase { - func testBasicString() { XCTAssertEqual(swiftIdentifier(from: "Hello"), "Hello") } @@ -47,3 +46,55 @@ class SwiftIdentifierTests: XCTestCase { "HelloWorldThisContainsALotOfForbiddenCharsDoesItStillWorkAnyway") } } + +extension SwiftIdentifierTests { + func testSwiftIdentifier_WithNoArgsDefaultsToNormal() throws { + let result = try Filters.Strings.swiftIdentifier("some_test", arguments: []) as? String + XCTAssertEqual(result, "Some_test") + } + + func testSwiftIdentifier_WithWrongArgWillThrow() throws { + do { + _ = try Filters.Strings.swiftIdentifier("", arguments: ["wrong"]) + XCTFail("Code did succeed while it was expected to fail for wrong option") + } catch Filters.Error.invalidOption { + // That's the expected exception we want to happen + } catch let error { + XCTFail("Unexpected error occured: \(error)") + } + } + + func testSwiftIdentifier_WithNormal() throws { + let expectations = [ + "hello": "Hello", + "42hello": "_42hello", + "some$URL": "Some_URL", + "with space": "With_Space", + "25 Ultra Light": "_25_Ultra_Light", + "26_extra_ultra_light": "_26_extra_ultra_light", + "12 @ 34 % 56 + 78 Hello world": "_12___34___56___78_Hello_World" + ] + + for (input, expected) in expectations { + let result = try Filters.Strings.swiftIdentifier(input, arguments: ["normal"]) as? String + XCTAssertEqual(result, expected) + } + } + + func testSwiftIdentifier_WithPretty() throws { + let expectations = [ + "hello": "Hello", + "42hello": "_42hello", + "some$URL": "Some_URL", + "with space": "WithSpace", + "25 Ultra Light": "_25UltraLight", + "26_extra_ultra_light": "_26ExtraUltraLight", + "12 @ 34 % 56 + 78 Hello world": "_12_34_56_78HelloWorld" + ] + + for (input, expected) in expectations { + let result = try Filters.Strings.swiftIdentifier(input, arguments: ["pretty"]) as? String + XCTAssertEqual(result, expected) + } + } +} From 5dfe0569a19f21c2af30e3a4d16a2e2a600a878b Mon Sep 17 00:00:00 2001 From: David Jennes Date: Fri, 18 Aug 2017 01:16:05 +0200 Subject: [PATCH 3/6] changelog entry --- CHANGELOG.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9e3de202..dcfe02d2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,9 @@ _None_ * Added the `basename` and `dirname` string filters for getting a filename, or parent folder (respectively), out of a path. [David Jennes](https://github.com/djbe) [#60](https://github.com/SwiftGen/StencilSwiftKit/pull/60) +* Modify the `swiftIdentifier` string filter to accept an optional "pretty" mode, to first apply the `snakeToCamelCase` filter before converting to an identifier. + [David Jennes](https://github.com/djbe) + [#61](https://github.com/SwiftGen/StencilSwiftKit/pull/61) ### Internal Changes From f8038193a9d92acf692b8cf44f4e849a9dc6be4e Mon Sep 17 00:00:00 2001 From: David Jennes Date: Sat, 19 Aug 2017 16:50:54 +0200 Subject: [PATCH 4/6] rework pretty filter a bit as discussed --- Documentation/filters-strings.md | 9 ++++-- README.md | 2 +- Sources/Filters+Strings.swift | 4 +-- Sources/SwiftIdentifier.swift | 28 +++++++++++++------ .../SwiftIdentifierTests.swift | 16 +++++++++-- 5 files changed, 43 insertions(+), 16 deletions(-) diff --git a/Documentation/filters-strings.md b/Documentation/filters-strings.md index b4a7c50e..1f54cabe 100644 --- a/Documentation/filters-strings.md +++ b/Documentation/filters-strings.md @@ -184,16 +184,21 @@ https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift | `some$URL` | `Some_URL` | | `25 Ultra Light` | `_25_Ultra_Light` | | `26_extra_ultra_light` | `_26_extra_ultra_light` | +| `apples.count` | `Apples_Count` | +| `foo_bar.baz.qux-yay` | `Foo_bar_Baz_Qux_Yay` | -**pretty**: Same as normal, but it will first replace whitespaces by underscores and apply the `snakeToCamelCase` filter. +**pretty**: Same as normal, but afterwards it will apply the `snakeToCamelCase` filter, and other manipulations, for a prettier (but still valid) identifier. | Input | Output | |------------------------|----------------------| | `hello` | `Hello` | | `42hello` | `_42hello` | -| `some$URL` | `Some_URL` | +| `some$URL` | `SomeURL` | | `25 Ultra Light` | `_25UltraLight` | | `26_extra_ultra_light` | `_26ExtraUltraLight` | +| `apples.count` | `ApplesCount` | +| `foo_bar.baz.qux-yay` | `FooBarBazQuxYay` | + ## Filter: `titlecase` diff --git a/README.md b/README.md index a39375b6..2b187253 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,7 @@ * `removeNewlines`: Removes newlines and other whitespace characters, depending on the mode ("all" or "leading"). * `replace`: Replaces instances of a substring with a new string. * `snakeToCamelCase`: Transforms text from snake_case to camelCase. By default it keeps leading underscores, unless a single optional argument is set to "true", "yes" or "1". - * `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference). In "pretty" mode, it will also first apply the snakeToCamelCase filter. + * `swiftIdentifier`: Transforms an arbitrary string into a valid Swift identifier (using only valid characters for a Swift identifier as defined in the Swift language reference). In "pretty" mode, it will also apply the snakeToCamelCase filter afterwards, and other manipulations if needed for a "prettier" but still valid identifier. * `upperFirstLetter`: Uppercases only the first character * [Number filters](Documentation/filters-numbers.md): * `int255toFloat` diff --git a/Sources/Filters+Strings.swift b/Sources/Filters+Strings.swift index 523b2c9f..ee3f4869 100644 --- a/Sources/Filters+Strings.swift +++ b/Sources/Filters+Strings.swift @@ -73,9 +73,9 @@ extension Filters { case .normal: return StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) case .pretty: - string = string.replacingOccurrences(of: " ", with: "_") + string = StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) string = try snakeToCamelCase(string, stripLeading: true) - return StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) + return StencilSwiftKit.prefixWithUnderscoreIfNeeded(string: string) } } diff --git a/Sources/SwiftIdentifier.swift b/Sources/SwiftIdentifier.swift index 68d9e5e8..9a6ab369 100644 --- a/Sources/SwiftIdentifier.swift +++ b/Sources/SwiftIdentifier.swift @@ -32,7 +32,7 @@ private let tailRanges: [CountableClosedRange] = [ 0x30...0x39, 0x300...0x36F, 0x1dc0...0x1dff, 0x20d0...0x20ff, 0xfe20...0xfe2f ] -private func identifierCharacterSets() -> (head: NSMutableCharacterSet, tail: NSMutableCharacterSet) { +private func identifierCharacterSets(exceptions: String) -> (head: NSMutableCharacterSet, tail: NSMutableCharacterSet) { let addRange: (NSMutableCharacterSet, CountableClosedRange) -> Void = { (mcs, range) in mcs.addCharacters(in: NSRange(location: range.lowerBound, length: range.count)) } @@ -41,6 +41,7 @@ private func identifierCharacterSets() -> (head: NSMutableCharacterSet, tail: NS for range in headRanges { addRange(head, range) } + head.removeCharacters(in: exceptions) guard let tail = head.mutableCopy() as? NSMutableCharacterSet else { fatalError("Internal error: mutableCopy() should have returned a valid NSMutableCharacterSet") @@ -48,6 +49,7 @@ private func identifierCharacterSets() -> (head: NSMutableCharacterSet, tail: NS for range in tailRanges { addRange(tail, range) } + tail.removeCharacters(in: exceptions) return (head, tail) } @@ -56,14 +58,8 @@ func swiftIdentifier(from string: String, forbiddenChars exceptions: String = "", replaceWithUnderscores underscores: Bool = false) -> String { - let (head, tail) = identifierCharacterSets() - head.removeCharacters(in: exceptions) - tail.removeCharacters(in: exceptions) + let (_, tail) = identifierCharacterSets(exceptions: exceptions) - let chars = string.unicodeScalars - let firstChar = chars[chars.startIndex] - - let prefix = !head.longCharacterIsMember(firstChar.value) && tail.longCharacterIsMember(firstChar.value) ? "_" : "" let parts = string.components(separatedBy: tail.inverted) let replacement = underscores ? "_" : "" let mappedParts = parts.map({ (string: String) -> String in @@ -78,5 +74,19 @@ func swiftIdentifier(from string: String, return "" } }) - return prefix + mappedParts.joined(separator: replacement) + + let result = mappedParts.joined(separator: replacement) + return prefixWithUnderscoreIfNeeded(string: result, forbiddenChars: exceptions) +} + +func prefixWithUnderscoreIfNeeded(string: String, + forbiddenChars exceptions: String = "") -> String { + + let (head, tail) = identifierCharacterSets(exceptions: exceptions) + + let chars = string.unicodeScalars + let firstChar = chars[chars.startIndex] + let prefix = !head.longCharacterIsMember(firstChar.value) && tail.longCharacterIsMember(firstChar.value) ? "_" : "" + + return prefix + string } diff --git a/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift b/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift index fd035d02..b9ecef4e 100644 --- a/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift +++ b/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift @@ -70,6 +70,12 @@ extension SwiftIdentifierTests { "42hello": "_42hello", "some$URL": "Some_URL", "with space": "With_Space", + "apples.count": "Apples_Count", + ".SFNSDisplay": "_SFNSDisplay", + "Show-NavCtrl": "Show_NavCtrl", + "HEADER_TITLE": "HEADER_TITLE", + "multiLine\nKey": "MultiLine_Key", + "foo_bar.baz.qux-yay": "Foo_bar_Baz_Qux_Yay", "25 Ultra Light": "_25_Ultra_Light", "26_extra_ultra_light": "_26_extra_ultra_light", "12 @ 34 % 56 + 78 Hello world": "_12___34___56___78_Hello_World" @@ -85,11 +91,17 @@ extension SwiftIdentifierTests { let expectations = [ "hello": "Hello", "42hello": "_42hello", - "some$URL": "Some_URL", + "some$URL": "SomeURL", "with space": "WithSpace", + "apples.count": "ApplesCount", + ".SFNSDisplay": "SFNSDisplay", + "Show-NavCtrl": "ShowNavCtrl", + "HEADER_TITLE": "HeaderTitle", + "multiLine\nKey": "MultiLineKey", + "foo_bar.baz.qux-yay": "FooBarBazQuxYay", "25 Ultra Light": "_25UltraLight", "26_extra_ultra_light": "_26ExtraUltraLight", - "12 @ 34 % 56 + 78 Hello world": "_12_34_56_78HelloWorld" + "12 @ 34 % 56 + 78 Hello world": "_12345678HelloWorld" ] for (input, expected) in expectations { From f5d481fc90db5165c51f577f95054363264ab165 Mon Sep 17 00:00:00 2001 From: David Jennes Date: Sun, 20 Aug 2017 02:21:31 +0200 Subject: [PATCH 5/6] move swiftidentifier code into enum namespace --- Sources/Filters+Strings.swift | 6 +- Sources/SwiftIdentifier.swift | 64 ++++++++++--------- .../SwiftIdentifierTests.swift | 20 +++--- 3 files changed, 47 insertions(+), 43 deletions(-) diff --git a/Sources/Filters+Strings.swift b/Sources/Filters+Strings.swift index ee3f4869..b4671b46 100644 --- a/Sources/Filters+Strings.swift +++ b/Sources/Filters+Strings.swift @@ -71,11 +71,11 @@ extension Filters { switch mode { case .normal: - return StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) + return SwiftIdentifier.identifier(from: string, replaceWithUnderscores: true) case .pretty: - string = StencilSwiftKit.swiftIdentifier(from: string, replaceWithUnderscores: true) + string = SwiftIdentifier.identifier(from: string, replaceWithUnderscores: true) string = try snakeToCamelCase(string, stripLeading: true) - return StencilSwiftKit.prefixWithUnderscoreIfNeeded(string: string) + return SwiftIdentifier.prefixWithUnderscoreIfNeeded(string: string) } } diff --git a/Sources/SwiftIdentifier.swift b/Sources/SwiftIdentifier.swift index 9a6ab369..54ac1f27 100644 --- a/Sources/SwiftIdentifier.swift +++ b/Sources/SwiftIdentifier.swift @@ -54,39 +54,41 @@ private func identifierCharacterSets(exceptions: String) -> (head: NSMutableChar return (head, tail) } -func swiftIdentifier(from string: String, - forbiddenChars exceptions: String = "", - replaceWithUnderscores underscores: Bool = false) -> String { - - let (_, tail) = identifierCharacterSets(exceptions: exceptions) - - let parts = string.components(separatedBy: tail.inverted) - let replacement = underscores ? "_" : "" - let mappedParts = parts.map({ (string: String) -> String in - // Can't use capitalizedString here because it will lowercase all letters after the first - // e.g. "SomeNiceIdentifier".capitalizedString will because "Someniceidentifier" which is not what we want - let ns = NSString(string: string) - if ns.length > 0 { - let firstLetter = ns.substring(to: 1) - let rest = ns.substring(from: 1) - return firstLetter.uppercased() + rest - } else { - return "" - } - }) - - let result = mappedParts.joined(separator: replacement) - return prefixWithUnderscoreIfNeeded(string: result, forbiddenChars: exceptions) -} +enum SwiftIdentifier { + static func identifier(from string: String, + forbiddenChars exceptions: String = "", + replaceWithUnderscores underscores: Bool = false) -> String { + + let (_, tail) = identifierCharacterSets(exceptions: exceptions) + + let parts = string.components(separatedBy: tail.inverted) + let replacement = underscores ? "_" : "" + let mappedParts = parts.map({ (string: String) -> String in + // Can't use capitalizedString here because it will lowercase all letters after the first + // e.g. "SomeNiceIdentifier".capitalizedString will because "Someniceidentifier" which is not what we want + let ns = NSString(string: string) + if ns.length > 0 { + let firstLetter = ns.substring(to: 1) + let rest = ns.substring(from: 1) + return firstLetter.uppercased() + rest + } else { + return "" + } + }) + + let result = mappedParts.joined(separator: replacement) + return prefixWithUnderscoreIfNeeded(string: result, forbiddenChars: exceptions) + } -func prefixWithUnderscoreIfNeeded(string: String, - forbiddenChars exceptions: String = "") -> String { + static func prefixWithUnderscoreIfNeeded(string: String, + forbiddenChars exceptions: String = "") -> String { - let (head, tail) = identifierCharacterSets(exceptions: exceptions) + let (head, tail) = identifierCharacterSets(exceptions: exceptions) - let chars = string.unicodeScalars - let firstChar = chars[chars.startIndex] - let prefix = !head.longCharacterIsMember(firstChar.value) && tail.longCharacterIsMember(firstChar.value) ? "_" : "" + let chars = string.unicodeScalars + let firstChar = chars[chars.startIndex] + let prefix = !head.longCharacterIsMember(firstChar.value) && tail.longCharacterIsMember(firstChar.value) ? "_" : "" - return prefix + string + return prefix + string + } } diff --git a/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift b/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift index b9ecef4e..b979ce39 100644 --- a/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift +++ b/Tests/StencilSwiftKitTests/SwiftIdentifierTests.swift @@ -9,40 +9,42 @@ import XCTest class SwiftIdentifierTests: XCTestCase { func testBasicString() { - XCTAssertEqual(swiftIdentifier(from: "Hello"), "Hello") + XCTAssertEqual(SwiftIdentifier.identifier(from: "Hello"), "Hello") } func testBasicStringWithForbiddenChars() { - XCTAssertEqual(swiftIdentifier(from: "Hello", forbiddenChars: "l"), "HeO") + XCTAssertEqual(SwiftIdentifier.identifier(from: "Hello", forbiddenChars: "l"), "HeO") } func testBasicStringWithForbiddenCharsAndUnderscores() { - XCTAssertEqual(swiftIdentifier(from: "Hello", forbiddenChars: "l", replaceWithUnderscores: true), "He__O") + XCTAssertEqual(SwiftIdentifier.identifier(from: "Hello", + forbiddenChars: "l", + replaceWithUnderscores: true), "He__O") } func testSpecialChars() { - XCTAssertEqual(swiftIdentifier(from: "This-is-42$hello@world"), "ThisIs42HelloWorld") + XCTAssertEqual(SwiftIdentifier.identifier(from: "This-is-42$hello@world"), "ThisIs42HelloWorld") } func testKeepUppercaseAcronyms() { - XCTAssertEqual(swiftIdentifier(from: "some$URLDecoder"), "SomeURLDecoder") + XCTAssertEqual(SwiftIdentifier.identifier(from: "some$URLDecoder"), "SomeURLDecoder") } func testEmojis() { - XCTAssertEqual(swiftIdentifier(from: "some😎🎉emoji"), "Some😎🎉emoji") + XCTAssertEqual(SwiftIdentifier.identifier(from: "some😎🎉emoji"), "Some😎🎉emoji") } func testEmojis2() { - XCTAssertEqual(swiftIdentifier(from: "😎🎉"), "😎🎉") + XCTAssertEqual(SwiftIdentifier.identifier(from: "😎🎉"), "😎🎉") } func testNumbersFirst() { - XCTAssertEqual(swiftIdentifier(from: "42hello"), "_42hello") + XCTAssertEqual(SwiftIdentifier.identifier(from: "42hello"), "_42hello") } func testForbiddenChars() { XCTAssertEqual( - swiftIdentifier(from: "hello$world^this*contains%a=lot@ofchars!does#it/still:work.anyway?"), + SwiftIdentifier.identifier(from: "hello$world^this*contains%a=lot@ofchars!does#it/still:work.anyway?"), "HelloWorldThisContainsALotOfForbiddenCharsDoesItStillWorkAnyway") } } From 6fb9e7aefd7e3dedd574645aa2f825226e2e46ff Mon Sep 17 00:00:00 2001 From: David Jennes Date: Sun, 20 Aug 2017 02:22:33 +0200 Subject: [PATCH 6/6] remove unnecessary check --- Sources/SwiftIdentifier.swift | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Sources/SwiftIdentifier.swift b/Sources/SwiftIdentifier.swift index 54ac1f27..b470e9da 100644 --- a/Sources/SwiftIdentifier.swift +++ b/Sources/SwiftIdentifier.swift @@ -83,11 +83,11 @@ enum SwiftIdentifier { static func prefixWithUnderscoreIfNeeded(string: String, forbiddenChars exceptions: String = "") -> String { - let (head, tail) = identifierCharacterSets(exceptions: exceptions) + let (head, _) = identifierCharacterSets(exceptions: exceptions) let chars = string.unicodeScalars let firstChar = chars[chars.startIndex] - let prefix = !head.longCharacterIsMember(firstChar.value) && tail.longCharacterIsMember(firstChar.value) ? "_" : "" + let prefix = !head.longCharacterIsMember(firstChar.value) ? "_" : "" return prefix + string }